KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > dialogs > TypeInfoViewer


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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 JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.Comparator JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.HashSet JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Map JavaDoc;
21 import java.util.Set JavaDoc;
22
23 import org.eclipse.core.runtime.Assert;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IProgressMonitor;
26 import org.eclipse.core.runtime.IStatus;
27 import org.eclipse.core.runtime.OperationCanceledException;
28 import org.eclipse.core.runtime.Platform;
29 import org.eclipse.core.runtime.ProgressMonitorWrapper;
30 import org.eclipse.core.runtime.Status;
31 import org.eclipse.core.runtime.jobs.Job;
32
33 import org.eclipse.swt.SWT;
34 import org.eclipse.swt.events.ControlAdapter;
35 import org.eclipse.swt.events.ControlEvent;
36 import org.eclipse.swt.events.DisposeEvent;
37 import org.eclipse.swt.events.DisposeListener;
38 import org.eclipse.swt.events.KeyAdapter;
39 import org.eclipse.swt.events.KeyEvent;
40 import org.eclipse.swt.events.MenuAdapter;
41 import org.eclipse.swt.events.MenuEvent;
42 import org.eclipse.swt.events.SelectionAdapter;
43 import org.eclipse.swt.events.SelectionEvent;
44 import org.eclipse.swt.graphics.Color;
45 import org.eclipse.swt.graphics.GC;
46 import org.eclipse.swt.graphics.Image;
47 import org.eclipse.swt.graphics.Rectangle;
48 import org.eclipse.swt.widgets.Composite;
49 import org.eclipse.swt.widgets.Display;
50 import org.eclipse.swt.widgets.Event;
51 import org.eclipse.swt.widgets.Label;
52 import org.eclipse.swt.widgets.Listener;
53 import org.eclipse.swt.widgets.Menu;
54 import org.eclipse.swt.widgets.MenuItem;
55 import org.eclipse.swt.widgets.Table;
56 import org.eclipse.swt.widgets.TableItem;
57
58 import org.eclipse.jface.resource.ImageDescriptor;
59
60 import org.eclipse.ui.progress.UIJob;
61
62 import org.eclipse.jdt.core.IPackageFragmentRoot;
63 import org.eclipse.jdt.core.JavaModelException;
64 import org.eclipse.jdt.core.WorkingCopyOwner;
65 import org.eclipse.jdt.core.search.IJavaSearchConstants;
66 import org.eclipse.jdt.core.search.IJavaSearchScope;
67 import org.eclipse.jdt.core.search.SearchEngine;
68 import org.eclipse.jdt.core.search.SearchPattern;
69 import org.eclipse.jdt.core.search.TypeNameMatch;
70 import org.eclipse.jdt.core.search.TypeNameMatchRequestor;
71 import org.eclipse.jdt.core.search.TypeNameRequestor;
72
73 import org.eclipse.jdt.internal.corext.util.Messages;
74 import org.eclipse.jdt.internal.corext.util.OpenTypeHistory;
75 import org.eclipse.jdt.internal.corext.util.Strings;
76 import org.eclipse.jdt.internal.corext.util.TypeFilter;
77 import org.eclipse.jdt.internal.corext.util.TypeInfoRequestorAdapter;
78 import org.eclipse.jdt.internal.corext.util.TypeInfoFilter;
79
80 import org.eclipse.jdt.launching.IVMInstall;
81 import org.eclipse.jdt.launching.IVMInstallType;
82 import org.eclipse.jdt.launching.JavaRuntime;
83 import org.eclipse.jdt.launching.LibraryLocation;
84
85 import org.eclipse.jdt.ui.JavaElementLabels;
86 import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension;
87 import org.eclipse.jdt.ui.dialogs.ITypeInfoImageProvider;
88
89 import org.eclipse.jdt.internal.ui.JavaPlugin;
90 import org.eclipse.jdt.internal.ui.JavaPluginImages;
91 import org.eclipse.jdt.internal.ui.JavaUIMessages;
92 import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
93
94 /**
95  * A viewer to present type queried form the type history and form the
96  * search engine. All viewer updating takes place in the UI thread.
97  * Therefore no synchronization of the methods is necessary.
98  *
99  * @since 3.1
100  */

