OSDN Git Service

BUG 1922588: SDK Updater, Needs better license display
[android-x86/sdk.git] / sdkmanager / libs / sdkuilib / src / com / android / sdkuilib / internal / repository / UpdateChooserDialog.java
1 /*\r
2  * Copyright (C) 2009 The Android Open Source Project\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 package com.android.sdkuilib.internal.repository;\r
18 \r
19 import com.android.sdklib.SdkConstants;\r
20 import com.android.sdklib.internal.repository.Archive;\r
21 import com.android.sdkuilib.internal.repository.icons.ImageFactory;\r
22 \r
23 import org.eclipse.jface.viewers.ISelection;\r
24 import org.eclipse.jface.viewers.IStructuredContentProvider;\r
25 import org.eclipse.jface.viewers.IStructuredSelection;\r
26 import org.eclipse.jface.viewers.LabelProvider;\r
27 import org.eclipse.jface.viewers.TableViewer;\r
28 import org.eclipse.jface.viewers.Viewer;\r
29 import org.eclipse.swt.SWT;\r
30 import org.eclipse.swt.custom.SashForm;\r
31 import org.eclipse.swt.custom.StyleRange;\r
32 import org.eclipse.swt.custom.StyledText;\r
33 import org.eclipse.swt.events.ControlAdapter;\r
34 import org.eclipse.swt.events.ControlEvent;\r
35 import org.eclipse.swt.events.SelectionAdapter;\r
36 import org.eclipse.swt.events.SelectionEvent;\r
37 import org.eclipse.swt.events.ShellAdapter;\r
38 import org.eclipse.swt.events.ShellEvent;\r
39 import org.eclipse.swt.graphics.Image;\r
40 import org.eclipse.swt.graphics.Point;\r
41 import org.eclipse.swt.graphics.Rectangle;\r
42 import org.eclipse.swt.layout.GridData;\r
43 import org.eclipse.swt.layout.GridLayout;\r
44 import org.eclipse.swt.widgets.Button;\r
45 import org.eclipse.swt.widgets.Composite;\r
46 import org.eclipse.swt.widgets.Dialog;\r
47 import org.eclipse.swt.widgets.Display;\r
48 import org.eclipse.swt.widgets.Group;\r
49 import org.eclipse.swt.widgets.Label;\r
50 import org.eclipse.swt.widgets.Shell;\r
51 import org.eclipse.swt.widgets.Table;\r
52 import org.eclipse.swt.widgets.TableColumn;\r
53 \r
54 import java.util.ArrayList;\r
55 import java.util.Collection;\r
56 import java.util.Comparator;\r
57 import java.util.HashSet;\r
58 import java.util.Map;\r
59 import java.util.TreeMap;\r
60 \r
61 \r
62 /**\r
63  * Implements an {@link UpdateChooserDialog}.\r
64  */\r
65 final class UpdateChooserDialog extends Dialog {\r
66 \r
67     /**\r
68      * Min Y location for dialog. Need to deal with the menu bar on mac os.\r
69      */\r
70     private final static int MIN_Y = SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_DARWIN ?\r
71             20 : 0;\r
72 \r
73     /** Last dialog size for this session. */\r
74     private static Point sLastSize;\r
75     private boolean mCompleted;\r
76     private final Map<Archive, Archive> mNewToOldArchiveMap;\r
77     private boolean mLicenseAcceptAll;\r
78     private boolean mInternalLicenseRadioUpdate;\r
79     private HashSet<Archive> mAccepted = new HashSet<Archive>();\r
80     private HashSet<Archive> mRejected = new HashSet<Archive>();\r
81     private ArrayList<Archive> mResult = new ArrayList<Archive>();\r
82 \r
83     // UI fields\r
84     private Shell mDialogShell;\r
85     private SashForm mSashForm;\r
86     private Composite mPackageRootComposite;\r
87     private Button mCancelButton;\r
88     private Button mInstallButton;\r
89     private TableViewer mTableViewPackage;\r
90     private Table mTablePackage;\r
91     private TableColumn mTableColum;\r
92     private StyledText mPackageText;\r
93     private Button mLicenseRadioAccept;\r
94     private Button mLicenseRadioReject;\r
95     private Button mLicenseRadioAcceptAll;\r
96     private Group mPackageTextGroup;\r
97     private final UpdaterData mUpdaterData;\r
98     private Group mTableGroup;\r
99 \r
100 \r
101     /**\r
102      * Create the dialog.\r
103      * @param parentShell The shell to use, typically updaterData.getWindowShell()\r
104      * @param updaterData The updater data\r
105      * @param newToOldUpdates The map [new archive => old archive] of potential updates\r
106      */\r
107     public UpdateChooserDialog(Shell parentShell,\r
108             UpdaterData updaterData,\r
109             Map<Archive, Archive> newToOldUpdates) {\r
110         super(parentShell,\r
111               SWT.APPLICATION_MODAL);\r
112         mUpdaterData = updaterData;\r
113 \r
114         mNewToOldArchiveMap = new TreeMap<Archive, Archive>(new Comparator<Archive>() {\r
115             public int compare(Archive a1, Archive a2) {\r
116                 // The items are archive but what we show are packages so we'll\r
117                 // sort of packages short descriptions\r
118                 String desc1 = a1.getParentPackage().getShortDescription();\r
119                 String desc2 = a2.getParentPackage().getShortDescription();\r
120                 return desc1.compareTo(desc2);\r
121             }\r
122         });\r
123         mNewToOldArchiveMap.putAll(newToOldUpdates);\r
124     }\r
125 \r
126     /**\r
127      * Returns the results, i.e. the list of selected new archives to install.\r
128      * The list is always non null. It is empty when cancel is selected or when\r
129      * all potential updates have been refused.\r
130      */\r
131     public Collection<Archive> getResult() {\r
132         return mResult;\r
133     }\r
134 \r
135     /**\r
136      * Open the dialog and blocks till it gets closed\r
137      */\r
138     public void open() {\r
139         createContents();\r
140         positionShell();            //$hide$ (hide from SWT designer)\r
141         mDialogShell.open();\r
142         mDialogShell.layout();\r
143 \r
144         postCreate();               //$hide$ (hide from SWT designer)\r
145 \r
146         Display display = getParent().getDisplay();\r
147         while (!mDialogShell.isDisposed() && !mCompleted) {\r
148             if (!display.readAndDispatch()) {\r
149                 display.sleep();\r
150             }\r
151         }\r
152 \r
153         if (!mDialogShell.isDisposed()) {\r
154             mDialogShell.close();\r
155         }\r
156     }\r
157 \r
158     /**\r
159      * Create contents of the dialog.\r
160      */\r
161     private void createContents() {\r
162         mDialogShell = new Shell(getParent(), SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MIN | SWT.MAX);\r
163         mDialogShell.addShellListener(new ShellAdapter() {\r
164             @Override\r
165             public void shellClosed(ShellEvent e) {\r
166                 onShellClosed(e);\r
167             }\r
168         });\r
169         mDialogShell.setLayout(new GridLayout(3, false/*makeColumnsEqual*/));\r
170         mDialogShell.setSize(600, 400);\r
171         mDialogShell.setText("Choose Packages to Install");\r
172 \r
173         // Sash form\r
174         mSashForm = new SashForm(mDialogShell, SWT.NONE);\r
175         mSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));\r
176 \r
177 \r
178         // Left part of Sash Form\r
179 \r
180         mTableGroup = new Group(mSashForm, SWT.NONE);\r
181         mTableGroup.setText("Packages");\r
182         mTableGroup.setLayout(new GridLayout(1, false/*makeColumnsEqual*/));\r
183 \r
184         mTableViewPackage = new TableViewer(mTableGroup, SWT.BORDER | SWT.V_SCROLL | SWT.SINGLE);\r
185         mTablePackage = mTableViewPackage.getTable();\r
186         mTablePackage.setHeaderVisible(false);\r
187         mTablePackage.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));\r
188 \r
189         mTablePackage.addSelectionListener(new SelectionAdapter() {\r
190             @Override\r
191             public void widgetSelected(SelectionEvent e) {\r
192                 onPackageSelected();  //$hide$\r
193             }\r
194             @Override\r
195             public void widgetDefaultSelected(SelectionEvent e) {\r
196                 onPackageDoubleClick();\r
197             }\r
198         });\r
199 \r
200         mTableColum = new TableColumn(mTablePackage, SWT.NONE);\r
201         mTableColum.setWidth(100);\r
202         mTableColum.setText("Packages");\r
203 \r
204 \r
205         // Right part of Sash form\r
206         mPackageRootComposite = new Composite(mSashForm, SWT.NONE);\r
207         mPackageRootComposite.setLayout(new GridLayout(4, false/*makeColumnsEqual*/));\r
208         mPackageRootComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));\r
209 \r
210         mPackageTextGroup = new Group(mPackageRootComposite, SWT.NONE);\r
211         mPackageTextGroup.setText("Package Description && License");\r
212         mPackageTextGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));\r
213         mPackageTextGroup.setLayout(new GridLayout(1, false/*makeColumnsEqual*/));\r
214 \r
215         mPackageText = new StyledText(mPackageTextGroup,\r                        SWT.MULTI | SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL);\r
216         mPackageText.setBackground(\r
217                 getParent().getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));\r
218         mPackageText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));\r
219 \r
220         mLicenseRadioAccept = new Button(mPackageRootComposite, SWT.RADIO);\r
221         mLicenseRadioAccept.setText("Accept");\r
222         mLicenseRadioAccept.addSelectionListener(new SelectionAdapter() {\r
223             @Override\r
224             public void widgetSelected(SelectionEvent e) {\r
225                 onLicenseRadioSelected();\r
226             }\r
227         });\r
228 \r
229         mLicenseRadioReject = new Button(mPackageRootComposite, SWT.RADIO);\r
230         mLicenseRadioReject.setText("Reject");\r
231         mLicenseRadioReject.addSelectionListener(new SelectionAdapter() {\r
232             @Override\r
233             public void widgetSelected(SelectionEvent e) {\r
234                 onLicenseRadioSelected();\r
235             }\r
236         });\r
237 \r
238         Label placeholder = new Label(mPackageRootComposite, SWT.NONE);\r
239         placeholder.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));\r
240 \r
241         mLicenseRadioAcceptAll = new Button(mPackageRootComposite, SWT.RADIO);\r
242         mLicenseRadioAcceptAll.setText("Accept All");\r
243         mLicenseRadioAcceptAll.addSelectionListener(new SelectionAdapter() {\r
244             @Override\r
245             public void widgetSelected(SelectionEvent e) {\r
246                 onLicenseRadioSelected();\r
247             }\r
248         });\r
249 \r
250         mSashForm.setWeights(new int[] {200, 300});\r
251 \r
252         // Bottom buttons\r
253         placeholder = new Label(mDialogShell, SWT.NONE);\r
254         placeholder.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1));\r
255 \r
256         // for MacOS, the Cancel button should be left.\r
257         if (SdkConstants.currentPlatform() == SdkConstants.PLATFORM_DARWIN) {\r
258             mCancelButton = new Button(mDialogShell, SWT.PUSH);\r
259         }\r
260 \r
261         mInstallButton = new Button(mDialogShell, SWT.PUSH);\r
262         mInstallButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));\r
263         mInstallButton.setText("Install Accepted");\r
264         mInstallButton.addSelectionListener(new SelectionAdapter() {\r
265             @Override\r
266             public void widgetSelected(SelectionEvent e) {\r
267                 onInstallSelected();\r
268             }\r
269         });\r
270 \r
271         // if we haven't created the cancel button yet (macos?), create it now.\r
272         if (mCancelButton == null) {\r
273             mCancelButton = new Button(mDialogShell, SWT.PUSH);\r
274         }\r
275         mCancelButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));\r
276         mCancelButton.setText("Cancel");\r
277         mCancelButton.addSelectionListener(new SelectionAdapter() {\r
278             @Override\r
279             public void widgetSelected(SelectionEvent e) {\r
280                 onCancelSelected();\r
281             }\r
282         });\r
283     }\r
284 \r
285     // -- End of UI, Start of internal logic ----------\r
286     // Hide everything down-below from SWT designer\r
287     //$hide>>$\r
288 \r
289     /**\r
290      * Starts the thread that runs the task.\r
291      * This is deferred till the UI is created.\r
292      */\r
293     private void postCreate() {\r
294         setWindowImage();\r
295 \r
296         // Automatically accept those with an empty license\r
297         for (Archive a : mNewToOldArchiveMap.keySet()) {\r
298 \r
299             String license = a.getParentPackage().getLicense();\r
300             if (license != null) {\r
301                 license = license.trim();\r
302                 if (license.length() == 0) {\r
303                     mAccepted.add(a);\r
304                 }\r
305             } else {\r
306                 mAccepted.add(a);\r
307             }\r
308         }\r
309 \r
310         // Fill the list with the replacement packages\r
311         mTableViewPackage.setLabelProvider(new NewArchivesLabelProvider());\r
312         mTableViewPackage.setContentProvider(new NewArchivesContentProvider());\r
313         mTableViewPackage.setInput(mNewToOldArchiveMap);\r
314 \r
315         adjustColumnsWidth();\r
316 \r
317         // select first item\r
318         mTablePackage.select(0);\r
319         onPackageSelected();\r
320     }\r
321 \r
322     /**\r
323      * Creates the icon of the window shell.\r
324      */\r
325     private void setWindowImage() {\r
326         String imageName = "android_icon_16.png"; //$NON-NLS-1$\r
327         if (SdkConstants.currentPlatform() == SdkConstants.PLATFORM_DARWIN) {\r
328             imageName = "android_icon_128.png"; //$NON-NLS-1$\r
329         }\r
330 \r
331         if (mUpdaterData != null) {\r
332             ImageFactory imgFactory = mUpdaterData.getImageFactory();\r
333             if (imgFactory != null) {\r
334                 mDialogShell.setImage(imgFactory.getImageByName(imageName));\r
335             }\r
336         }\r
337     }\r
338 \r
339     /**\r
340      * Adds a listener to adjust the columns width when the parent is resized.\r
341      * <p/>\r
342      * If we need something more fancy, we might want to use this:\r
343      * http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet77.java?view=co\r
344      */\r
345     private void adjustColumnsWidth() {\r
346         // Add a listener to resize the column to the full width of the table\r
347         ControlAdapter resizer = new ControlAdapter() {\r
348             @Override\r
349             public void controlResized(ControlEvent e) {\r
350                 Rectangle r = mTablePackage.getClientArea();\r
351                 mTableColum.setWidth(r.width);\r
352             }\r
353         };\r
354         mTablePackage.addControlListener(resizer);\r
355         resizer.controlResized(null);\r
356     }\r
357 \r
358     /**\r
359      * Callback invoked when the shell is closed either by clicking the close button\r
360      * on by calling shell.close().\r
361      * Captures the window size before closing this.\r
362      */\r
363     private void onShellClosed(ShellEvent e) {\r
364         sLastSize = mDialogShell.getSize();\r
365     }\r
366 \r
367     /**\r
368      * Centers the dialog in its parent shell.\r
369      */\r
370     private void positionShell() {\r
371         // Centers the dialog in its parent shell\r
372         Shell child = mDialogShell;\r
373         Shell parent = getParent();\r
374         if (child != null && parent != null) {\r
375 \r
376             // get the parent client area with a location relative to the display\r
377             Rectangle parentArea = parent.getClientArea();\r
378             Point parentLoc = parent.getLocation();\r
379             int px = parentLoc.x;\r
380             int py = parentLoc.y;\r
381             int pw = parentArea.width;\r
382             int ph = parentArea.height;\r
383 \r
384             // Reuse the last size if there's one, otherwise use the default\r
385             Point childSize = sLastSize != null ? sLastSize : child.getSize();\r
386             int cw = childSize.x;\r
387             int ch = childSize.y;\r
388 \r
389             int x = px + (pw - cw) / 2;\r
390             int y = py + (ph - ch) / 2;\r
391 \r
392             if (x < 0) {\r
393                 x = 0;\r
394             }\r
395 \r
396             if (y < MIN_Y) {\r
397                 y = MIN_Y;\r
398             }\r
399 \r
400             child.setLocation(x, y);\r
401             child.setSize(cw, ch);\r
402         }\r
403     }\r
404 \r
405     /**\r
406      * Callback invoked when the Install button is selected. Fills {@link #mResult} and\r
407      * completes the dialog.\r
408      */\r
409     private void onInstallSelected() {\r
410         // get list of accepted items\r
411         mResult.addAll(mAccepted);\r
412         mCompleted = true;\r
413     }\r
414 \r
415     /**\r
416      * Callback invoked when the Cancel button is selected.\r
417      */\r
418     private void onCancelSelected() {\r
419         mCompleted = true;\r
420     }\r
421 \r
422     /**\r
423      * Callback invoked when a package item is selected in the list.\r
424      */\r
425     private void onPackageSelected() {\r
426         Archive a = getSelectedArchive();\r
427         displayInformation(a);\r
428         updateLicenceRadios(a);\r
429     }\r
430 \r
431     /** Returns the currently selected Archive or null. */\r
432     private Archive getSelectedArchive() {\r
433         ISelection sel = mTableViewPackage.getSelection();\r
434         if (sel instanceof IStructuredSelection) {\r
435             Object elem = ((IStructuredSelection) sel).getFirstElement();\r
436             if (elem instanceof Archive) {\r
437                 return (Archive) elem;\r
438             }\r
439         }\r
440         return null;\r
441     }\r
442 \r
443     private void displayInformation(Archive a) {\r
444         if (a == null) {\r
445             mPackageText.setText("Please select a package.");\r
446             return;\r
447         }\r
448 \r
449         mPackageText.setText("");                                               //$NON-NLS-1$\r
450 \r
451         addSectionTitle("Package Description\n");\r
452         addText(a.getParentPackage().getLongDescription(), "\n\n");             //$NON-NLS-1$\r
453 \r
454         Archive aold = mNewToOldArchiveMap.get(a);\r
455         if (aold != null) {\r
456             addText(String.format("This update will replace revision %1$s with revision %2$s.\n\n",\r
457                     aold.getParentPackage().getRevision(),\r
458                     a.getParentPackage().getRevision()));\r
459         }\r
460 \r
461 \r
462         addSectionTitle("Archive Description\n");\r
463         addText(a.getLongDescription(), "\n\n");                                //$NON-NLS-1$\r
464 \r
465         String license = a.getParentPackage().getLicense();\r
466         if (license != null) {\r
467             addSectionTitle("License\n");\r
468             addText(license.trim(), "\n");                                      //$NON-NLS-1$\r
469         }\r
470     }\r
471 \r
472     private void addText(String...string) {\r
473         for (String s : string) {\r
474             mPackageText.append(s);\r
475         }\r
476     }\r
477 \r
478     private void addSectionTitle(String string) {\r
479         String s = mPackageText.getText();\r
480         int start = (s == null ? 0 : s.length());\r
481         mPackageText.append(string);\r
482 \r
483         StyleRange sr = new StyleRange();\r
484         sr.start = start;\r
485         sr.length = string.length();\r
486         sr.fontStyle = SWT.BOLD;\r
487         sr.underline = true;\r
488         mPackageText.setStyleRange(sr);\r
489     }\r
490 \r
491     private void updateLicenceRadios(Archive a) {\r
492         if (mInternalLicenseRadioUpdate) {\r
493             return;\r
494         }\r
495         mInternalLicenseRadioUpdate = true;\r
496 \r
497         if (mLicenseAcceptAll) {\r
498             mLicenseRadioAcceptAll.setSelection(true);\r
499             mLicenseRadioAccept.setSelection(false);\r
500             mLicenseRadioReject.setSelection(false);\r
501         } else {\r
502             mLicenseRadioAcceptAll.setSelection(false);\r
503             mLicenseRadioAccept.setSelection(mAccepted.contains(a));\r
504             mLicenseRadioReject.setSelection(mRejected.contains(a));\r
505         }\r
506 \r
507         // The install button is enabled if there's at least one\r
508         // package accepted.\r
509         mInstallButton.setEnabled(mAccepted.size() > 0);\r
510 \r
511         mInternalLicenseRadioUpdate = false;\r
512     }\r
513 \r
514     /**\r
515      * Callback invoked when one of the radio license buttons is selected.\r
516      *\r
517      * - accept/refuse: toggle, update item checkbox\r
518      * - accept all: set accept-all, check all items\r
519      */\r
520     private void onLicenseRadioSelected() {\r
521         if (mInternalLicenseRadioUpdate) {\r
522             return;\r
523         }\r
524         mInternalLicenseRadioUpdate = true;\r
525 \r
526         Archive a = getSelectedArchive();\r
527         boolean needUpdate = true;\r
528 \r
529         if (!mLicenseAcceptAll && mLicenseRadioAcceptAll.getSelection()) {\r
530             // Accept all has been switched on. Mark all packages as accepted\r
531             mLicenseAcceptAll = true;\r
532             mAccepted.addAll(mNewToOldArchiveMap.keySet());\r
533             mRejected.clear();\r
534 \r
535         } else if (mLicenseRadioAccept.getSelection()) {\r
536             // Accept only this one\r
537             mLicenseAcceptAll = false;\r
538             mAccepted.add(a);\r
539             mRejected.remove(a);\r
540 \r
541         } else if (mLicenseRadioReject.getSelection()) {\r
542             // Reject only this one\r
543             mLicenseAcceptAll = false;\r
544             mAccepted.remove(a);\r
545             mRejected.add(a);\r
546 \r
547         } else {\r
548             needUpdate = false;\r
549         }\r
550 \r
551         mInternalLicenseRadioUpdate = false;\r
552 \r
553         if (needUpdate) {\r
554             if (mLicenseAcceptAll) {\r
555                 mTableViewPackage.refresh();\r
556             } else {\r
557                mTableViewPackage.refresh(a);\r
558             }\r
559             updateLicenceRadios(a);\r
560         }\r
561     }\r
562 \r
563     /**\r
564      * Callback invoked when a package item is double-clicked in the list.\r
565      */\r
566     private void onPackageDoubleClick() {\r
567         Archive a = getSelectedArchive();\r
568 \r
569         if (mAccepted.contains(a)) {\r
570             // toggle from accepted to rejected\r
571             mAccepted.remove(a);\r
572             mRejected.add(a);\r
573         } else {\r
574             // toggle from rejected or unknown to accepted\r
575             mAccepted.add(a);\r
576             mRejected.remove(a);\r
577         }\r
578 \r
579         // update state\r
580         mLicenseAcceptAll = false;\r
581         mTableViewPackage.refresh(a);\r
582         updateLicenceRadios(a);\r
583     }\r
584 \r
585     private class NewArchivesLabelProvider extends LabelProvider {\r
586         @Override\r
587         public Image getImage(Object element) {\r
588             ImageFactory imgFactory = mUpdaterData.getImageFactory();\r
589             if (imgFactory != null) {\r
590                 if (mAccepted.contains(element)) {\r
591                     return imgFactory.getImageByName("accept_icon16.png");\r
592                 } else if (mRejected.contains(element)) {\r
593                     return imgFactory.getImageByName("reject_icon16.png");\r
594                 }\r
595                 return imgFactory.getImageByName("unknown_icon16.png");\r
596             }\r
597             return super.getImage(element);\r
598         }\r
599 \r
600         @Override\r
601         public String getText(Object element) {\r
602             if (element instanceof Archive) {\r
603                 return ((Archive) element).getParentPackage().getShortDescription();\r
604             }\r
605             return super.getText(element);\r
606         }\r
607     }\r
608 \r
609     private class NewArchivesContentProvider implements IStructuredContentProvider {\r
610 \r
611         public void dispose() {\r
612             // pass\r
613         }\r
614 \r
615         public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
616             // Ignore. The input is always mNewArchives\r
617         }\r
618 \r
619         public Object[] getElements(Object inputElement) {\r
620             return mNewToOldArchiveMap.keySet().toArray();\r
621         }\r
622     }\r
623 \r
624     // End of hiding from SWT Designer\r
625     //$hide<<$\r
626 }\r