]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-after/internal compatibility/org/eclipse/jdt/internal/ui/dialogs/TypeInfoViewer.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-after / internal compatibility / org / eclipse / jdt / internal / ui / dialogs / TypeInfoViewer.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2011 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.ui.dialogs;
12
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Comparator;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22
23 import org.eclipse.swt.SWT;
24 import org.eclipse.swt.accessibility.AccessibleAdapter;
25 import org.eclipse.swt.accessibility.AccessibleEvent;
26 import org.eclipse.swt.events.ControlAdapter;
27 import org.eclipse.swt.events.ControlEvent;
28 import org.eclipse.swt.events.DisposeEvent;
29 import org.eclipse.swt.events.DisposeListener;
30 import org.eclipse.swt.events.KeyAdapter;
31 import org.eclipse.swt.events.KeyEvent;
32 import org.eclipse.swt.events.KeyListener;
33 import org.eclipse.swt.events.MenuAdapter;
34 import org.eclipse.swt.events.MenuEvent;
35 import org.eclipse.swt.events.ModifyEvent;
36 import org.eclipse.swt.events.ModifyListener;
37 import org.eclipse.swt.events.SelectionAdapter;
38 import org.eclipse.swt.events.SelectionEvent;
39 import org.eclipse.swt.events.TraverseEvent;
40 import org.eclipse.swt.events.TraverseListener;
41 import org.eclipse.swt.graphics.Color;
42 import org.eclipse.swt.graphics.Font;
43 import org.eclipse.swt.graphics.GC;
44 import org.eclipse.swt.graphics.Image;
45 import org.eclipse.swt.graphics.Rectangle;
46 import org.eclipse.swt.layout.GridData;
47 import org.eclipse.swt.widgets.Composite;
48 import org.eclipse.swt.widgets.Display;
49 import org.eclipse.swt.widgets.Event;
50 import org.eclipse.swt.widgets.Label;
51 import org.eclipse.swt.widgets.Listener;
52 import org.eclipse.swt.widgets.Menu;
53 import org.eclipse.swt.widgets.MenuItem;
54 import org.eclipse.swt.widgets.Table;
55 import org.eclipse.swt.widgets.TableItem;
56 import org.eclipse.swt.widgets.Text;
57
58 import org.eclipse.core.runtime.Assert;
59 import org.eclipse.core.runtime.CoreException;
60 import org.eclipse.core.runtime.IProgressMonitor;
61 import org.eclipse.core.runtime.IStatus;
62 import org.eclipse.core.runtime.OperationCanceledException;
63 import org.eclipse.core.runtime.Platform;
64 import org.eclipse.core.runtime.ProgressMonitorWrapper;
65 import org.eclipse.core.runtime.Status;
66 import org.eclipse.core.runtime.jobs.Job;
67
68 import org.eclipse.jface.resource.ImageDescriptor;
69
70 import org.eclipse.ui.progress.UIJob;
71
72 import org.eclipse.jdt.core.IPackageFragmentRoot;
73 import org.eclipse.jdt.core.JavaModelException;
74 import org.eclipse.jdt.core.WorkingCopyOwner;
75 import org.eclipse.jdt.core.search.IJavaSearchConstants;
76 import org.eclipse.jdt.core.search.IJavaSearchScope;
77 import org.eclipse.jdt.core.search.SearchEngine;
78 import org.eclipse.jdt.core.search.SearchPattern;
79 import org.eclipse.jdt.core.search.TypeNameMatch;
80 import org.eclipse.jdt.core.search.TypeNameMatchRequestor;
81 import org.eclipse.jdt.core.search.TypeNameRequestor;
82
83 import org.eclipse.jdt.internal.corext.util.Messages;
84 import org.eclipse.jdt.internal.corext.util.OpenTypeHistory;
85 import org.eclipse.jdt.internal.corext.util.Strings;
86 import org.eclipse.jdt.internal.corext.util.TypeFilter;
87 import org.eclipse.jdt.internal.corext.util.TypeInfoFilter;
88 import org.eclipse.jdt.internal.corext.util.TypeInfoRequestorAdapter;
89
90 import org.eclipse.jdt.launching.IVMInstall;
91 import org.eclipse.jdt.launching.IVMInstallType;
92 import org.eclipse.jdt.launching.JavaRuntime;
93 import org.eclipse.jdt.launching.LibraryLocation;
94
95 import org.eclipse.jdt.ui.JavaElementLabels;
96 import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension;
97 import org.eclipse.jdt.ui.dialogs.ITypeInfoImageProvider;
98
99 import org.eclipse.jdt.internal.ui.JavaPlugin;
100 import org.eclipse.jdt.internal.ui.JavaPluginImages;
101 import org.eclipse.jdt.internal.ui.JavaUIMessages;
102
103
104 /**
105  * DO NOT REMOVE, used in a product.
106  * @deprecated As of 3.5, replaced by {@link org.eclipse.ui.dialogs.FilteredItemsSelectionDialog}
107  */
108 public class TypeInfoViewer {
109         
110         private static class SearchRequestor extends TypeNameMatchRequestor {
111                 private volatile boolean fStop;
112                 
113                 private Set fHistory;
114
115                 private TypeInfoFilter fFilter;
116                 private List fResult;
117                 
118                 public SearchRequestor(TypeInfoFilter filter) {
119                         super();
120                         fResult= new ArrayList(2048);
121                         fFilter= filter;
122                 }
123                 public TypeNameMatch[] getResult() {
124                         return (TypeNameMatch[])fResult.toArray(new TypeNameMatch[fResult.size()]);
125                 }
126                 public void cancel() {
127                         fStop= true;
128                 }
129                 public void setHistory(Set history) {
130                         fHistory= history;
131                 }
132                 
133                 /* (non-Javadoc)
134                  * @see org.eclipse.jdt.core.search.TypeNameMatchRequestor#acceptTypeNameMatch(org.eclipse.jdt.core.search.TypeNameMatch)
135                  */
136                 @Override
137                 public void acceptTypeNameMatch(TypeNameMatch match) {
138                         if (fStop)
139                                 return;
140                         if (TypeFilter.isFiltered(match))
141                                 return;
142                         if (fHistory.contains(match))
143                                 return;
144                         if (fFilter.matchesFilterExtension(match))
145                                 fResult.add(match);
146                 }
147         }
148         
149         public static class TypeInfoComparator implements Comparator {
150                 private TypeInfoLabelProvider fLabelProvider;
151                 public TypeInfoFilter fFilter;
152                 public TypeInfoComparator(TypeInfoLabelProvider labelProvider, TypeInfoFilter filter) {
153                         fLabelProvider= labelProvider;
154                         fFilter= filter;
155                 }
156             public int compare(Object left, Object right) {
157                 TypeNameMatch leftInfo= (TypeNameMatch)left;
158                 TypeNameMatch rightInfo= (TypeNameMatch)right;
159                 int leftCategory= getCamelCaseCategory(leftInfo);
160                 int rightCategory= getCamelCaseCategory(rightInfo);
161                 if (leftCategory < rightCategory)
162                         return -1;
163                 if (leftCategory > rightCategory)
164                         return +1;
165                 int result= compareName(leftInfo.getSimpleTypeName(), rightInfo.getSimpleTypeName());
166                 if (result != 0)
167                         return result;
168                 result= compareTypeContainerName(leftInfo.getTypeContainerName(), rightInfo.getTypeContainerName());
169                 if (result != 0)
170                         return result;
171                 
172                 leftCategory= getElementTypeCategory(leftInfo);
173                 rightCategory= getElementTypeCategory(rightInfo);
174                 if (leftCategory < rightCategory)
175                         return -1;
176                 if (leftCategory > rightCategory)
177                         return +1;
178                 return compareContainerName(leftInfo, rightInfo);
179             }
180                 private int compareName(String leftString, String rightString) {
181                         int result= leftString.compareToIgnoreCase(rightString);
182                         if (result != 0 || rightString.length() == 0) {
183                                 return result;
184                         } else if (Strings.isLowerCase(leftString.charAt(0)) &&
185                                 !Strings.isLowerCase(rightString.charAt(0))) {
186                         return +1;
187                         } else if (Strings.isLowerCase(rightString.charAt(0)) &&
188                         !Strings.isLowerCase(leftString.charAt(0))) {
189                         return -1;
190                         } else {
191                                 return leftString.compareTo(rightString);
192                         }
193                 }
194                 private int compareTypeContainerName(String leftString, String rightString) {
195                         int leftLength= leftString.length();
196                         int rightLength= rightString.length();
197                         if (leftLength == 0 && rightLength > 0)
198                                 return -1;
199                         if (leftLength == 0 && rightLength == 0)
200                                 return 0;
201                         if (leftLength > 0 && rightLength == 0)
202                                 return +1;
203                         return compareName(leftString, rightString);
204                 }
205                 private int compareContainerName(TypeNameMatch leftType, TypeNameMatch rightType) {
206                         return fLabelProvider.generated_4080221774471558952(leftType, rightType);
207                 }
208                 private int getCamelCaseCategory(TypeNameMatch type) {
209                         if (fFilter == null)
210                                 return 0;
211                         return fFilter.generated_6162093895603037472(type);
212                 }
213                 private int getElementTypeCategory(TypeNameMatch type) {
214                         try {
215                                 if (type.getPackageFragmentRoot().getKind() == IPackageFragmentRoot.K_SOURCE)
216                                         return 0;
217                         } catch (JavaModelException e) {
218                                 // TODO Auto-generated catch block
219                                 e.printStackTrace();
220                         }
221                         return 1;
222                 }
223         }
224         
225         public static class TypeInfoLabelProvider {
226
227                 public ITypeInfoImageProvider fProviderExtension;
228                 public TypeInfoRequestorAdapter fAdapter= new TypeInfoRequestorAdapter();
229                 
230                 private Map fLib2Name= new HashMap();
231                 private String[] fInstallLocations;
232                 private String[] fVMNames;
233
234                 private boolean fFullyQualifyDuplicates;
235                 
236                 public TypeInfoLabelProvider(ITypeInfoImageProvider extension) {
237                         fProviderExtension= extension;
238                         List locations= new ArrayList();
239                         List labels= new ArrayList();
240                         IVMInstallType[] installs= JavaRuntime.getVMInstallTypes();
241                         for (int i= 0; i < installs.length; i++) {
242                                 processVMInstallType(installs[i], locations, labels);
243                         }
244                         fInstallLocations= (String[])locations.toArray(new String[locations.size()]);
245                         fVMNames= (String[])labels.toArray(new String[labels.size()]);
246                         
247                 }
248                 public void setFullyQualifyDuplicates(boolean value) {
249                         fFullyQualifyDuplicates= value;
250                 }
251                 private void processVMInstallType(IVMInstallType installType, List locations, List labels) {
252                         if (installType != null) {
253                                 IVMInstall[] installs= installType.getVMInstalls();
254                                 boolean isMac= Platform.OS_MACOSX.equals(Platform.getOS());
255                                 final String HOME_SUFFIX= "/Home"; //$NON-NLS-1$
256                                 for (int i= 0; i < installs.length; i++) {
257                                         String label= getFormattedLabel(installs[i].getName());
258                                         LibraryLocation[] libLocations= installs[i].getLibraryLocations();
259                                         if (libLocations != null) {
260                                                 processLibraryLocation(libLocations, label);
261                                         } else {
262                                                 String filePath= installs[i].getInstallLocation().getAbsolutePath();
263                                                 // on MacOS X install locations end in an additional "/Home" segment; remove it
264                                                 if (isMac && filePath.endsWith(HOME_SUFFIX))
265                                                         filePath= filePath.substring(0, filePath.length()- HOME_SUFFIX.length() + 1);
266                                                 locations.add(filePath);
267                                                 labels.add(label);
268                                         }
269                                 }
270                         }
271                 }
272                 private void processLibraryLocation(LibraryLocation[] libLocations, String label) {
273                         for (int l= 0; l < libLocations.length; l++) {
274                                 LibraryLocation location= libLocations[l];
275                                 fLib2Name.put(location.getSystemLibraryPath().toString(), label);
276                         }
277                 }
278                 private String getFormattedLabel(String name) {
279                         return Messages.format(JavaUIMessages.TypeInfoViewer_library_name_format, name);
280                 }
281                 public String getText(Object element) {
282                         return ((TypeNameMatch)element).getSimpleTypeName();
283                 }
284                 public String getQualifiedText(TypeNameMatch type) {
285                         StringBuffer result= new StringBuffer();
286                         result.append(type.getSimpleTypeName());
287                         String containerName= type.getTypeContainerName();
288                         result.append(JavaElementLabels.CONCAT_STRING);
289                         if (containerName.length() > 0) {
290                                 result.append(containerName);
291                         } else {
292                                 result.append(JavaUIMessages.TypeInfoViewer_default_package);
293                         }
294                         return result.toString();
295                 }
296                 public String getFullyQualifiedText(TypeNameMatch type) {
297                         StringBuffer result= new StringBuffer();
298                         result.append(type.getSimpleTypeName());
299                         String containerName= type.getTypeContainerName();
300                         if (containerName.length() > 0) {
301                                 result.append(JavaElementLabels.CONCAT_STRING);
302                                 result.append(containerName);
303                         }
304                         result.append(JavaElementLabels.CONCAT_STRING);
305                         result.append(getContainerName(type));
306                         return result.toString();
307                 }
308                 public String getText(TypeNameMatch last, TypeNameMatch current, TypeNameMatch next) {
309                         StringBuffer result= new StringBuffer();
310                         int qualifications= 0;
311                         String currentTN= current.getSimpleTypeName();
312                         result.append(currentTN);
313                         String currentTCN= getTypeContainerName(current);
314                         if (last != null) {
315                                 String lastTN= last.getSimpleTypeName();
316                                 String lastTCN= getTypeContainerName(last);
317                                 if (currentTCN.equals(lastTCN)) {
318                                         if (currentTN.equals(lastTN)) {
319                                                 result.append(JavaElementLabels.CONCAT_STRING);
320                                                 result.append(currentTCN);
321                                                 result.append(JavaElementLabels.CONCAT_STRING);
322                                                 result.append(getContainerName(current));
323                                                 return result.toString();
324                                         }
325                                 } else if (currentTN.equals(lastTN)) {
326                                         qualifications= 1;
327                                 }
328                         }
329                         if (next != null) {
330                                 String nextTN= next.getSimpleTypeName();
331                                 String nextTCN= getTypeContainerName(next);
332                                 if (currentTCN.equals(nextTCN)) {
333                                         if (currentTN.equals(nextTN)) {
334                                                 result.append(JavaElementLabels.CONCAT_STRING);
335                                                 result.append(currentTCN);
336                                                 result.append(JavaElementLabels.CONCAT_STRING);
337                                                 result.append(getContainerName(current));
338                                                 return result.toString();
339                                         }
340                                 } else if (currentTN.equals(nextTN)) {
341                                         qualifications= 1;
342                                 }
343                         }
344                         if (qualifications > 0) {
345                                 result.append(JavaElementLabels.CONCAT_STRING);
346                                 result.append(currentTCN);
347                                 if (fFullyQualifyDuplicates) {
348                                         result.append(JavaElementLabels.CONCAT_STRING);
349                                         result.append(getContainerName(current));
350                                 }
351                         }
352                         return result.toString();
353                 }
354                 public String getQualificationText(TypeNameMatch type) {
355                         StringBuffer result= new StringBuffer();
356                         String containerName= type.getTypeContainerName();
357                         if (containerName.length() > 0) {
358                                 result.append(containerName);
359                                 result.append(JavaElementLabels.CONCAT_STRING);
360                         }
361                         result.append(getContainerName(type));
362                         return result.toString();
363                 }
364                 
365                 public boolean isInnerType(TypeNameMatch match) {
366                         return match.getTypeQualifiedName().indexOf('.') != -1;
367                 }
368                 
369                 public ImageDescriptor getImageDescriptor(Object element) {
370                         TypeNameMatch type= (TypeNameMatch)element;
371                         return fAdapter.generated_6686271377108945784(this, type);
372                 }
373                 private String getTypeContainerName(TypeNameMatch info) {
374                         String result= info.getTypeContainerName();
375                         if (result.length() > 0)
376                                 return result;
377                         return JavaUIMessages.TypeInfoViewer_default_package;
378                 }
379                 
380                 String getContainerName(TypeNameMatch type) {
381                         IPackageFragmentRoot root= type.getPackageFragmentRoot();
382                         if (root.isExternal()) {
383                                 String name= root.getPath().toOSString();
384                                 for (int i= 0; i < fInstallLocations.length; i++) {
385                                         if (name.startsWith(fInstallLocations[i])) {
386                                                 return fVMNames[i];
387                                         }
388                                 }
389                                 String lib= (String)fLib2Name.get(name);
390                                 if (lib != null)
391                                         return lib;
392                         }
393                         StringBuffer buf= new StringBuffer();
394                         JavaElementLabels.getPackageFragmentRootLabel(root, JavaElementLabels.ROOT_QUALIFIED | JavaElementLabels.ROOT_VARIABLE, buf);
395                         return buf.toString();
396                 }
397                 public void generated_7293536804022995861(TypeInfoViewer typeinfoviewer, TableItem item, int index, TypeNameMatch type) {
398                         item.setData(type);
399                         item.setImage(typeinfoviewer.fImageManager.get(getImageDescriptor(type)));
400                         item.setText(getText(
401                                 typeinfoviewer.getTypeInfo(index - 1),
402                                 type,
403                                 typeinfoviewer.getTypeInfo(index + 1)));
404                         item.setForeground(null);
405                 }
406                 public String generated_7876537592558312876(TypeInfoViewer typeinfoviewer, TypeNameMatch type) {
407                         return typeinfoviewer.fFullyQualifySelection
408                                 ? getFullyQualifiedText(type)
409                                 : getQualifiedText(type);
410                 }
411                 public int generated_4080221774471558952(TypeNameMatch leftType, TypeNameMatch rightType) {
412                         return getContainerName(leftType).compareTo(
413                                 getContainerName(rightType));
414                 }
415                 public void generated_5565475567477228589(TypeNameMatch last, TypeNameMatch type, TypeNameMatch next, List imageDescriptors, List labels) {
416                         imageDescriptors.add(getImageDescriptor(type));
417                         labels.add(getText(last, type, next));
418                 }
419         }
420
421         private static class ProgressUpdateJob extends UIJob {
422                 private TypeInfoViewer fViewer;
423                 private boolean fStopped;
424                 public ProgressUpdateJob(Display display, TypeInfoViewer viewer) {
425                         super(display, JavaUIMessages.TypeInfoViewer_progressJob_label);
426                         fViewer= viewer;
427                 }
428                 public void stop() {
429                         fStopped= true;
430                         cancel();
431                 }
432                 @Override
433                 public IStatus runInUIThread(IProgressMonitor monitor) {
434                         if (stopped())
435                                 return new Status(IStatus.CANCEL, JavaPlugin.getPluginId(), IStatus.CANCEL, "", null); //$NON-NLS-1$
436                         fViewer.updateProgressMessage();
437                         if (!stopped())
438                                 schedule(300);
439                         return new Status(IStatus.OK, JavaPlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
440                 }
441                 private boolean stopped() {
442                         return fStopped || fViewer.getTable().isDisposed();
443                 }
444         }
445         
446         public static class ProgressMonitor extends ProgressMonitorWrapper {
447                 private TypeInfoViewer fViewer;
448                 private String fName;
449                 private int fTotalWork;
450                 private double fWorked;
451                 private boolean fDone;
452                 
453                 public ProgressMonitor(IProgressMonitor monitor, TypeInfoViewer viewer) {
454                         super(monitor);
455                         fViewer= viewer;
456                 }
457                 @Override
458                 public void setTaskName(String name) {
459                         super.setTaskName(name);
460                         fName= name;
461                 }
462                 @Override
463                 public void beginTask(String name, int totalWork) {
464                         super.beginTask(name, totalWork);
465                         if (fName == null)
466                                 fName= name;
467                         fTotalWork= totalWork;
468                 }
469                 @Override
470                 public void worked(int work) {
471                         super.worked(work);
472                         internalWorked(work);
473                 }
474                 @Override
475                 public void done() {
476                         fDone= true;
477                         fViewer.setProgressMessage(""); //$NON-NLS-1$
478                         super.done();
479                 }
480                 @Override
481                 public void internalWorked(double work) {
482                         fWorked= fWorked + work;
483                         fViewer.setProgressMessage(getMessage());
484                 }
485                 private String getMessage() {
486                         if (fDone) {
487                                 return ""; //$NON-NLS-1$
488                         } else if (fTotalWork == 0) {
489                                 return fName;
490                         } else {
491                                 return Messages.format(
492                                         JavaUIMessages.TypeInfoViewer_progress_label,
493                                         new Object[] { fName, new Integer((int)((fWorked * 100) / fTotalWork)) });
494                         }
495                 }
496                 public void generated_4483633629445221987(AbstractSearchJob abstractsearchjob) throws CoreException, InterruptedException {
497                         if (TypeInfoViewer.VIRTUAL) {
498                                 abstractsearchjob.internalRunVirtual(this);
499                         } else {
500                                 abstractsearchjob.internalRun(this);
501                         }
502                 }
503                 public void generated_5068716864496295402() throws JavaModelException {
504                         setTaskName(JavaUIMessages.TypeInfoViewer_syncJob_taskName);
505                         new SearchEngine().searchAllTypeNames(
506                                 null,
507                                 0,
508                                 // make sure we search a concrete name. This is faster according to Kent
509                                 "_______________".toCharArray(), //$NON-NLS-1$
510                                 SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE,
511                                 IJavaSearchConstants.ENUM,
512                                 SearchEngine.createWorkspaceScope(),
513                                 new TypeNameRequestor() {},
514                                 IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
515                                 this);
516                 }
517         }
518
519         private static abstract class AbstractJob extends Job {
520                 protected TypeInfoViewer fViewer;
521                 protected AbstractJob(String name, TypeInfoViewer viewer) {
522                         super(name);
523                         fViewer= viewer;
524                         setSystem(true);
525                 }
526                 @Override
527                 protected final IStatus run(IProgressMonitor parent) {
528                         ProgressMonitor monitor= new ProgressMonitor(parent, fViewer);
529                         try {
530                                 fViewer.scheduleProgressUpdateJob();
531                                 return doRun(monitor);
532                         } finally {
533                                 fViewer.stopProgressUpdateJob();
534                         }
535                 }
536                 protected abstract IStatus doRun(ProgressMonitor monitor);
537         }
538         
539         public static abstract class AbstractSearchJob extends AbstractJob {
540                 private int fMode;
541                 
542                 protected int fTicket;
543                 public TypeInfoLabelProvider fLabelProvider;
544                 
545                 public TypeInfoFilter fFilter;
546                 protected OpenTypeHistory fHistory;
547                 
548                 protected AbstractSearchJob(int ticket, TypeInfoViewer viewer, TypeInfoFilter filter, OpenTypeHistory history, int numberOfVisibleItems, int mode) {
549                         super(JavaUIMessages.TypeInfoViewer_job_label, viewer);
550                         fMode= mode;
551                         fTicket= ticket;
552                         fViewer= viewer;
553                         fLabelProvider= fViewer.getLabelProvider();
554                         fFilter= filter;
555                         fHistory= history;
556                 }
557                 public void stop() {
558                         cancel();
559                 }
560                 @Override
561                 protected IStatus doRun(ProgressMonitor monitor) {
562                         try {
563                                 monitor.generated_4483633629445221987(AbstractSearchJob.this);
564                         } catch (CoreException e) {
565                                 fViewer.searchJobFailed(fTicket, e);
566                                 return new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.ERROR, JavaUIMessages.TypeInfoViewer_job_error, e);
567                         } catch (InterruptedException e) {
568                                 return canceled(e, true);
569                         } catch (OperationCanceledException e) {
570                                 return canceled(e, false);
571                         }
572                         fViewer.searchJobDone(fTicket);
573                         return ok();
574                 }
575                 protected abstract TypeNameMatch[] getSearchResult(Set matchIdsInHistory, ProgressMonitor monitor) throws CoreException;
576                 
577                 void internalRun(ProgressMonitor monitor) throws CoreException, InterruptedException {
578                         if (monitor.isCanceled())
579                                 throw new OperationCanceledException();
580                         
581                         fViewer.clear(fTicket);
582
583                         // local vars to speed up rendering
584                         TypeNameMatch last= null;
585                         TypeNameMatch type= null;
586                         TypeNameMatch next= null;
587                         List elements= new ArrayList();
588                         List imageDescriptors= new ArrayList();
589                         List labels= new ArrayList();
590                         Set filteredMatches= new HashSet();
591                         
592                         TypeNameMatch[] matchingTypes= fHistory.getFilteredTypeInfos(fFilter);
593                         if (matchingTypes.length > 0) {
594                                 Arrays.sort(matchingTypes, new TypeInfoComparator(fLabelProvider, fFilter));
595                                 type= matchingTypes[0];
596                                 int i= 1;
597                                 while(type != null) {
598                                         next= (i == matchingTypes.length) ? null : matchingTypes[i];
599                                         elements.add(type);
600                                         filteredMatches.add(type);
601                                         fLabelProvider.generated_5565475567477228589(last, type, next, imageDescriptors, labels);
602                                         last= type;
603                                         type= next;
604                                         i++;
605                                 }
606                         }
607                         matchingTypes= null;
608                         fViewer.fExpectedItemCount= elements.size();
609                         fViewer.addHistory(fTicket, elements, imageDescriptors, labels);
610                         
611                         if ((fMode & INDEX) == 0) {
612                                 return;
613                         }
614                         TypeNameMatch[] result= getSearchResult(filteredMatches, monitor);
615                         fViewer.fExpectedItemCount+= result.length;
616                         if (result.length == 0) {
617                                 return;
618                         }
619                         if (monitor.isCanceled())
620                                 throw new OperationCanceledException();
621                         int processed= 0;
622                         int nextIndex= 1;
623                         type= result[0];
624                         if (!filteredMatches.isEmpty()) {
625                                 fViewer.addDashLineAndUpdateLastHistoryEntry(fTicket, type);
626                         }
627                         while (true) {
628                                 long startTime= System.currentTimeMillis();
629                                 elements.clear();
630                                 imageDescriptors.clear();
631                                 labels.clear();
632                     int delta = Math.min(nextIndex == 1 ? fViewer.getNumberOfVisibleItems() : 10, result.length - processed);
633                                 if (delta == 0)
634                                         break;
635                                 processed= processed + delta;
636                                 while(delta > 0) {
637                                         next= (nextIndex == result.length) ? null : result[nextIndex];
638                                         elements.add(type);
639                                         labels.add(fLabelProvider.getText(last, type, next));
640                                         imageDescriptors.add(fLabelProvider.getImageDescriptor(type));
641                                         last= type;
642                                         type= next;
643                                         nextIndex++;
644                                         delta--;
645                                 }
646                                 fViewer.addAll(fTicket, elements, imageDescriptors, labels);
647                                 long sleep= 100 - (System.currentTimeMillis() - startTime);
648                                 
649                                 if (sleep > 0)
650                                         Thread.sleep(sleep);
651                                 
652                                 if (monitor.isCanceled())
653                                         throw new OperationCanceledException();
654                         }
655                 }
656                 void internalRunVirtual(ProgressMonitor monitor) throws CoreException, InterruptedException {
657                         if (monitor.isCanceled())
658                                 throw new OperationCanceledException();
659                         
660                         fViewer.clear(fTicket);
661
662                         TypeNameMatch[] matchingTypes= fHistory.getFilteredTypeInfos(fFilter);
663                         fViewer.setHistoryResult(fTicket, matchingTypes);
664                         if ((fMode & INDEX) == 0)
665                                 return;
666                                 
667                         Set filteredMatches= new HashSet(matchingTypes.length * 2);
668                         for (int i= 0; i < matchingTypes.length; i++) {
669                                 filteredMatches.add(matchingTypes[i]);
670                         }
671                         
672                         TypeNameMatch[] result= getSearchResult(filteredMatches, monitor);
673                         if (monitor.isCanceled())
674                                 throw new OperationCanceledException();
675                         
676                         fViewer.setSearchResult(fTicket, result);
677                 }
678                 private IStatus canceled(Exception e, boolean removePendingItems) {
679                         fViewer.searchJobCanceled(fTicket, removePendingItems);
680                         return new Status(IStatus.CANCEL, JavaPlugin.getPluginId(), IStatus.CANCEL, JavaUIMessages.TypeInfoViewer_job_cancel, e);
681                 }
682                 private IStatus ok() {
683                         return new Status(IStatus.OK, JavaPlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
684                 }
685         }
686         
687         public static class SearchEngineJob extends AbstractSearchJob {
688                 public IJavaSearchScope fScope;
689                 public int fElementKind;
690                 public SearchRequestor fReqestor;
691                 
692                 public SearchEngineJob(int ticket, TypeInfoViewer viewer, TypeInfoFilter filter, OpenTypeHistory history, int numberOfVisibleItems, int mode,
693                                 IJavaSearchScope scope, int elementKind) {
694                         super(ticket, viewer, filter, history, numberOfVisibleItems, mode);
695                         fScope= scope;
696                         fElementKind= elementKind;
697                         fReqestor= new SearchRequestor(filter);
698                 }
699                 @Override
700                 public void stop() {
701                         fReqestor.cancel();
702                         super.stop();
703                 }
704                 @Override
705                 protected TypeNameMatch[] getSearchResult(Set matchIdsInHistory, ProgressMonitor monitor) throws CoreException {
706                         long start= System.currentTimeMillis();
707                         fReqestor.setHistory(matchIdsInHistory);
708                         // consider primary working copies during searching
709                         SearchEngine engine= new SearchEngine((WorkingCopyOwner)null);
710                         String packPattern= fFilter.getPackagePattern();
711                         monitor.setTaskName(JavaUIMessages.TypeInfoViewer_searchJob_taskName);
712                         fFilter.generated_2887788459050990176(this, monitor, engine, packPattern);
713                         if (DEBUG)
714                                 System.out.println("Time needed until search has finished: " + (System.currentTimeMillis() - start)); //$NON-NLS-1$
715                         TypeNameMatch[] result= fReqestor.getResult();
716                         Arrays.sort(result, new TypeInfoComparator(fLabelProvider, fFilter));
717                         if (DEBUG)
718                                 System.out.println("Time needed until sort has finished: " + (System.currentTimeMillis() - start)); //$NON-NLS-1$
719                         fViewer.rememberResult(fTicket, result);
720                         return result;
721                 }
722         }
723         
724         public static class CachedResultJob extends AbstractSearchJob {
725                 public TypeNameMatch[] fLastResult;
726                 public CachedResultJob(int ticket, TypeNameMatch[] lastResult, TypeInfoViewer viewer, TypeInfoFilter filter, OpenTypeHistory history, int numberOfVisibleItems, int mode) {
727                         super(ticket, viewer, filter, history, numberOfVisibleItems, mode);
728                         fLastResult= lastResult;
729                 }
730                 @Override
731                 protected TypeNameMatch[] getSearchResult(Set filteredHistory, ProgressMonitor monitor) throws CoreException {
732                         return fFilter.generated_395777301205010512(this, filteredHistory);
733                 }
734         }
735         
736         private static class SyncJob extends AbstractJob {
737                 public SyncJob(TypeInfoViewer viewer) {
738                         super(JavaUIMessages.TypeInfoViewer_syncJob_label, viewer);
739                 }
740                 public void stop() {
741                         cancel();
742                 }
743                 @Override
744                 protected IStatus doRun(ProgressMonitor monitor) {
745                         try {
746                                 monitor.generated_5068716864496295402();
747                         } catch (JavaModelException e) {
748                                 JavaPlugin.log(e);
749                                 return new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.ERROR, JavaUIMessages.TypeInfoViewer_job_error, e);
750                         } catch (OperationCanceledException e) {
751                                 return new Status(IStatus.CANCEL, JavaPlugin.getPluginId(), IStatus.CANCEL, JavaUIMessages.TypeInfoViewer_job_cancel, e);
752                         } finally {
753                                 fViewer.syncJobDone();
754                         }
755                         return new Status(IStatus.OK, JavaPlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
756                 }
757         }
758         
759         static class DashLine {
760                 private int fSeparatorWidth;
761                 private String fMessage;
762                 private int fMessageLength;
763                 public String getText(int width) {
764                         StringBuffer dashes= new StringBuffer();
765                         int chars= (((width - fMessageLength) / fSeparatorWidth) / 2) -2;
766                         for (int i= 0; i < chars; i++) {
767                                 dashes.append(SEPARATOR);
768                         }
769                         StringBuffer result= new StringBuffer();
770                         result.append(dashes);
771                         result.append(fMessage);
772                         result.append(dashes);
773                         return result.toString();
774                 }
775                 public void initialize(GC gc) {
776                         fSeparatorWidth= gc.getAdvanceWidth(SEPARATOR);
777                         fMessage= " " + JavaUIMessages.TypeInfoViewer_separator_message + " ";  //$NON-NLS-1$ //$NON-NLS-2$
778                         fMessageLength= gc.textExtent(fMessage).x;
779                 }
780                 public void generated_4106678073497933459(TypeInfoViewer typeinfoviewer, TableItem item, Rectangle bounds, Rectangle area) {
781                         boolean willHaveScrollBar= typeinfoviewer.fExpectedItemCount + 1 > typeinfoviewer.fNumberOfVisibleItems;
782                         item.setText(getText(area.width - bounds.x - bounds.width - typeinfoviewer.fTableWidthDelta -
783                                 (willHaveScrollBar ? typeinfoviewer.fScrollbarWidth : 0)));
784                         item.setImage(typeinfoviewer.fSeparatorIcon);
785                         item.setForeground(typeinfoviewer.fDashLineColor);
786                         item.setData(this);
787                 }
788         }
789         
790         static class ImageManager {
791                 private Map fImages= new HashMap(20);
792                 
793                 public Image get(ImageDescriptor descriptor) {
794                         if (descriptor == null)
795                                 descriptor= ImageDescriptor.getMissingImageDescriptor();
796                         
797                         Image result= (Image)fImages.get(descriptor);
798                         if (result != null)
799                                 return result;
800                         result= descriptor.createImage();
801                         if (result != null)
802                                 fImages.put(descriptor, result);
803                         return result;
804                 }
805                 
806                 public void dispose() {
807                         for (Iterator iter= fImages.values().iterator(); iter.hasNext(); ) {
808                                 Image image= (Image)iter.next();
809                                 image.dispose();
810                         }
811                         fImages.clear();
812                 }
813         }
814         
815         private Display fDisplay;
816         
817         private String fProgressMessage;
818         private Label fProgressLabel;
819         private int fProgressCounter;
820         private ProgressUpdateJob fProgressUpdateJob;
821         
822         public OpenTypeHistory fHistory;
823
824         /* non virtual table */
825         private int fNextElement;
826         private List fItems;
827         
828         /* virtual table */
829         private TypeNameMatch[] fHistoryMatches;
830         private TypeNameMatch[] fSearchMatches;
831         
832         public int fNumberOfVisibleItems;
833         private int fExpectedItemCount;
834         private Color fDashLineColor;
835         private int fScrollbarWidth;
836         private int fTableWidthDelta;
837         private int fDashLineIndex= -1;
838         private Image fSeparatorIcon;
839         private DashLine fDashLine= new DashLine();
840         
841         private boolean fFullyQualifySelection;
842         /* remembers the last selection to restore unqualified labels */
843         private TableItem[] fLastSelection;
844         private String[] fLastLabels;
845         
846         private TypeInfoLabelProvider fLabelProvider;
847         private ImageManager fImageManager;
848         
849         private Table fTable;
850         
851         private SyncJob fSyncJob;
852         
853         public TypeInfoFilter fTypeInfoFilter;
854         private ITypeInfoFilterExtension fFilterExtension;
855         public TypeNameMatch[] fLastCompletedResult;
856         public TypeInfoFilter fLastCompletedFilter;
857         
858         public int fSearchJobTicket;
859         public int fElementKind;
860         public IJavaSearchScope fSearchScope;
861         
862         public AbstractSearchJob fSearchJob;
863
864         private static final int HISTORY= 1;
865         private static final int INDEX= 2;
866         private static final int FULL= HISTORY | INDEX;
867         
868         private static final char SEPARATOR= '-';
869         
870         private static final boolean DEBUG= false;
871         private static final boolean VIRTUAL= false;
872         
873         private static final TypeNameMatch[] EMTPY_TYPE_INFO_ARRAY= new TypeNameMatch[0];
874         // only needed when in virtual table mode
875         
876         private static final TypeNameMatch DASH_LINE= SearchEngine.createTypeNameMatch(null, 0);
877                 
878
879         public TypeInfoViewer(Composite parent, int flags, Label progressLabel,
880                         IJavaSearchScope scope, int elementKind, String initialFilter,
881                         ITypeInfoFilterExtension filterExtension, ITypeInfoImageProvider imageExtension) {
882                 Assert.isNotNull(scope);
883                 fDisplay= parent.getDisplay();
884                 fProgressLabel= progressLabel;
885                 fSearchScope= scope;
886                 fElementKind= elementKind;
887                 fFilterExtension= filterExtension;
888                 fFullyQualifySelection= (flags & SWT.MULTI) != 0;
889                 if (VIRTUAL)
890                         flags|= SWT.VIRTUAL;
891                 fTable= new Table(parent, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER | SWT.FLAT | flags);
892                 fTable.setFont(parent.getFont());
893                 fLabelProvider= new TypeInfoLabelProvider(imageExtension);
894                 fItems= new ArrayList(500);
895                 fTable.setHeaderVisible(false);
896                 addPopupMenu();
897                 fTable.addControlListener(new ControlAdapter() {
898                         @Override
899                         public void controlResized(ControlEvent event) {
900                                 int itemHeight= fTable.getItemHeight();
901                                 Rectangle clientArea= fTable.getClientArea();
902                                 fNumberOfVisibleItems= (clientArea.height / itemHeight) + 1;
903                         }
904                 });
905                 fTable.addKeyListener(new KeyAdapter() {
906                         @Override
907                         public void keyPressed(KeyEvent e) {
908                                 if (e.keyCode == SWT.DEL) {
909                                         deleteHistoryEntry();
910                                 } else if (e.keyCode == SWT.ARROW_DOWN) {
911                                         int index= fTable.getSelectionIndex();
912                                         if (index == fDashLineIndex - 1) {
913                                                 e.doit= false;
914                                                 setTableSelection(index + 2);
915                                         }
916                                 } else if (e.keyCode == SWT.ARROW_UP) {
917                                         int index= fTable.getSelectionIndex();
918                                         if (fDashLineIndex != -1 && index == fDashLineIndex + 1) {
919                                                 e.doit= false;
920                                                 setTableSelection(index - 2);
921                                         }
922                                 }
923                         }
924                 });
925                 fTable.addSelectionListener(new SelectionAdapter() {
926                         @Override
927                         public void widgetSelected(SelectionEvent e) {
928                                 if (fLastSelection != null) {
929                                         for (int i= 0; i < fLastSelection.length; i++) {
930                                                 TableItem item= fLastSelection[i];
931                                                 // could be disposed by deleting element from
932                                                 // type info history
933                                                 if (!item.isDisposed())
934                                                         item.setText(fLastLabels[i]);
935                                         }
936                                 }
937                                 TableItem[] items= fTable.getSelection();
938                                 fLastSelection= new TableItem[items.length];
939                                 fLastLabels= new String[items.length];
940                                 for (int i= 0; i < items.length; i++) {
941                                         TableItem item= items[i];
942                                         fLastSelection[i]= item;
943                                         fLastLabels[i]= item.getText();
944                                         Object data= item.getData();
945                                         if (data instanceof TypeNameMatch) {
946                                                 String qualifiedText= getQualifiedText((TypeNameMatch)data);
947                                                 if (qualifiedText.length() > fLastLabels[i].length())
948                                                         item.setText(qualifiedText);
949                                         }
950                                 }
951                         }
952                 });
953                 fTable.addDisposeListener(new DisposeListener() {
954                         public void widgetDisposed(DisposeEvent e) {
955                                 stop(true, true);
956                                 fDashLineColor.dispose();
957                                 fSeparatorIcon.dispose();
958                                 fImageManager.dispose();
959                                 if (fProgressUpdateJob != null) {
960                                         fProgressUpdateJob.stop();
961                                         fProgressUpdateJob= null;
962                                 }
963                         }
964                 });
965                 if (VIRTUAL) {
966                         fHistoryMatches= EMTPY_TYPE_INFO_ARRAY;
967                         fSearchMatches= EMTPY_TYPE_INFO_ARRAY;
968                         fTable.addListener(SWT.SetData, new Listener() {
969                                 public void handleEvent(Event event) {
970                                         TableItem item= (TableItem)event.item;
971                                         setData(item);
972                                 }
973                         });
974                 }
975                 
976                 fDashLineColor= computeDashLineColor();
977                 fScrollbarWidth= computeScrollBarWidth();
978                 fTableWidthDelta= fTable.computeTrim(0, 0, 0, 0).width - fScrollbarWidth;
979                 fSeparatorIcon= JavaPluginImages.DESC_OBJS_TYPE_SEPARATOR.createImage(fTable.getDisplay());
980                 // Use a new image manager since an extension can provide its own
981                 // image descriptors. To avoid thread problems with SWT the registry
982                 // must be created in the UI thread.
983                 fImageManager= new ImageManager();
984                 
985                 fHistory= OpenTypeHistory.getInstance();
986                 if (initialFilter != null && initialFilter.length() > 0)
987                         fTypeInfoFilter= createTypeInfoFilter(initialFilter);
988                 GC gc= null;
989                 try {
990                         gc= new GC(fTable);
991                         gc.setFont(fTable.getFont());
992                         fDashLine.initialize(gc);
993                 } finally {
994                         gc.dispose();
995                 }
996                 // If we do have a type info filter then we are
997                 // scheduling a search job in startup. So no
998                 // need to sync the search indices.
999                 if (fTypeInfoFilter == null) {
1000                         scheduleSyncJob();
1001                 }
1002         }
1003         
1004         /* package */ void startup() {
1005                 if (fTypeInfoFilter == null) {
1006                         reset();
1007                 } else {
1008                         scheduleSearchJob(FULL);
1009                 }
1010         }
1011
1012         public Table getTable() {
1013                 return fTable;
1014         }
1015         
1016         /* package */ TypeInfoLabelProvider getLabelProvider() {
1017                 return fLabelProvider;
1018         }
1019         
1020         private int getNumberOfVisibleItems() {
1021                 return fNumberOfVisibleItems;
1022         }
1023         
1024         public void setFocus() {
1025                 fTable.setFocus();
1026         }
1027         
1028         
1029         public void setQualificationStyle(boolean value) {
1030                 if (fFullyQualifySelection == value)
1031                         return;
1032                 fFullyQualifySelection= value;
1033                 if (fLastSelection != null) {
1034                         for (int i= 0; i < fLastSelection.length; i++) {
1035                                 TableItem item= fLastSelection[i];
1036                                 Object data= item.getData();
1037                                 if (data instanceof TypeNameMatch) {
1038                                         item.setText(getQualifiedText((TypeNameMatch)data));
1039                                 }
1040                         }
1041                 }
1042         }
1043         
1044         public TypeNameMatch[] getSelection() {
1045                 TableItem[] items= fTable.getSelection();
1046                 List result= new ArrayList(items.length);
1047                 for (int i= 0; i < items.length; i++) {
1048                         Object data= items[i].getData();
1049                         if (data instanceof TypeNameMatch) {
1050                                 result.add(data);
1051                         }
1052                 }
1053                 return (TypeNameMatch[])result.toArray(new TypeNameMatch[result.size()]);
1054         }
1055         
1056         public void stop() {
1057                 stop(true, false);
1058         }
1059         
1060         public void stop(boolean stopSyncJob, boolean dispose) {
1061                 if (fSyncJob != null && stopSyncJob) {
1062                         fSyncJob.stop();
1063                         fSyncJob= null;
1064                 }
1065                 if (fSearchJob != null) {
1066                         fSearchJob.stop();
1067                         fSearchJob= null;
1068                 }
1069         }
1070         
1071         public void forceSearch() {
1072                 stop(false, false);
1073                 if (fTypeInfoFilter == null) {
1074                         reset();
1075                 } else {
1076                         // clear last results
1077                         fLastCompletedFilter= null;
1078                         fLastCompletedResult= null;
1079                         scheduleSearchJob(isSyncJobRunning() ? HISTORY : FULL);
1080                 }
1081         }
1082         
1083         public void setSearchPattern(String text) {
1084                 stop(false, false);
1085                 if (text.length() == 0 || "*".equals(text)) { //$NON-NLS-1$
1086                         fTypeInfoFilter= null;
1087                         reset();
1088                 } else {
1089                         fTypeInfoFilter= createTypeInfoFilter(text);
1090                         scheduleSearchJob(isSyncJobRunning() ? HISTORY : FULL);
1091                 }
1092         }
1093         
1094         public void setSearchScope(IJavaSearchScope scope, boolean refresh) {
1095                 fSearchScope= scope;
1096                 if (!refresh)
1097                         return;
1098                 stop(false, false);
1099                 fLastCompletedFilter= null;
1100                 fLastCompletedResult= null;
1101                 if (fTypeInfoFilter == null) {
1102                         reset();
1103                 } else {
1104                         scheduleSearchJob(isSyncJobRunning() ? HISTORY : FULL);
1105                 }
1106         }
1107
1108         public void setFullyQualifyDuplicates(boolean value, boolean refresh) {
1109                 fLabelProvider.setFullyQualifyDuplicates(value);
1110                 if (!refresh)
1111                         return;
1112                 stop(false, false);
1113                 if (fTypeInfoFilter == null) {
1114                         reset();
1115                 } else {
1116                         scheduleSearchJob(isSyncJobRunning() ? HISTORY : FULL);
1117                 }
1118         }
1119         
1120         public void reset() {
1121                 fLastSelection= null;
1122                 fLastLabels= null;
1123                 fExpectedItemCount= 0;
1124                 fDashLineIndex= -1;
1125                 TypeInfoFilter filter= (fTypeInfoFilter != null)
1126                         ? fTypeInfoFilter
1127                         : new TypeInfoFilter("*", fSearchScope, fElementKind, fFilterExtension); //$NON-NLS-1$
1128                 if (VIRTUAL) {
1129                         fHistoryMatches= fHistory.getFilteredTypeInfos(filter);
1130                         fExpectedItemCount= fHistoryMatches.length;
1131                         fTable.setItemCount(fHistoryMatches.length);
1132                         // bug under windows.
1133                         if (fHistoryMatches.length == 0) {
1134                                 fTable.redraw();
1135                         }
1136                         fTable.clear(0, fHistoryMatches.length - 1);
1137                 } else {
1138                         fNextElement= 0;
1139                         TypeNameMatch[] historyItems= fHistory.getFilteredTypeInfos(filter);
1140                         if (historyItems.length == 0) {
1141                                 shortenTable();
1142                                 return;
1143                         }
1144                         fExpectedItemCount= historyItems.length;
1145                         int lastIndex= historyItems.length - 1;
1146                         TypeNameMatch last= null;
1147                         TypeNameMatch type= historyItems[0];
1148                         for (int i= 0; i < historyItems.length; i++) {
1149                                 TypeNameMatch next= i == lastIndex ? null : historyItems[i + 1];
1150                                 addSingleElement(type,
1151                                         fLabelProvider.getImageDescriptor(type),
1152                                         fLabelProvider.getText(last, type, next));
1153                                 last= type;
1154                                 type= next;
1155                         }
1156                         shortenTable();
1157                 }
1158         }
1159         
1160         protected TypeInfoFilter createTypeInfoFilter(String text) {
1161                 if ("**".equals(text)) //$NON-NLS-1$
1162                         text= "*"; //$NON-NLS-1$
1163                 return new TypeInfoFilter(text, fSearchScope, fElementKind, fFilterExtension);
1164         }
1165         
1166         private void addPopupMenu() {
1167                 Menu menu= new Menu(fTable.getShell(), SWT.POP_UP);
1168                 fTable.setMenu(menu);
1169                 final MenuItem remove= new MenuItem(menu, SWT.NONE);
1170                 remove.setText(JavaUIMessages.TypeInfoViewer_remove_from_history);
1171                 menu.addMenuListener(new MenuAdapter() {
1172                         @Override
1173                         public void menuShown(MenuEvent e) {
1174                                 TableItem[] selection= fTable.getSelection();
1175                                 remove.setEnabled(canEnable(selection));
1176                         }
1177                 });
1178                 remove.addSelectionListener(new SelectionAdapter() {
1179                         @Override
1180                         public void widgetSelected(SelectionEvent e) {
1181                                 deleteHistoryEntry();
1182                         }
1183                 });
1184         }
1185         
1186         private boolean canEnable(TableItem[] selection) {
1187                 if (selection.length == 0)
1188                         return false;
1189                 for (int i= 0; i < selection.length; i++) {
1190                         TableItem item= selection[i];
1191                         Object data= item.getData();
1192                         if (!(data instanceof TypeNameMatch))
1193                                 return false;
1194                         if (!(fHistory.contains((TypeNameMatch)data)))
1195                                 return false;
1196                 }
1197                 return true;
1198         }
1199         
1200         //---- History management -------------------------------------------------------
1201         
1202         private void deleteHistoryEntry() {
1203                 int index= fTable.getSelectionIndex();
1204                 if (index == -1)
1205                         return;
1206                 TableItem item= fTable.getItem(index);
1207                 Object element= item.getData();
1208                 if (!(element instanceof TypeNameMatch))
1209                         return;
1210                 if (fHistory.remove(element) != null) {
1211                         item.dispose();
1212                         fItems.remove(index);
1213                         int count= fTable.getItemCount();
1214                         if (count > 0) {
1215                                 item= fTable.getItem(0);
1216                                 if (item.getData() instanceof DashLine) {
1217                                         item.dispose();
1218                                         fItems.remove(0);
1219                                         fDashLineIndex= -1;
1220                                         if (count > 1) {
1221                                                 setTableSelection(0);
1222                                         }
1223                                 } else {
1224                                         if (index >= count) {
1225                                                 index= count - 1;
1226                                         }
1227                                         setTableSelection(index);
1228                                 }
1229                         } else {
1230                                 // send dummy selection
1231                                 fTable.notifyListeners(SWT.Selection, new Event());
1232                         }
1233                 }
1234         }
1235         
1236         //-- Search result updating ----------------------------------------------------
1237         
1238         private void clear(int ticket) {
1239                 syncExec(ticket, new Runnable() {
1240                         public void run() {
1241                                 fNextElement= 0;
1242                                 fDashLineIndex= -1;
1243                                 fLastSelection= null;
1244                                 fLastLabels= null;
1245                                 fExpectedItemCount= 0;
1246                         }
1247                 });
1248         }
1249         
1250         private void rememberResult(int ticket, final TypeNameMatch[] result) {
1251                 syncExec(ticket, new Runnable() {
1252                         public void run() {
1253                                 if (fLastCompletedResult == null) {
1254                                         fLastCompletedFilter= fTypeInfoFilter;
1255                                         fLastCompletedResult= result;
1256                                 }
1257                         }
1258                 });
1259         }
1260
1261         private void addHistory(int ticket, final List elements, final List imageDescriptors, final List labels) {
1262                 addAll(ticket, elements, imageDescriptors, labels);
1263         }
1264         
1265         private void addAll(int ticket, final List elements, final List imageDescriptors, final List labels) {
1266                 syncExec(ticket, new Runnable() {
1267                         public void run() {
1268                                 int size= elements.size();
1269                                 for(int i= 0; i < size; i++) {
1270                                         addSingleElement(elements.get(i),
1271                                                 (ImageDescriptor)imageDescriptors.get(i),
1272                                                 (String)labels.get(i));
1273                                 }
1274                         }
1275                 });
1276         }
1277         
1278         private void addDashLineAndUpdateLastHistoryEntry(int ticket, final TypeNameMatch next) {
1279                 syncExec(ticket, new Runnable() {
1280                         public void run() {
1281                                 if (fNextElement > 0) {
1282                                         TableItem item= fTable.getItem(fNextElement - 1);
1283                                         String label= item.getText();
1284                                         String newLabel= fLabelProvider.getText(null, (TypeNameMatch)item.getData(), next);
1285                                         if (newLabel.length() != label.length())
1286                                                 item.setText(newLabel);
1287                                         if (fLastSelection != null && fLastSelection.length > 0) {
1288                                                 TableItem last= fLastSelection[fLastSelection.length - 1];
1289                                                 if (last == item) {
1290                                                         fLastLabels[fLastLabels.length - 1]= newLabel;
1291                                                 }
1292                                         }
1293                                 }
1294                                 fDashLineIndex= fNextElement;
1295                                 addDashLine();
1296                         }
1297                 });
1298         }
1299         
1300         private void addDashLine() {
1301                 TableItem item= null;
1302                 if (fItems.size() > fNextElement) {
1303                         item= (TableItem)fItems.get(fNextElement);
1304                 } else {
1305                         item= new TableItem(fTable, SWT.NONE);
1306                         fItems.add(item);
1307                 }
1308                 fillDashLine(item);
1309                 fNextElement++;
1310         }
1311         
1312         private void addSingleElement(Object element, ImageDescriptor imageDescriptor, String label) {
1313                 TableItem item= null;
1314                 Object old= null;
1315                 if (fItems.size() > fNextElement) {
1316                         item= (TableItem)fItems.get(fNextElement);
1317                         old= item.getData();
1318                         item.setForeground(null);
1319                 } else {
1320                         item= new TableItem(fTable, SWT.NONE);
1321                         fItems.add(item);
1322                 }
1323                 item.setData(element);
1324                 item.setImage(fImageManager.get(imageDescriptor));
1325                 if (fNextElement == 0) {
1326                         if (needsSelectionChange(old, element) || fLastSelection != null) {
1327                                 item.setText(label);
1328                                 fTable.setSelection(0);
1329                     fTable.notifyListeners(SWT.Selection, new Event());
1330                         } else {
1331                                 fLastSelection= new TableItem[] { item };
1332                                 fLastLabels= new String[] { label };
1333                         }
1334                 } else {
1335                         item.setText(label);
1336                 }
1337                 fNextElement++;
1338         }
1339         
1340         private boolean needsSelectionChange(Object oldElement, Object newElement) {
1341                 int[] selected= fTable.getSelectionIndices();
1342                 if (selected.length != 1)
1343                         return true;
1344                 if (selected[0] != 0)
1345                         return true;
1346                 if (oldElement == null)
1347                         return true;
1348                 return !oldElement.equals(newElement);
1349         }
1350         
1351         private void scheduleSearchJob(int mode) {
1352                 fTypeInfoFilter.generated_2392701484878639473(this, mode);
1353                 fSearchJob.schedule();
1354         }
1355
1356         private void searchJobDone(int ticket) {
1357                 syncExec(ticket, new Runnable() {
1358                         public void run() {
1359                                 shortenTable();
1360                                 checkEmptyList();
1361                                 fSearchJob= null;
1362                         }
1363                 });
1364         }
1365         
1366         private void searchJobCanceled(int ticket, final boolean removePendingItems) {
1367                 syncExec(ticket, new Runnable() {
1368                         public void run() {
1369                                 if (removePendingItems) {
1370                                         shortenTable();
1371                                         checkEmptyList();
1372                                 }
1373                                 fSearchJob= null;
1374                         }
1375                 });
1376         }
1377         
1378         private synchronized void searchJobFailed(int ticket, CoreException e) {
1379                 searchJobDone(ticket);
1380                 JavaPlugin.log(e);
1381         }
1382         
1383         //-- virtual table support -------------------------------------------------------
1384         
1385         private void setHistoryResult(int ticket, final TypeNameMatch[] types) {
1386                 syncExec(ticket, new Runnable() {
1387                         public void run() {
1388                                 fExpectedItemCount= types.length;
1389                                 int lastHistoryLength= fHistoryMatches.length;
1390                                 fHistoryMatches= types;
1391                                 int length= fHistoryMatches.length + fSearchMatches.length;
1392                                 int dash= (fHistoryMatches.length > 0 && fSearchMatches.length > 0) ? 1 : 0;
1393                                 fTable.setItemCount(length + dash);
1394                                 if (length == 0) {
1395                                         // bug under windows.
1396                                         fTable.redraw();
1397                                         return;
1398                                 }
1399                                 int update= Math.max(lastHistoryLength, fHistoryMatches.length);
1400                                 if (update > 0) {
1401                                         fTable.clear(0, update + dash - 1);
1402                                 }
1403                         }
1404                 });
1405         }
1406         
1407         private void setSearchResult(int ticket, final TypeNameMatch[] types) {
1408                 syncExec(ticket, new Runnable() {
1409                         public void run() {
1410                                 fExpectedItemCount+= types.length;
1411                                 fSearchMatches= types;
1412                                 int length= fHistoryMatches.length + fSearchMatches.length;
1413                                 int dash= (fHistoryMatches.length > 0 && fSearchMatches.length > 0) ? 1 : 0;
1414                                 fTable.setItemCount(length + dash);
1415                                 if (length == 0) {
1416                                         // bug under windows.
1417                                         fTable.redraw();
1418                                         return;
1419                                 }
1420                                 if (fHistoryMatches.length == 0) {
1421                                         fTable.clear(0, length + dash - 1);
1422                                 } else {
1423                                         fTable.clear(fHistoryMatches.length - 1, length + dash - 1);
1424                                 }
1425                         }
1426                 });
1427         }
1428         
1429         private void setData(TableItem item) {
1430                 int index= fTable.indexOf(item);
1431                 TypeNameMatch type= getTypeInfo(index);
1432                 if (type == DASH_LINE) {
1433                         item.setData(fDashLine);
1434                         fillDashLine(item);
1435                 } else {
1436                         fLabelProvider.generated_7293536804022995861(this, item, index, type);
1437                 }
1438         }
1439
1440         private TypeNameMatch getTypeInfo(int index) {
1441                 if (index < 0)
1442                         return null;
1443                 if (index < fHistoryMatches.length) {
1444                         return fHistoryMatches[index];
1445                 }
1446                 int dash= (fHistoryMatches.length > 0 && fSearchMatches.length > 0) ? 1 : 0;
1447                 if (index == fHistoryMatches.length && dash == 1) {
1448                         return DASH_LINE;
1449                 }
1450                 index= index - fHistoryMatches.length - dash;
1451                 if (index >= fSearchMatches.length)
1452                         return null;
1453                 return fSearchMatches[index];
1454         }
1455         
1456         //-- Sync Job updates ------------------------------------------------------------
1457         
1458         private void scheduleSyncJob() {
1459                 fSyncJob= new SyncJob(this);
1460                 fSyncJob.schedule();
1461         }
1462         
1463         private void syncJobDone() {
1464                 syncExec(new Runnable() {
1465                         public void run() {
1466                                 fSyncJob= null;
1467                                 if (fTypeInfoFilter != null) {
1468                                         scheduleSearchJob(FULL);
1469                                 }
1470                         }
1471                 });
1472         }
1473
1474         private boolean isSyncJobRunning() {
1475                 return fSyncJob != null;
1476         }
1477         
1478         //-- progress monitor updates -----------------------------------------------------
1479         
1480         private void scheduleProgressUpdateJob() {
1481                 syncExec(new Runnable() {
1482                         public void run() {
1483                                 if (fProgressCounter == 0) {
1484                                         clearProgressMessage();
1485                                         fProgressUpdateJob= new ProgressUpdateJob(fDisplay, TypeInfoViewer.this);
1486                                         fProgressUpdateJob.schedule(300);
1487                                 }
1488                                 fProgressCounter++;
1489                         }
1490                 });
1491         }
1492         
1493         private void stopProgressUpdateJob() {
1494                 syncExec(new Runnable() {
1495                         public void run() {
1496                                 fProgressCounter--;
1497                                 if (fProgressCounter == 0 && fProgressUpdateJob != null) {
1498                                         fProgressUpdateJob.stop();
1499                                         fProgressUpdateJob= null;
1500                                         clearProgressMessage();
1501                                 }
1502                         }
1503                 });
1504         }
1505         
1506         private void setProgressMessage(String message) {
1507                 fProgressMessage= message;
1508         }
1509         
1510         private void clearProgressMessage() {
1511                 fProgressMessage= ""; //$NON-NLS-1$
1512                 fProgressLabel.setText(fProgressMessage);
1513         }
1514         
1515         private void updateProgressMessage() {
1516                 fProgressLabel.setText(fProgressMessage);
1517         }
1518         
1519         //-- Helper methods --------------------------------------------------------------
1520
1521         private void syncExec(final Runnable runnable) {
1522                 if (fDisplay.isDisposed())
1523                         return;
1524                 fDisplay.syncExec(new Runnable() {
1525                         public void run() {
1526                                 if (fTable.isDisposed())
1527                                         return;
1528                                 runnable.run();
1529                         }
1530                 });
1531         }
1532         
1533         private void syncExec(final int ticket, final Runnable runnable) {
1534                 if (fDisplay.isDisposed())
1535                         return;
1536                 fDisplay.syncExec(new Runnable() {
1537                         public void run() {
1538                                 if (fTable.isDisposed() || ticket != fSearchJobTicket)
1539                                         return;
1540                                 runnable.run();
1541                         }
1542                 });
1543         }
1544         
1545         private void fillDashLine(TableItem item) {
1546                 Rectangle bounds= item.getImageBounds(0);
1547                 Rectangle area= fTable.getBounds();
1548                 fDashLine.generated_4106678073497933459(this, item, bounds, area);
1549         }
1550
1551         private void shortenTable() {
1552                 if (VIRTUAL)
1553                         return;
1554         if (fNextElement < fItems.size()) {
1555             fTable.setRedraw(false);
1556             fTable.remove(fNextElement, fItems.size() - 1);
1557             fTable.setRedraw(true);
1558         }
1559                 for (int i= fItems.size() - 1; i >= fNextElement; i--) {
1560                         fItems.remove(i);
1561                 }
1562         }
1563         
1564         private void checkEmptyList() {
1565                 if (fTable.getItemCount() == 0) {
1566                         fTable.notifyListeners(SWT.Selection, new Event());
1567                 }
1568         }
1569         
1570         private void setTableSelection(int index) {
1571                 fTable.setSelection(index);
1572                 fTable.notifyListeners(SWT.Selection, new Event());
1573         }
1574         
1575         private Color computeDashLineColor() {
1576                 Color fg= fTable.getForeground();
1577                 int fGray= (int)(0.3*fg.getRed() + 0.59*fg.getGreen() + 0.11*fg.getBlue());
1578                 Color bg= fTable.getBackground();
1579                 int bGray= (int)(0.3*bg.getRed() + 0.59*bg.getGreen() + 0.11*bg.getBlue());
1580                 int gray= (int)((fGray + bGray) * 0.66);
1581                 return new Color(fDisplay, gray, gray, gray);
1582         }
1583         
1584         private int computeScrollBarWidth() {
1585                 Composite t= new Composite(fTable.getShell(), SWT.V_SCROLL);
1586                 int result= t.computeTrim(0, 0, 0, 0).width;
1587                 t.dispose();
1588                 return result;
1589         }
1590
1591         private String getQualifiedText(TypeNameMatch type) {
1592                 return fLabelProvider.generated_7876537592558312876(this, type);
1593         }
1594
1595         public void generated_694059975286430385(final TypeSelectionComponent typeselectioncomponent, final String message, Font font, GridData gd) {
1596                 typeselectioncomponent.fFilter.setLayoutData(gd);
1597                 typeselectioncomponent.fFilter.addModifyListener(new ModifyListener() {
1598                         public void modifyText(ModifyEvent e) {
1599                                 typeselectioncomponent.patternChanged((Text)e.widget);
1600                         }
1601                 });
1602                 typeselectioncomponent.fFilter.addKeyListener(new KeyListener() {
1603                         public void keyReleased(KeyEvent e) {
1604                         }
1605                         public void keyPressed(KeyEvent e) {
1606                                 if (e.keyCode == SWT.ARROW_DOWN) {
1607                                         setFocus();
1608                                 }
1609                         }
1610                 });
1611                 typeselectioncomponent.fFilter.getAccessible().addAccessibleListener(new AccessibleAdapter() {
1612                         @Override
1613                         public void getName(AccessibleEvent e) {
1614                                 e.result= Strings.removeMnemonicIndicator(message);
1615                         }
1616                 });
1617                 TextFieldNavigationHandler.install(typeselectioncomponent.fFilter);
1618                 
1619                 Label label= new Label(typeselectioncomponent, SWT.NONE);
1620                 label.setFont(font);
1621                 label.setText(JavaUIMessages.TypeSelectionComponent_label);
1622                 label.addTraverseListener(new TraverseListener() {
1623                         public void keyTraversed(TraverseEvent e) {
1624                                 if (e.detail == SWT.TRAVERSE_MNEMONIC && e.doit) {
1625                                         e.detail= SWT.TRAVERSE_NONE;
1626                                         setFocus();
1627                                 }
1628                         }
1629                 });
1630         }
1631 }