101 public class TypeInfoViewer {
102     
103     private static class SearchRequestor extends TypeNameMatchRequestor {
104         private volatile boolean fStop;
105         
106         private Set JavaDoc fHistory;
107
108         private TypeInfoFilter fFilter;
109         private List JavaDoc fResult;
110         
111         public SearchRequestor(TypeInfoFilter filter) {
112             super();
113             fResult= new ArrayList JavaDoc(2048);
114             fFilter= filter;
115         }
116         public TypeNameMatch[] getResult() {
117             return (TypeNameMatch[])fResult.toArray(new TypeNameMatch[fResult.size()]);
118         }
119         public void cancel() {
120             fStop= true;
121         }
122         public void setHistory(Set JavaDoc history) {
123             fHistory= history;
124         }
125         
126         /* (non-Javadoc)
127          * @see org.eclipse.jdt.core.search.TypeNameMatchRequestor#acceptTypeNameMatch(org.eclipse.jdt.core.search.TypeNameMatch)
128          */

129         public void acceptTypeNameMatch(TypeNameMatch match) {
130             if (fStop)
131                 return;
132             if (TypeFilter.isFiltered(match))
133                 return;
134             if (fHistory.contains(match))
135                 return;
136             if (fFilter.matchesFilterExtension(match))
137                 fResult.add(match);
138         }
139     }
140     
141     protected static class TypeInfoComparator implements Comparator JavaDoc {
142         private TypeInfoLabelProvider fLabelProvider;
143         private TypeInfoFilter fFilter;
144         public TypeInfoComparator(TypeInfoLabelProvider labelProvider, TypeInfoFilter filter) {
145             fLabelProvider= labelProvider;
146             fFilter= filter;
147         }
148         public int compare(Object JavaDoc left, Object JavaDoc right) {
149             TypeNameMatch leftInfo= (TypeNameMatch)left;
150             TypeNameMatch rightInfo= (TypeNameMatch)right;
151             int leftCategory= getCamelCaseCategory(leftInfo);
152             int rightCategory= getCamelCaseCategory(rightInfo);
153             if (leftCategory < rightCategory)
154                 return -1;
155             if (leftCategory > rightCategory)
156                 return +1;
157             int result= compareName(leftInfo.getSimpleTypeName(), rightInfo.getSimpleTypeName());
158             if (result != 0)
159                 return result;
160             result= compareTypeContainerName(leftInfo.getTypeContainerName(), rightInfo.getTypeContainerName());
161             if (result != 0)
162                 return result;
163             
164             leftCategory= getElementTypeCategory(leftInfo);
165             rightCategory= getElementTypeCategory(rightInfo);
166             if (leftCategory < rightCategory)
167                 return -1;
168             if (leftCategory > rightCategory)
169                 return +1;
170             return compareContainerName(leftInfo, rightInfo);
171         }
172         private int compareName(String JavaDoc leftString, String JavaDoc rightString) {
173             int result= leftString.compareToIgnoreCase(rightString);
174             if (result != 0 || rightString.length() == 0) {
175                 return result;
176             } else if (Strings.isLowerCase(leftString.charAt(0)) &&
177                 !Strings.isLowerCase(rightString.charAt(0))) {
178                 return +1;
179             } else if (Strings.isLowerCase(rightString.charAt(0)) &&
180                 !Strings.isLowerCase(leftString.charAt(0))) {
181                 return -1;
182             } else {
183                 return leftString.compareTo(rightString);
184             }
185         }
186         private int compareTypeContainerName(String JavaDoc leftString, String JavaDoc rightString) {
187             int leftLength= leftString.length();
188             int rightLength= rightString.length();
189             if (leftLength == 0 && rightLength > 0)
190                 return -1;
191             if (leftLength == 0 && rightLength == 0)
192                 return 0;
193             if (leftLength > 0 && rightLength == 0)
194                 return +1;
195             return compareName(leftString, rightString);
196         }
197         private int compareContainerName(TypeNameMatch leftType, TypeNameMatch rightType) {
198             return fLabelProvider.getContainerName(leftType).compareTo(
199                 fLabelProvider.getContainerName(rightType));
200         }
201         private int getCamelCaseCategory(TypeNameMatch type) {
202             if (fFilter == null)
203                 return 0;
204             if (!fFilter.isCamelCasePattern())
205                 return 0;
206             return fFilter.matchesRawNamePattern(type) ? 0 : 1;
207         }
208         private int getElementTypeCategory(TypeNameMatch type) {
209             try {
210                 if (type.getPackageFragmentRoot().getKind() == IPackageFragmentRoot.K_SOURCE)
211                     return 0;
212             } catch (JavaModelException e) {
213                 // TODO Auto-generated catch block
214
e.printStackTrace();
215             }
216             return 1;
217         }
218     }
219     
220     protected static class TypeInfoLabelProvider {
221
222         private ITypeInfoImageProvider fProviderExtension;
223         private TypeInfoRequestorAdapter fAdapter= new TypeInfoRequestorAdapter();
224         
225         private Map JavaDoc fLib2Name= new HashMap JavaDoc();
226         private String JavaDoc[] fInstallLocations;
227         private String JavaDoc[] fVMNames;
228
229         private boolean fFullyQualifyDuplicates;
230         
231         public TypeInfoLabelProvider(ITypeInfoImageProvider extension) {
232             fProviderExtension= extension;
233             List JavaDoc locations= new ArrayList JavaDoc();
234             List JavaDoc labels= new ArrayList JavaDoc();
235             IVMInstallType[] installs= JavaRuntime.getVMInstallTypes();
236             for (int i= 0; i < installs.length; i++) {
237                 processVMInstallType(installs[i], locations, labels);
238             }
239             fInstallLocations= (String JavaDoc[])locations.toArray(new String JavaDoc[locations.size()]);
240             fVMNames= (String JavaDoc[])labels.toArray(new String JavaDoc[labels.size()]);
241             
242         }
243         public void setFullyQualifyDuplicates(boolean value) {
244             fFullyQualifyDuplicates= value;
245         }
246         private void processVMInstallType(IVMInstallType installType, List JavaDoc locations, List JavaDoc labels) {
247             if (installType != null) {
248                 IVMInstall[] installs= installType.getVMInstalls();
249                 boolean isMac= Platform.OS_MACOSX.equals(Platform.getOS());
250                 final String JavaDoc HOME_SUFFIX= "/Home"; //$NON-NLS-1$
251
for (int i= 0; i < installs.length; i++) {
252                     String JavaDoc label= getFormattedLabel(installs[i].getName());
253                     LibraryLocation[] libLocations= installs[i].getLibraryLocations();
254                     if (libLocations != null) {
255                         processLibraryLocation(libLocations, label);
256                     } else {
257                         String JavaDoc filePath= installs[i].getInstallLocation().getAbsolutePath();
258                         // on MacOS X install locations end in an additional "/Home" segment; remove it
259
if (isMac && filePath.endsWith(HOME_SUFFIX))
260                             filePath= filePath.substring(0, filePath.length()- HOME_SUFFIX.length() + 1);
261                         locations.add(filePath);
262                         labels.add(label);
263                     }
264                 }
265             }
266         }
267         private void processLibraryLocation(LibraryLocation[] libLocations, String JavaDoc label) {
268             for (int l= 0; l < libLocations.length; l++) {
269                 LibraryLocation location= libLocations[l];
270                 fLib2Name.put(location.getSystemLibraryPath().toString(), label);
271             }
272         }
273         private String JavaDoc getFormattedLabel(String JavaDoc name) {
274             return Messages.format(JavaUIMessages.TypeInfoViewer_library_name_format, name);
275         }
276         public String JavaDoc getText(Object JavaDoc element) {
277             return ((TypeNameMatch)element).getSimpleTypeName();
278         }
279         public String JavaDoc getQualifiedText(TypeNameMatch type) {
280             StringBuffer JavaDoc result= new StringBuffer JavaDoc();
281             result.append(type.getSimpleTypeName());
282             String JavaDoc containerName= type.getTypeContainerName();
283             result.append(JavaElementLabels.CONCAT_STRING);
284             if (containerName.length() > 0) {
285                 result.append(containerName);
286             } else {
287                 result.append(JavaUIMessages.TypeInfoViewer_default_package);
288             }
289             return result.toString();
290         }
291         public String JavaDoc getFullyQualifiedText(TypeNameMatch type) {
292             StringBuffer JavaDoc result= new StringBuffer JavaDoc();
293             result.append(type.getSimpleTypeName());
294             String JavaDoc containerName= type.getTypeContainerName();
295             if (containerName.length() > 0) {
296                 result.append(JavaElementLabels.CONCAT_STRING);
297                 result.append(containerName);
298             }
299             result.append(JavaElementLabels.CONCAT_STRING);
300             result.append(getContainerName(type));
301             return result.toString();
302         }
303         public String JavaDoc getText(TypeNameMatch last, TypeNameMatch current, TypeNameMatch next) {
304             StringBuffer JavaDoc result= new StringBuffer JavaDoc();
305             int qualifications= 0;
306             String JavaDoc currentTN= current.getSimpleTypeName();
307             result.append(currentTN);
308             String JavaDoc currentTCN= getTypeContainerName(current);
309             if (last != null) {
310                 String JavaDoc lastTN= last.getSimpleTypeName();
311                 String JavaDoc lastTCN= getTypeContainerName(last);
312                 if (currentTCN.equals(lastTCN)) {
313                     if (currentTN.equals(lastTN)) {
314                         result.append(JavaElementLabels.CONCAT_STRING);
315                         result.append(currentTCN);
316                         result.append(JavaElementLabels.CONCAT_STRING);
317                         result.append(getContainerName(current));
318                         return result.toString();
319                     }
320                 } else if (currentTN.equals(lastTN)) {
321                     qualifications= 1;
322                 }
323             }
324             if (next != null) {
325                 String JavaDoc nextTN= next.getSimpleTypeName();
326                 String JavaDoc nextTCN= getTypeContainerName(next);
327                 if (currentTCN.equals(nextTCN)) {
328                     if (currentTN.equals(nextTN)) {
329                         result.append(JavaElementLabels.CONCAT_STRING);
330                         result.append(currentTCN);
331                         result.append(JavaElementLabels.CONCAT_STRING);
332                         result.append(getContainerName(current));
333                         return result.toString();
334                     }
335                 } else if (currentTN.equals(nextTN)) {
336                     qualifications= 1;
337                 }
338             }
339             if (qualifications > 0) {
340                 result.append(JavaElementLabels.CONCAT_STRING);
341                 result.append(currentTCN);
342                 if (fFullyQualifyDuplicates) {
343                     result.append(JavaElementLabels.CONCAT_STRING);
344                     result.append(getContainerName(current));
345                 }
346             }
347             return result.toString();
348         }
349         public String JavaDoc getQualificationText(TypeNameMatch type) {
350             StringBuffer JavaDoc result= new StringBuffer JavaDoc();
351             String JavaDoc containerName= type.getTypeContainerName();
352             if (containerName.length() > 0) {
353                 result.append(containerName);
354                 result.append(JavaElementLabels.CONCAT_STRING);
355             }
356             result.append(getContainerName(type));
357             return result.toString();
358         }
359         
360         private boolean isInnerType(TypeNameMatch match) {
361             return match.getTypeQualifiedName().indexOf('.') != -1;
362         }
363         
364         public ImageDescriptor getImageDescriptor(Object JavaDoc element) {
365             TypeNameMatch type= (TypeNameMatch)element;
366             if (fProviderExtension != null) {
367                 fAdapter.setMatch(type);
368                 ImageDescriptor descriptor= fProviderExtension.getImageDescriptor(fAdapter);
369                 if (descriptor != null)
370                     return descriptor;
371             }
372             return JavaElementImageProvider.getTypeImageDescriptor(
373                 isInnerType(type), false, type.getModifiers(), false);
374         }
375         
376         private String JavaDoc getTypeContainerName(TypeNameMatch info) {
377             String JavaDoc result= info.getTypeContainerName();
378             if (result.length() > 0)
379                 return result;
380             return JavaUIMessages.TypeInfoViewer_default_package;
381         }
382         
383         private String JavaDoc getContainerName(TypeNameMatch type) {
384             IPackageFragmentRoot root= type.getPackageFragmentRoot();
385             if (root.isExternal()) {
386                 String JavaDoc name= root.getPath().toOSString();
387                 for (int i= 0; i < fInstallLocations.length; i++) {
388                     if (name.startsWith(fInstallLocations[i])) {
389                         return fVMNames[i];
390                     }
391                 }
392                 String JavaDoc lib= (String JavaDoc)fLib2Name.get(name);
393                 if (lib != null)
394                     return lib;
395             }
396             StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
397             JavaElementLabels.getPackageFragmentRootLabel(root, JavaElementLabels.ROOT_QUALIFIED | JavaElementLabels.ROOT_VARIABLE, buf);
398             return buf.toString();
399         }
400     }
401
402     private static class ProgressUpdateJob extends UIJob {
403         private TypeInfoViewer fViewer;
404         private boolean fStopped;
405         public ProgressUpdateJob(Display display, TypeInfoViewer viewer) {
406             super(display, JavaUIMessages.TypeInfoViewer_progressJob_label);
407             fViewer= viewer;
408         }
409         public void stop() {
410             fStopped= true;
411             cancel();
412         }
413         public IStatus runInUIThread(IProgressMonitor monitor) {
414             if (stopped())
415                 return new Status(IStatus.CANCEL, JavaPlugin.getPluginId(), IStatus.CANCEL, "", null); //$NON-NLS-1$
416
fViewer.updateProgressMessage();
417             if (!stopped())
418                 schedule(300);
419             return new Status(IStatus.OK, JavaPlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
420
}
421         private boolean stopped() {
422             return fStopped || fViewer.getTable().isDisposed();
423         }
424     }
425     
426     private static class ProgressMonitor extends ProgressMonitorWrapper {
427         private TypeInfoViewer fViewer;
428         private String JavaDoc fName;
429         private int fTotalWork;
430         private double fWorked;
431         private boolean fDone;
432         
433         public ProgressMonitor(IProgressMonitor monitor, TypeInfoViewer viewer) {
434             super(monitor);
435             fViewer= viewer;
436         }
437         public void setTaskName(String JavaDoc name) {
438             super.setTaskName(name);
439             fName= name;
440         }
441         public void beginTask(String JavaDoc name, int totalWork) {
442             super.beginTask(name, totalWork);
443             if (fName == null)
444                 fName= name;
445             fTotalWork= totalWork;
446         }
447         public void worked(int work) {
448             super.worked(work);
449             internalWorked(work);
450         }
451         public void done() {
452             fDone= true;
453             fViewer.setProgressMessage(""); //$NON-NLS-1$
454
super.done();
455         }
456         public void internalWorked(double work) {
457             fWorked= fWorked + work;
458             fViewer.setProgressMessage(getMessage());
459         }
460         private String JavaDoc getMessage() {
461             if (fDone) {
462                 return ""; //$NON-NLS-1$
463
} else if (fTotalWork == 0) {
464                 return fName;
465             } else {
466                 return Messages.format(
467                     JavaUIMessages.TypeInfoViewer_progress_label,
468                     new Object JavaDoc[] { fName, new Integer JavaDoc((int)((fWorked * 100) / fTotalWork)) });
469             }
470         }
471     }
472
473     private static abstract class AbstractJob extends Job {
474         protected TypeInfoViewer fViewer;
475         protected AbstractJob(String JavaDoc name, TypeInfoViewer viewer) {
476             super(name);
477             fViewer= viewer;
478             setSystem(true);
479         }
480         protected final IStatus run(IProgressMonitor parent) {
481             ProgressMonitor monitor= new ProgressMonitor(parent, fViewer);
482             try {
483                 fViewer.scheduleProgressUpdateJob();
484                 return doRun(monitor);
485             } finally {
486                 fViewer.stopProgressUpdateJob();
487             }
488         }
489         protected abstract IStatus doRun(ProgressMonitor monitor);
490     }
491     
492     private static abstract class AbstractSearchJob extends AbstractJob {
493         private int fMode;
494         
495         protected int fTicket;
496         protected TypeInfoLabelProvider fLabelProvider;
497         
498         protected TypeInfoFilter fFilter;
499         protected OpenTypeHistory fHistory;
500         
501         protected AbstractSearchJob(int ticket, TypeInfoViewer viewer, TypeInfoFilter filter, OpenTypeHistory history, int numberOfVisibleItems, int mode) {
502             super(JavaUIMessages.TypeInfoViewer_job_label, viewer);
503             fMode= mode;
504             fTicket= ticket;
505             fViewer= viewer;
506             fLabelProvider= fViewer.getLabelProvider();
507             fFilter= filter;
508             fHistory= history;
509         }
510         public void stop() {
511             cancel();
512         }
513         protected IStatus doRun(ProgressMonitor monitor) {
514             try {
515                 if (VIRTUAL) {
516                     internalRunVirtual(monitor);
517                 } else {
518                     internalRun(monitor);
519                 }
520             } catch (CoreException e) {
521                 fViewer.searchJobFailed(fTicket, e);
522                 return new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.ERROR, JavaUIMessages.TypeInfoViewer_job_error, e);
523             } catch (InterruptedException JavaDoc e) {
524                 return canceled(e, true);
525             } catch (OperationCanceledException e) {
526                 return canceled(e, false);
527             }
528             fViewer.searchJobDone(fTicket);
529             return ok();
530         }
531         protected abstract TypeNameMatch[] getSearchResult(Set JavaDoc matchIdsInHistory, ProgressMonitor monitor) throws CoreException;
532         
533         private void internalRun(ProgressMonitor monitor) throws CoreException, InterruptedException JavaDoc {
534             if (monitor.isCanceled())
535                 throw new OperationCanceledException();
536             
537             fViewer.clear(fTicket);
538
539             // local vars to speed up rendering
540
TypeNameMatch last= null;
541             TypeNameMatch type= null;
542             TypeNameMatch next= null;
543             List JavaDoc elements= new ArrayList JavaDoc();
544             List JavaDoc imageDescriptors= new ArrayList JavaDoc();
545             List JavaDoc labels= new ArrayList JavaDoc();
546             Set JavaDoc filteredMatches= new HashSet JavaDoc();
547             
548             TypeNameMatch[] matchingTypes= fHistory.getFilteredTypeInfos(fFilter);
549             if (matchingTypes.length > 0) {
550                 Arrays.sort(matchingTypes, new TypeInfoComparator(fLabelProvider, fFilter));
551                 type= matchingTypes[0];
552                 int i= 1;
553                 while(type != null) {
554                     next= (i == matchingTypes.length) ? null : matchingTypes[i];
555                     elements.add(type);
556                     filteredMatches.add(type);
557                     imageDescriptors.add(fLabelProvider.getImageDescriptor(type));
558                     labels.add(fLabelProvider.getText(last, type, next));
559                     last= type;
560                     type= next;
561                     i++;
562                 }
563             }
564             matchingTypes= null;
565             fViewer.fExpectedItemCount= elements.size();
566             fViewer.addHistory(fTicket, elements, imageDescriptors, labels);
567             
568             if ((fMode & INDEX) == 0) {
569                 return;
570             }
571             TypeNameMatch[] result= getSearchResult(filteredMatches, monitor);
572             fViewer.fExpectedItemCount+= result.length;
573             if (result.length == 0) {
574                 return;
575             }
576             if (monitor.isCanceled())
577                 throw new OperationCanceledException();
578             int processed= 0;
579             int nextIndex= 1;
580             type= result[0];
581             if (!filteredMatches.isEmpty()) {
582                 fViewer.addDashLineAndUpdateLastHistoryEntry(fTicket, type);
583             }
584             while (true) {
585                 long startTime= System.currentTimeMillis();
586                 elements.clear();
587                 imageDescriptors.clear();
588                 labels.clear();
589                 int delta = Math.min(nextIndex == 1 ? fViewer.getNumberOfVisibleItems() : 10, result.length - processed);
590                 if (delta == 0)
591                     break;
592                 processed= processed + delta;
593                 while(delta > 0) {
594                     next= (nextIndex == result.length) ? null : result[nextIndex];
595                     elements.add(type);
596                     labels.add(fLabelProvider.getText(last, type, next));
597                     imageDescriptors.add(fLabelProvider.getImageDescriptor(type));
598                     last= type;
599                     type= next;
600                     nextIndex++;
601                     delta--;
602                 }
603                 fViewer.addAll(fTicket, elements, imageDescriptors, labels);
604                 long sleep= 100 - (System.currentTimeMillis() - startTime);
605                 if (false)
606                     System.out.println("Sleeping for: " + sleep); //$NON-NLS-1$
607

608                 if (sleep > 0)
609                     Thread.sleep(sleep);
610                 
611                 if (monitor.isCanceled())
612                     throw new OperationCanceledException();
613             }
614         }
615         private void internalRunVirtual(ProgressMonitor monitor) throws CoreException, InterruptedException JavaDoc {
616             if (monitor.isCanceled())
617                 throw new OperationCanceledException();
618             
619             fViewer.clear(fTicket);
620
621             TypeNameMatch[] matchingTypes= fHistory.getFilteredTypeInfos(fFilter);
622             fViewer.setHistoryResult(fTicket, matchingTypes);
623             if ((fMode & INDEX) == 0)
624                 return;
625                 
626             Set JavaDoc filteredMatches= new HashSet JavaDoc(matchingTypes.length * 2);
627             for (int i= 0; i < matchingTypes.length; i++) {
628                 filteredMatches.add(matchingTypes[i]);
629             }
630             
631             TypeNameMatch[] result= getSearchResult(filteredMatches, monitor);
632             if (monitor.isCanceled())
633                 throw new OperationCanceledException();
634             
635             fViewer.setSearchResult(fTicket, result);
636         }
637         private IStatus canceled(Exception JavaDoc e, boolean removePendingItems) {
638             fViewer.searchJobCanceled(fTicket, removePendingItems);
639             return new Status(IStatus.CANCEL, JavaPlugin.getPluginId(), IStatus.CANCEL, JavaUIMessages.TypeInfoViewer_job_cancel, e);
640         }
641         private IStatus ok() {
642             return new Status(IStatus.OK, JavaPlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
643
}
644     }
645     
646     private static class SearchEngineJob extends AbstractSearchJob {
647         private IJavaSearchScope fScope;
648         private int fElementKind;
649         private SearchRequestor fReqestor;
650         
651         public SearchEngineJob(int ticket, TypeInfoViewer viewer, TypeInfoFilter filter, OpenTypeHistory history, int numberOfVisibleItems, int mode,
652                 IJavaSearchScope scope, int elementKind) {
653             super(ticket, viewer, filter, history, numberOfVisibleItems, mode);
654             fScope= scope;
655             fElementKind= elementKind;
656             fReqestor= new SearchRequestor(filter);
657         }
658         public void stop() {
659             fReqestor.cancel();
660             super.stop();
661         }
662         protected TypeNameMatch[] getSearchResult(Set JavaDoc matchIdsInHistory, ProgressMonitor monitor) throws CoreException {
663             long start= System.currentTimeMillis();
664             fReqestor.setHistory(matchIdsInHistory);
665             // consider primary working copies during searching
666
SearchEngine engine= new SearchEngine((WorkingCopyOwner)null);
667             String JavaDoc packPattern= fFilter.getPackagePattern();
668             monitor.setTaskName(JavaUIMessages.TypeInfoViewer_searchJob_taskName);
669             engine.searchAllTypeNames(
670                 packPattern == null ? null : packPattern.toCharArray(),
671                 fFilter.getPackageFlags(),
672                 fFilter.getNamePattern().toCharArray(),
673                 fFilter.getSearchFlags(),
674                 fElementKind,
675                 fScope,
676                 fReqestor,
677                 IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
678                 monitor);
679             if (DEBUG)
680                 System.out.println("Time needed until search has finished: " + (System.currentTimeMillis() - start)); //$NON-NLS-1$
681
TypeNameMatch[] result= fReqestor.getResult();
682             Arrays.sort(result, new TypeInfoComparator(fLabelProvider, fFilter));
683             if (DEBUG)
684                 System.out.println("Time needed until sort has finished: " + (System.currentTimeMillis() - start)); //$NON-NLS-1$
685
fViewer.rememberResult(fTicket, result);
686             return result;
687         }
688     }
689     
690     private static class CachedResultJob extends AbstractSearchJob {
691         private TypeNameMatch[] fLastResult;
692         public CachedResultJob(int ticket, TypeNameMatch[] lastResult, TypeInfoViewer viewer, TypeInfoFilter filter, OpenTypeHistory history, int numberOfVisibleItems, int mode) {
693             super(ticket, viewer, filter, history, numberOfVisibleItems, mode);
694             fLastResult= lastResult;
695         }
696         protected TypeNameMatch[] getSearchResult(Set JavaDoc filteredHistory, ProgressMonitor monitor) throws CoreException {
697             List JavaDoc result= new ArrayList JavaDoc(2048);
698             for (int i= 0; i < fLastResult.length; i++) {
699                 TypeNameMatch type= fLastResult[i];
700                 if (filteredHistory.contains(type))
701                     continue;
702                 if (fFilter.matchesCachedResult(type))
703                     result.add(type);
704             }
705             // we have to sort if the filter is a camel case filter.
706
TypeNameMatch[] types= (TypeNameMatch[])result.toArray(new TypeNameMatch[result.size()]);
707             if (fFilter.isCamelCasePattern()) {
708                 Arrays.sort(types, new TypeInfoComparator(fLabelProvider, fFilter));
709             }
710             return types;
711         }
712     }
713     
714     private static class SyncJob extends AbstractJob {
715         public SyncJob(TypeInfoViewer viewer) {
716             super(JavaUIMessages.TypeInfoViewer_syncJob_label, viewer);
717         }
718         public void stop() {
719             cancel();
720         }
721         protected IStatus doRun(ProgressMonitor monitor) {
722             try {
723                 monitor.setTaskName(JavaUIMessages.TypeInfoViewer_syncJob_taskName);
724                 new SearchEngine().searchAllTypeNames(
725                     null,
726                     0,
727                     // make sure we search a concrete name. This is faster according to Kent
728
"_______________".toCharArray(), //$NON-NLS-1$
729
SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE,
730                     IJavaSearchConstants.ENUM,
731                     SearchEngine.createWorkspaceScope(),
732                     new TypeNameRequestor() {},
733                     IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
734                     monitor);
735             } catch (JavaModelException e) {
736                 JavaPlugin.log(e);
737                 return new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.ERROR, JavaUIMessages.TypeInfoViewer_job_error, e);
738             } catch (OperationCanceledException e) {
739                 return new Status(IStatus.CANCEL, JavaPlugin.getPluginId(), IStatus.CANCEL, JavaUIMessages.TypeInfoViewer_job_cancel, e);
740             } finally {
741                 fViewer.syncJobDone();
742             }
743             return new Status(IStatus.OK, JavaPlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
744
}
745     }
746     
747     private static class DashLine {
748         private int fSeparatorWidth;
749         private String JavaDoc fMessage;
750         private int fMessageLength;
751         public String JavaDoc getText(int width) {
752             StringBuffer JavaDoc dashes= new StringBuffer JavaDoc();
753             int chars= (((width - fMessageLength) / fSeparatorWidth) / 2) -2;
754             for (int i= 0; i < chars; i++) {
755                 dashes.append(SEPARATOR);
756             }
757             StringBuffer JavaDoc result= new StringBuffer JavaDoc();
758             result.append(dashes);
759             result.append(fMessage);
760             result.append(dashes);
761             return result.toString();
762         }
763         public void initialize(GC gc) {
764             fSeparatorWidth= gc.getAdvanceWidth(SEPARATOR);
765             fMessage= " " + JavaUIMessages.TypeInfoViewer_separator_message + " "; //$NON-NLS-1$ //$NON-NLS-2$
766
fMessageLength= gc.textExtent(fMessage).x;
767         }
768     }
769     
770     private static class ImageManager {
771         private Map JavaDoc fImages= new HashMap JavaDoc(20);
772         
773         public Image get(ImageDescriptor descriptor) {
774             if (descriptor == null)
775                 descriptor= ImageDescriptor.getMissingImageDescriptor();
776             
777             Image result= (Image)fImages.get(descriptor);
778             if (result != null)
779                 return result;
780             result= descriptor.createImage();
781             if (result != null)
782                 fImages.put(descriptor, result);
783             return result;
784         }
785         
786         public void dispose() {
787             for (Iterator JavaDoc iter= fImages.values().iterator(); iter.hasNext(); ) {
788                 Image image= (Image)iter.next();
789                 image.dispose();
790             }
791             fImages.clear();
792         }
793     }
794     
795     private Display fDisplay;
796     
797     private String JavaDoc fProgressMessage;
798     private Label fProgressLabel;
799     private int fProgressCounter;
800     private ProgressUpdateJob fProgressUpdateJob;
801     
802     private OpenTypeHistory fHistory;
803
804     /* non virtual table */
805     private int fNextElement;
806     private List JavaDoc fItems;
807     
808     /* virtual table */
809     private TypeNameMatch[] fHistoryMatches;
810     private TypeNameMatch[] fSearchMatches;
811     
812     private int fNumberOfVisibleItems;
813     private int fExpectedItemCount;
814     private Color fDashLineColor;
815     private int fScrollbarWidth;
816     private int fTableWidthDelta;
817     private int fDashLineIndex= -1;
818     private Image fSeparatorIcon;
819     private DashLine fDashLine= new DashLine();
820     
821     private boolean fFullyQualifySelection;
822     /* remembers the last selection to restore unqualified labels */
823     private TableItem[] fLastSelection;
824     private String JavaDoc[] fLastLabels;
825     
826     private TypeInfoLabelProvider fLabelProvider;
827     private ImageManager fImageManager;
828     
829     private Table fTable;
830     
831     private SyncJob fSyncJob;
832     
833     private TypeInfoFilter fTypeInfoFilter;
834     private ITypeInfoFilterExtension fFilterExtension;
835     private TypeNameMatch[] fLastCompletedResult;
836     private TypeInfoFilter fLastCompletedFilter;
837     
838     private int fSearchJobTicket;
839     protected int fElementKind;
840     protected IJavaSearchScope fSearchScope;
841     
842     private AbstractSearchJob fSearchJob;
843
844     private static final int HISTORY= 1;
845     private static final int INDEX= 2;
846     private static final int FULL= HISTORY | INDEX;
847     
848     private static final char SEPARATOR= '-';
849     
850     private static final boolean DEBUG= false;
851     private static final boolean VIRTUAL= false;
852     
853     private static final TypeNameMatch[] EMTPY_TYPE_INFO_ARRAY= new TypeNameMatch[0];
854     // only needed when in virtual table mode
855

856     private static final TypeNameMatch DASH_LINE= SearchEngine.createTypeNameMatch(null, 0);
857         
858
859     public TypeInfoViewer(Composite parent, int flags, Label progressLabel,
860             IJavaSearchScope scope, int elementKind, String JavaDoc initialFilter,
861             ITypeInfoFilterExtension filterExtension, ITypeInfoImageProvider imageExtension) {
862         Assert.isNotNull(scope);
863         fDisplay= parent.getDisplay();
864         fProgressLabel= progressLabel;
865         fSearchScope= scope;
866         fElementKind= elementKind;
867         fFilterExtension= filterExtension;
868         fFullyQualifySelection= (flags & SWT.MULTI) != 0;
869         fTable= new Table(parent, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER | SWT.FLAT | flags | (VIRTUAL ? SWT.VIRTUAL : SWT.NONE));
870         fTable.setFont(parent.getFont());
871         fLabelProvider= new TypeInfoLabelProvider(imageExtension);
872         fItems= new ArrayList JavaDoc(500);
873         fTable.setHeaderVisible(false);
874         addPopupMenu();
875         fTable.addControlListener(new ControlAdapter() {
876             public void controlResized(ControlEvent event) {
877                 int itemHeight= fTable.getItemHeight();
878                 Rectangle clientArea= fTable.getClientArea();
879                 fNumberOfVisibleItems= (clientArea.height / itemHeight) + 1;
880             }
881         });
882         fTable.addKeyListener(new KeyAdapter() {
883             public void keyPressed(KeyEvent e) {
884                 if (e.keyCode == SWT.DEL) {
885                     deleteHistoryEntry();
886                 } else if (e.keyCode == SWT.ARROW_DOWN) {
887                     int index= fTable.getSelectionIndex();
888                     if (index == fDashLineIndex - 1) {
889                         e.doit= false;
890                         setTableSelection(index + 2);
891                     }
892                 } else if (e.keyCode == SWT.ARROW_UP) {
893                     int index= fTable.getSelectionIndex();
894                     if (fDashLineIndex != -1 && index == fDashLineIndex + 1) {
895                         e.doit= false;
896                         setTableSelection(index - 2);
897                     }
898                 }
899             }
900         });
901         fTable.addSelectionListener(new SelectionAdapter() {
902             public void widgetSelected(SelectionEvent e) {
903                 if (fLastSelection != null) {
904                     for (int i= 0; i < fLastSelection.length; i++) {
905                         TableItem item= fLastSelection[i];
906                         // could be disposed by deleting element from
907
// type info history
908
if (!item.isDisposed())
909                             item.setText(fLastLabels[i]);
910                     }
911                 }
912                 TableItem[] items= fTable.getSelection();
913                 fLastSelection= new TableItem[items.length];
914                 fLastLabels= new String JavaDoc[items.length];
915                 for (int i= 0; i < items.length; i++) {
916                     TableItem item= items[i];
917                     fLastSelection[i]= item;
918                     fLastLabels[i]= item.getText();
919                     Object JavaDoc data= item.getData();
920                     if (data instanceof TypeNameMatch) {
921                         String JavaDoc qualifiedText= getQualifiedText((TypeNameMatch)data);
922                         if (qualifiedText.length() > fLastLabels[i].length())
923                             item.setText(qualifiedText);
924                     }
925                 }
926             }
927         });
928         fTable.addDisposeListener(new DisposeListener() {
929             public void widgetDisposed(DisposeEvent e) {
930                 stop(true, true);
931                 fDashLineColor.dispose();
932                 fSeparatorIcon.dispose();
933                 fImageManager.dispose();
934                 if (fProgressUpdateJob != null) {
935                     fProgressUpdateJob.stop();
936                     fProgressUpdateJob= null;
937                 }
938             }
939         });
940         if (VIRTUAL) {
941             fHistoryMatches= EMTPY_TYPE_INFO_ARRAY;
942             fSearchMatches= EMTPY_TYPE_INFO_ARRAY;
943             fTable.addListener(SWT.SetData, new Listener() {
944                 public void handleEvent(Event event) {
945                     TableItem item= (TableItem)event.item;
946                     setData(item);
947                 }
948             });
949         }
950         
951         fDashLineColor= computeDashLineColor();
952         fScrollbarWidth= computeScrollBarWidth();
953         fTableWidthDelta= fTable.computeTrim(0, 0, 0, 0).width - fScrollbarWidth;
954         fSeparatorIcon= JavaPluginImages.DESC_OBJS_TYPE_SEPARATOR.createImage(fTable.getDisplay());
955         // Use a new image manager since an extension can provide its own
956
// image descriptors. To avoid thread problems with SWT the registry
957
// must be created in the UI thread.
958
fImageManager= new ImageManager();
959         
960         fHistory= OpenTypeHistory.getInstance();
961         if (initialFilter != null && initialFilter.length() > 0)
962             fTypeInfoFilter= createTypeInfoFilter(initialFilter);
963         GC gc= null;
964         try {
965             gc= new GC(fTable);
966             gc.setFont(fTable.getFont());
967             fDashLine.initialize(gc);
968         } finally {
969             gc.dispose();
970         }
971         // If we do have a type info filter then we are
972
// scheduling a search job in startup. So no
973
// need to sync the search indices.
974
if (fTypeInfoFilter == null) {
975             scheduleSyncJob();
976         }
977     }
978     
979     /* package */ void startup() {
980         if (fTypeInfoFilter == null) {
981             reset();
982         } else {
983             scheduleSearchJob(FULL);
984         }
985     }
986
987     public Table getTable() {
988         return fTable;
989     }
990     
991     /* package */ TypeInfoLabelProvider getLabelProvider() {
992         return fLabelProvider;
993     }
994     
995     private int getNumberOfVisibleItems() {
996         return fNumberOfVisibleItems;
997     }
998     
999     public void setFocus() {
1000        fTable.setFocus();
1001    }
1002    
1003    
1004    public void setQualificationStyle(boolean value) {
1005        if (fFullyQualifySelection == value)
1006            return;
1007        fFullyQualifySelection= value;
1008        if (fLastSelection != null) {
1009            for (int i= 0; i < fLastSelection.length; i++) {
1010                TableItem item= fLastSelection[i];
1011                Object JavaDoc data= item.getData();
1012                if (data instanceof TypeNameMatch) {
1013                    item.setText(getQualifiedText((TypeNameMatch)data));
1014                }
1015            }
1016        }
1017    }
1018    
1019    public TypeNameMatch[] getSelection() {
1020        TableItem[] items= fTable.getSelection();
1021        List JavaDoc result= new ArrayList JavaDoc(items.length);
1022        for (int i= 0; i < items.length; i++) {
1023            Object JavaDoc data= items[i].getData();
1024            if (data instanceof TypeNameMatch) {
1025                result.add(data);
1026            }
1027        }
1028        return (TypeNameMatch[])result.toArray(new TypeNameMatch[result.size()]);
1029    }
1030    
1031    public void stop() {
1032        stop(true, false);
1033    }
1034    
1035    public void stop(boolean stopSyncJob, boolean dispose) {
1036        if (fSyncJob != null && stopSyncJob) {
1037            fSyncJob.stop();
1038            fSyncJob= null;
1039        }
1040        if (fSearchJob != null) {
1041            fSearchJob.stop();
1042            fSearchJob= null;
1043        }
1044    }
1045    
1046    public void forceSearch() {
1047        stop(false, false);
1048        if (fTypeInfoFilter == null) {
1049            reset();
1050        } else {
1051            // clear last results
1052
fLastCompletedFilter= null;
1053            fLastCompletedResult= null;
1054            scheduleSearchJob(isSyncJobRunning() ? HISTORY : FULL);
1055        }
1056    }
1057    
1058    public void setSearchPattern(String JavaDoc text) {
1059        stop(false, false);
1060        if (text.length() == 0 || "*".equals(text)) { //$NON-NLS-1$
1061
fTypeInfoFilter= null;
1062            reset();
1063        } else {
1064            fTypeInfoFilter= createTypeInfoFilter(text);
1065            scheduleSearchJob(isSyncJobRunning() ? HISTORY : FULL);
1066        }
1067    }
1068    
1069    public void setSearchScope(IJavaSearchScope scope, boolean refresh) {
1070        fSearchScope= scope;
1071        if (!refresh)
1072            return;
1073        stop(false, false);
1074        fLastCompletedFilter= null;
1075        fLastCompletedResult= null;
1076        if (fTypeInfoFilter == null) {
1077            reset();
1078        } else {
1079            scheduleSearchJob(isSyncJobRunning() ? HISTORY : FULL);
1080        }
1081    }
1082
1083    public void setFullyQualifyDuplicates(boolean value, boolean refresh) {
1084        fLabelProvider.setFullyQualifyDuplicates(value);
1085        if (!refresh)
1086            return;
1087        stop(false, false);
1088        if (fTypeInfoFilter == null) {
1089            reset();
1090        } else {
1091            scheduleSearchJob(isSyncJobRunning() ? HISTORY : FULL);
1092        }
1093    }
1094    
1095    public void reset() {
1096        fLastSelection= null;
1097        fLastLabels= null;
1098        fExpectedItemCount= 0;
1099        fDashLineIndex= -1;
1100        TypeInfoFilter filter= (fTypeInfoFilter != null)
1101            ? fTypeInfoFilter
1102            : new TypeInfoFilter("*", fSearchScope, fElementKind, fFilterExtension); //$NON-NLS-1$
1103
if (VIRTUAL) {
1104            fHistoryMatches= fHistory.getFilteredTypeInfos(filter);
1105            fExpectedItemCount= fHistoryMatches.length;
1106            fTable.setItemCount(fHistoryMatches.length);
1107            // bug under windows.
1108
if (fHistoryMatches.length == 0) {
1109                fTable.redraw();
1110            }
1111            fTable.clear(0, fHistoryMatches.length - 1);
1112        } else {
1113            fNextElement= 0;
1114            TypeNameMatch[] historyItems= fHistory.getFilteredTypeInfos(filter);
1115            if (historyItems.length == 0) {
1116                shortenTable();
1117                return;
1118            }
1119            fExpectedItemCount= historyItems.length;
1120            int lastIndex= historyItems.length - 1;
1121            TypeNameMatch last= null;
1122            TypeNameMatch type= historyItems[0];
1123            for (int i= 0; i < historyItems.length; i++) {
1124                TypeNameMatch next= i == lastIndex ? null : historyItems[i + 1];
1125                addSingleElement(type,
1126                    fLabelProvider.getImageDescriptor(type),
1127                    fLabelProvider.getText(last, type, next));
1128                last= type;
1129                type= next;
1130            }
1131            shortenTable();
1132        }
1133    }
1134    
1135    protected TypeInfoFilter createTypeInfoFilter(String JavaDoc text) {
1136        if ("**".equals(text)) //$NON-NLS-1$
1137
text= "*"; //$NON-NLS-1$
1138
return new TypeInfoFilter(text, fSearchScope, fElementKind, fFilterExtension);
1139    }
1140    
1141    private void addPopupMenu() {
1142        Menu menu= new Menu(fTable.getShell(), SWT.POP_UP);
1143        fTable.setMenu(menu);
1144        final MenuItem remove= new MenuItem(menu, SWT.NONE);
1145        remove.setText(JavaUIMessages.TypeInfoViewer_remove_from_history);
1146        menu.addMenuListener(new MenuAdapter() {
1147            public void menuShown(MenuEvent e) {
1148                TableItem[] selection= fTable.getSelection();
1149                remove.setEnabled(canEnable(selection));
1150            }
1151        });
1152        remove.addSelectionListener(new SelectionAdapter() {
1153            public void widgetSelected(SelectionEvent e) {
1154                deleteHistoryEntry();
1155            }
1156        });
1157    }
1158    
1159    private boolean canEnable(TableItem[] selection) {
1160        if (selection.length == 0)
1161            return false;
1162        for (int i= 0; i < selection.length; i++) {
1163            TableItem item= selection[i];
1164            Object JavaDoc data= item.getData();
1165            if (!(data instanceof TypeNameMatch))
1166                return false;
1167            if (!(fHistory.contains((TypeNameMatch)data)))
1168                return false;
1169        }
1170        return true;
1171    }
1172    
1173    //---- History management -------------------------------------------------------
1174

1175    private void deleteHistoryEntry() {
1176        int index= fTable.getSelectionIndex();
1177        if (index == -1)
1178            return;
1179        TableItem item= fTable.getItem(index);
1180        Object JavaDoc element= item.getData();
1181        if (!(element instanceof TypeNameMatch))
1182            return;
1183        if (fHistory.remove(element) != null) {
1184            item.dispose();
1185            fItems.remove(index);
1186            int count= fTable.getItemCount();
1187            if (count > 0) {
1188                item= fTable.getItem(0);
1189                if (item.getData() instanceof DashLine) {
1190                    item.dispose();
1191                    fItems.remove(0);
1192                    fDashLineIndex= -1;
1193                    if (count > 1) {
1194                        setTableSelection(0);
1195                    }
1196                } else {
1197                    if (index >= count) {
1198                        index= count - 1;
1199                    }
1200                    setTableSelection(index);
1201                }
1202            } else {
1203                // send dummy selection
1204
fTable.notifyListeners(SWT.Selection, new Event());
1205            }
1206        }
1207    }
1208    
1209    //-- Search result updating ----------------------------------------------------
1210

1211    private void clear(int ticket) {
1212        syncExec(ticket, new Runnable JavaDoc() {
1213            public void run() {
1214                fNextElement= 0;
1215                fDashLineIndex= -1;
1216                fLastSelection= null;
1217                fLastLabels= null;
1218                fExpectedItemCount= 0;
1219            }
1220        });
1221    }
1222    
1223    private void rememberResult(int ticket, final TypeNameMatch[] result) {
1224        syncExec(ticket, new Runnable JavaDoc() {
1225            public void run() {
1226                if (fLastCompletedResult == null) {
1227                    fLastCompletedFilter= fTypeInfoFilter;
1228                    fLastCompletedResult= result;
1229                }
1230            }
1231        });
1232    }
1233
1234    private void addHistory(int ticket, final List JavaDoc elements, final List JavaDoc imageDescriptors, final List JavaDoc labels) {
1235        addAll(ticket, elements, imageDescriptors, labels);
1236    }
1237    
1238    private void addAll(int ticket, final List JavaDoc elements, final List JavaDoc imageDescriptors, final List JavaDoc labels) {
1239        syncExec(ticket, new Runnable JavaDoc() {
1240            public void run() {
1241                int size= elements.size();
1242                for(int i= 0; i < size; i++) {
1243                    addSingleElement(elements.get(i),
1244                        (ImageDescriptor)imageDescriptors.get(i),
1245                        (String JavaDoc)labels.get(i));
1246                }
1247            }
1248        });
1249    }
1250    
1251    private void addDashLineAndUpdateLastHistoryEntry(int ticket, final TypeNameMatch next) {
1252        syncExec(ticket, new Runnable JavaDoc() {
1253            public void run() {
1254                if (fNextElement > 0) {
1255                    TableItem item= fTable.getItem(fNextElement - 1);
1256                    String JavaDoc label= item.getText();
1257                    String JavaDoc newLabel= fLabelProvider.getText(null, (TypeNameMatch)item.getData(), next);
1258                    if (newLabel.length() != label.length())
1259                        item.setText(newLabel);
1260                    if (fLastSelection != null && fLastSelection.length > 0) {
1261                        TableItem last= fLastSelection[fLastSelection.length - 1];
1262                        if (last == item) {
1263                            fLastLabels[fLastLabels.length - 1]= newLabel;
1264                        }
1265                    }
1266                }
1267                fDashLineIndex= fNextElement;
1268                addDashLine();
1269            }
1270        });
1271    }
1272    
1273    private void addDashLine() {
1274        TableItem item= null;
1275        if (fItems.size() > fNextElement) {
1276            item= (TableItem)fItems.get(fNextElement);
1277        } else {
1278            item= new TableItem(fTable, SWT.NONE);
1279            fItems.add(item);
1280        }
1281        fillDashLine(item);
1282        fNextElement++;
1283    }
1284    
1285    private void addSingleElement(Object JavaDoc element, ImageDescriptor imageDescriptor, String JavaDoc label) {
1286        TableItem item= null;
1287        Object JavaDoc old= null;
1288        if (fItems.size() > fNextElement) {
1289            item= (TableItem)fItems.get(fNextElement);
1290            old= item.getData();
1291            item.setForeground(null);
1292        } else {
1293            item= new TableItem(fTable, SWT.NONE);
1294            fItems.add(item);
1295        }
1296        item.setData(element);
1297        item.setImage(fImageManager.get(imageDescriptor));
1298        if (fNextElement == 0) {
1299            if (needsSelectionChange(old, element) || fLastSelection != null) {
1300                item.setText(label);
1301                fTable.setSelection(0);
1302                fTable.notifyListeners(SWT.Selection, new Event());
1303            } else {
1304                fLastSelection= new TableItem[] { item };
1305                fLastLabels= new String JavaDoc[] { label };
1306            }
1307        } else {
1308            item.setText(label);
1309        }
1310        fNextElement++;
1311    }
1312    
1313    private boolean needsSelectionChange(Object JavaDoc oldElement, Object JavaDoc newElement) {
1314        int[] selected= fTable.getSelectionIndices();
1315        if (selected.length != 1)
1316            return true;
1317        if (selected[0] != 0)
1318            return true;
1319        if (oldElement == null)
1320            return true;
1321        return !oldElement.equals(newElement);
1322    }
1323    
1324    private void scheduleSearchJob(int mode) {
1325        fSearchJobTicket++;
1326        if (fLastCompletedFilter != null && fTypeInfoFilter.isSubFilter(fLastCompletedFilter.getText())) {
1327            fSearchJob= new CachedResultJob(fSearchJobTicket, fLastCompletedResult, this, fTypeInfoFilter,
1328                fHistory, fNumberOfVisibleItems,
1329                mode);
1330        } else {
1331            fLastCompletedFilter= null;
1332            fLastCompletedResult= null;
1333            fSearchJob= new SearchEngineJob(fSearchJobTicket, this, fTypeInfoFilter,
1334                fHistory, fNumberOfVisibleItems,
1335                mode, fSearchScope, fElementKind);
1336        }
1337        fSearchJob.schedule();
1338    }
1339    
1340    private void searchJobDone(int ticket) {
1341        syncExec(ticket, new Runnable JavaDoc() {
1342            public void run() {
1343                shortenTable();
1344                checkEmptyList();
1345                fSearchJob= null;
1346            }
1347        });
1348    }
1349    
1350    private void searchJobCanceled(int ticket, final boolean removePendingItems) {
1351        syncExec(ticket, new Runnable JavaDoc() {
1352            public void run() {
1353                if (removePendingItems) {
1354                    shortenTable();
1355                    checkEmptyList();
1356                }
1357                fSearchJob= null;
1358            }
1359        });
1360    }
1361    
1362    private synchronized void searchJobFailed(int ticket, CoreException e) {
1363        searchJobDone(ticket);
1364        JavaPlugin.log(e);
1365    }
1366    
1367    //-- virtual table support -------------------------------------------------------
1368

1369    private void setHistoryResult(int ticket, final TypeNameMatch[] types) {
1370        syncExec(ticket, new Runnable JavaDoc() {
1371            public void run() {
1372                fExpectedItemCount= types.length;
1373                int lastHistoryLength= fHistoryMatches.length;
1374                fHistoryMatches= types;
1375                int length= fHistoryMatches.length + fSearchMatches.length;
1376                int dash= (fHistoryMatches.length > 0 && fSearchMatches.length > 0) ? 1 : 0;
1377                fTable.setItemCount(length + dash);
1378                if (length == 0) {
1379                    // bug under windows.
1380
fTable.redraw();
1381                    return;
1382                }
1383                int update= Math.max(lastHistoryLength, fHistoryMatches.length);
1384                if (update > 0) {
1385                    fTable.clear(0, update + dash - 1);
1386                }
1387            }
1388        });
1389    }
1390    
1391    private void setSearchResult(int ticket, final TypeNameMatch[] types) {
1392        syncExec(ticket, new Runnable JavaDoc() {
1393            public void run() {
1394                fExpectedItemCount+= types.length;
1395                fSearchMatches= types;
1396                int length= fHistoryMatches.length + fSearchMatches.length;
1397                int dash= (fHistoryMatches.length > 0 && fSearchMatches.length > 0) ? 1 : 0;
1398                fTable.setItemCount(length + dash);
1399                if (length == 0) {
1400                    // bug under windows.
1401
fTable.redraw();
1402                    return;
1403                }
1404                if (fHistoryMatches.length == 0) {
1405                    fTable.clear(0, length + dash - 1);
1406                } else {
1407                    fTable.clear(fHistoryMatches.length - 1, length + dash - 1);
1408                }
1409            }
1410        });
1411    }
1412    
1413    private void setData(TableItem item) {
1414        int index= fTable.indexOf(item);
1415        TypeNameMatch type= getTypeInfo(index);
1416        if (type == DASH_LINE) {
1417            item.setData(fDashLine);
1418            fillDashLine(item);
1419        } else {
1420            item.setData(type);
1421            item.setImage(fImageManager.get(fLabelProvider.getImageDescriptor(type)));
1422            item.setText(fLabelProvider.getText(
1423                getTypeInfo(index - 1),
1424                type,
1425                getTypeInfo(index + 1)));
1426            item.setForeground(null);
1427        }
1428    }
1429    
1430    private TypeNameMatch getTypeInfo(int index) {
1431        if (index < 0)
1432            return null;
1433        if (index < fHistoryMatches.length) {
1434            return fHistoryMatches[index];
1435        }
1436        int dash= (fHistoryMatches.length > 0 && fSearchMatches.length > 0) ? 1 : 0;
1437        if (index == fHistoryMatches.length && dash == 1) {
1438            return DASH_LINE;
1439        }
1440        index= index - fHistoryMatches.length - dash;
1441        if (index >= fSearchMatches.length)
1442            return null;
1443        return fSearchMatches[index];
1444    }
1445    
1446    //-- Sync Job updates ------------------------------------------------------------
1447

1448    private void scheduleSyncJob() {
1449        fSyncJob= new SyncJob(this);
1450        fSyncJob.schedule();
1451    }
1452    
1453    private void syncJobDone() {
1454        syncExec(new Runnable JavaDoc() {
1455            public void run() {
1456                fSyncJob= null;
1457                if (fTypeInfoFilter != null) {
1458                    scheduleSearchJob(FULL);
1459                }
1460            }
1461        });
1462    }
1463
1464    private boolean isSyncJobRunning() {
1465        return fSyncJob != null;
1466    }
1467    
1468    //-- progress monitor updates -----------------------------------------------------
1469

1470    private void scheduleProgressUpdateJob() {
1471        syncExec(new Runnable JavaDoc() {
1472            public void run() {
1473                if (fProgressCounter == 0) {
1474                    clearProgressMessage();
1475                    fProgressUpdateJob= new ProgressUpdateJob(fDisplay, TypeInfoViewer.this);
1476                    fProgressUpdateJob.schedule(300);
1477                }
1478                fProgressCounter++;
1479            }
1480        });
1481    }
1482    
1483    private void stopProgressUpdateJob() {
1484        syncExec(new Runnable JavaDoc() {
1485            public void run() {
1486                fProgressCounter--;
1487                if (fProgressCounter == 0 && fProgressUpdateJob != null) {
1488                    fProgressUpdateJob.stop();
1489                    fProgressUpdateJob= null;
1490                    clearProgressMessage();
1491                }
1492            }
1493        });
1494    }
1495    
1496    private void setProgressMessage(String JavaDoc message) {
1497        fProgressMessage= message;
1498    }
1499    
1500    private void clearProgressMessage() {
1501        fProgressMessage= ""; //$NON-NLS-1$
1502
fProgressLabel.setText(fProgressMessage);
1503    }
1504    
1505    private void updateProgressMessage() {
1506        fProgressLabel.setText(fProgressMessage);
1507    }
1508    
1509    //-- Helper methods --------------------------------------------------------------
1510

1511    private void syncExec(final Runnable JavaDoc runnable) {
1512        if (fDisplay.isDisposed())
1513            return;
1514        fDisplay.syncExec(new Runnable JavaDoc() {
1515            public void run() {
1516                if (fTable.isDisposed())
1517                    return;
1518                runnable.run();
1519            }
1520        });
1521    }
1522    
1523    private void syncExec(final int ticket, final Runnable JavaDoc runnable) {
1524        if (fDisplay.isDisposed())
1525            return;
1526        fDisplay.syncExec(new Runnable JavaDoc() {
1527            public void run() {
1528                if (fTable.isDisposed() || ticket != fSearchJobTicket)
1529                    return;
1530                runnable.run();
1531            }
1532        });
1533    }
1534    
1535    private void fillDashLine(TableItem item) {
1536        Rectangle bounds= item.getImageBounds(0);
1537        Rectangle area= fTable.getBounds();
1538        boolean willHaveScrollBar= fExpectedItemCount + 1 > fNumberOfVisibleItems;
1539        item.setText(fDashLine.getText(area.width - bounds.x - bounds.width - fTableWidthDelta -
1540            (willHaveScrollBar ? fScrollbarWidth : 0)));
1541        item.setImage(fSeparatorIcon);
1542        item.setForeground(fDashLineColor);
1543        item.setData(fDashLine);
1544    }
1545
1546    private void shortenTable() {
1547        if (VIRTUAL)
1548            return;
1549        if (fNextElement < fItems.size()) {
1550            fTable.setRedraw(false);
1551            fTable.remove(fNextElement, fItems.size() - 1);
1552            fTable.setRedraw(true);
1553        }
1554        for (int i= fItems.size() - 1; i >= fNextElement; i--) {
1555            fItems.remove(i);
1556        }
1557    }
1558    
1559    private void checkEmptyList() {
1560        if (fTable.getItemCount() == 0) {
1561            fTable.notifyListeners(SWT.Selection, new Event());
1562        }
1563    }
1564    
1565    private void setTableSelection(int index) {
1566        fTable.setSelection(index);
1567        fTable.notifyListeners(SWT.Selection, new Event());
1568    }
1569    
1570    private Color computeDashLineColor() {
1571        Color fg= fTable.getForeground();
1572        int fGray= (int)(0.3*fg.getRed() + 0.59*fg.getGreen() + 0.11*fg.getBlue());
1573        Color bg= fTable.getBackground();
1574        int bGray= (int)(0.3*bg.getRed() + 0.59*bg.getGreen() + 0.11*bg.getBlue());
1575        int gray= (int)((fGray + bGray) * 0.66);
1576        return new Color(fDisplay, gray, gray, gray);
1577    }
1578    
1579    private int computeScrollBarWidth() {
1580        Composite t= new Composite(fTable.getShell(), SWT.V_SCROLL);
1581        int result= t.computeTrim(0, 0, 0, 0).width;
1582        t.dispose();
1583        return result;
1584    }
1585
1586    private String JavaDoc getQualifiedText(TypeNameMatch type) {
1587        return fFullyQualifySelection
1588            ? fLabelProvider.getFullyQualifiedText(type)
1589            : fLabelProvider.getQualifiedText(type);
1590    }
1591}
1592
Popular Tags