1 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.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 101 public class TypeInfoViewer { 102 103 private static class SearchRequestor extends TypeNameMatchRequestor { 104 private volatile boolean fStop; 105 106 private Set fHistory; 107 108 private TypeInfoFilter fFilter; 109 private List fResult; 110 111 public SearchRequestor(TypeInfoFilter filter) { 112 super(); 113 fResult= new ArrayList (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 history) { 123 fHistory= history; 124 } 125 126 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 { 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 left, Object 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 leftString, String 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 leftString, String 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 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 fLib2Name= new HashMap (); 226 private String [] fInstallLocations; 227 private String [] fVMNames; 228 229 private boolean fFullyQualifyDuplicates; 230 231 public TypeInfoLabelProvider(ITypeInfoImageProvider extension) { 232 fProviderExtension= extension; 233 List locations= new ArrayList (); 234 List labels= new ArrayList (); 235 IVMInstallType[] installs= JavaRuntime.getVMInstallTypes(); 236 for (int i= 0; i < installs.length; i++) { 237 processVMInstallType(installs[i], locations, labels); 238 } 239 fInstallLocations= (String [])locations.toArray(new String [locations.size()]); 240 fVMNames= (String [])labels.toArray(new String [labels.size()]); 241 242 } 243 public void setFullyQualifyDuplicates(boolean value) { 244 fFullyQualifyDuplicates= value; 245 } 246 private void processVMInstallType(IVMInstallType installType, List locations, List labels) { 247 if (installType != null) { 248 IVMInstall[] installs= installType.getVMInstalls(); 249 boolean isMac= Platform.OS_MACOSX.equals(Platform.getOS()); 250 final String HOME_SUFFIX= "/Home"; for (int i= 0; i < installs.length; i++) { 252 String label= getFormattedLabel(installs[i].getName()); 253 LibraryLocation[] libLocations= installs[i].getLibraryLocations(); 254 if (libLocations != null) { 255 processLibraryLocation(libLocations, label); 256 } else { 257 String filePath= installs[i].getInstallLocation().getAbsolutePath(); 258 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 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 getFormattedLabel(String name) { 274 return Messages.format(JavaUIMessages.TypeInfoViewer_library_name_format, name); 275 } 276 public String getText(Object element) { 277 return ((TypeNameMatch)element).getSimpleTypeName(); 278 } 279 public String getQualifiedText(TypeNameMatch type) { 280 StringBuffer result= new StringBuffer (); 281 result.append(type.getSimpleTypeName()); 282 String 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 getFullyQualifiedText(TypeNameMatch type) { 292 StringBuffer result= new StringBuffer (); 293 result.append(type.getSimpleTypeName()); 294 String 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 getText(TypeNameMatch last, TypeNameMatch current, TypeNameMatch next) { 304 StringBuffer result= new StringBuffer (); 305 int qualifications= 0; 306 String currentTN= current.getSimpleTypeName(); 307 result.append(currentTN); 308 String currentTCN= getTypeContainerName(current); 309 if (last != null) { 310 String lastTN= last.getSimpleTypeName(); 311 String 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 nextTN= next.getSimpleTypeName(); 326 String 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 getQualificationText(TypeNameMatch type) { 350 StringBuffer result= new StringBuffer (); 351 String 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 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 getTypeContainerName(TypeNameMatch info) { 377 String result= info.getTypeContainerName(); 378 if (result.length() > 0) 379 return result; 380 return JavaUIMessages.TypeInfoViewer_default_package; 381 } 382 383 private String getContainerName(TypeNameMatch type) { 384 IPackageFragmentRoot root= type.getPackageFragmentRoot(); 385 if (root.isExternal()) { 386 String 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 lib= (String )fLib2Name.get(name); 393 if (lib != null) 394 return lib; 395 } 396 StringBuffer buf= new StringBuffer (); 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); fViewer.updateProgressMessage(); 417 if (!stopped()) 418 schedule(300); 419 return new Status(IStatus.OK, JavaPlugin.getPluginId(), IStatus.OK, "", null); } 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 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 name) { 438 super.setTaskName(name); 439 fName= name; 440 } 441 public void beginTask(String 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(""); super.done(); 455 } 456 public void internalWorked(double work) { 457 fWorked= fWorked + work; 458 fViewer.setProgressMessage(getMessage()); 459 } 460 private String getMessage() { 461 if (fDone) { 462 return ""; } else if (fTotalWork == 0) { 464 return fName; 465 } else { 466 return Messages.format( 467 JavaUIMessages.TypeInfoViewer_progress_label, 468 new Object [] { fName, new Integer ((int)((fWorked * 100) / fTotalWork)) }); 469 } 470 } 471 } 472 473 private static abstract class AbstractJob extends Job { 474 protected TypeInfoViewer fViewer; 475 protected AbstractJob(String 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 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 matchIdsInHistory, ProgressMonitor monitor) throws CoreException; 532 533 private void internalRun(ProgressMonitor monitor) throws CoreException, InterruptedException { 534 if (monitor.isCanceled()) 535 throw new OperationCanceledException(); 536 537 fViewer.clear(fTicket); 538 539 TypeNameMatch last= null; 541 TypeNameMatch type= null; 542 TypeNameMatch next= null; 543 List elements= new ArrayList (); 544 List imageDescriptors= new ArrayList (); 545 List labels= new ArrayList (); 546 Set filteredMatches= new HashSet (); 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); 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 { 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 filteredMatches= new HashSet (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 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); } 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 matchIdsInHistory, ProgressMonitor monitor) throws CoreException { 663 long start= System.currentTimeMillis(); 664 fReqestor.setHistory(matchIdsInHistory); 665 SearchEngine engine= new SearchEngine((WorkingCopyOwner)null); 667 String 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)); 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)); 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 filteredHistory, ProgressMonitor monitor) throws CoreException { 697 List result= new ArrayList (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 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 "_______________".toCharArray(), 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); } 745 } 746 747 private static class DashLine { 748 private int fSeparatorWidth; 749 private String fMessage; 750 private int fMessageLength; 751 public String getText(int width) { 752 StringBuffer dashes= new StringBuffer (); 753 int chars= (((width - fMessageLength) / fSeparatorWidth) / 2) -2; 754 for (int i= 0; i < chars; i++) { 755 dashes.append(SEPARATOR); 756 } 757 StringBuffer result= new StringBuffer (); 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 + " "; fMessageLength= gc.textExtent(fMessage).x; 767 } 768 } 769 770 private static class ImageManager { 771 private Map fImages= new HashMap (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 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 fProgressMessage; 798 private Label fProgressLabel; 799 private int fProgressCounter; 800 private ProgressUpdateJob fProgressUpdateJob; 801 802 private OpenTypeHistory fHistory; 803 804 805 private int fNextElement; 806 private List fItems; 807 808 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 823 private TableItem[] fLastSelection; 824 private String [] 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 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 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 (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 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 [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 data= item.getData(); 920 if (data instanceof TypeNameMatch) { 921 String 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 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 (fTypeInfoFilter == null) { 975 scheduleSyncJob(); 976 } 977 } 978 979 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 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 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 result= new ArrayList (items.length); 1022 for (int i= 0; i < items.length; i++) { 1023 Object 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 fLastCompletedFilter= null; 1053 fLastCompletedResult= null; 1054 scheduleSearchJob(isSyncJobRunning() ? HISTORY : FULL); 1055 } 1056 } 1057 1058 public void setSearchPattern(String text) { 1059 stop(false, false); 1060 if (text.length() == 0 || "*".equals(text)) { 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); if (VIRTUAL) { 1104 fHistoryMatches= fHistory.getFilteredTypeInfos(filter); 1105 fExpectedItemCount= fHistoryMatches.length; 1106 fTable.setItemCount(fHistoryMatches.length); 1107 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 text) { 1136 if ("**".equals(text)) text= "*"; 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 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 1175 private void deleteHistoryEntry() { 1176 int index= fTable.getSelectionIndex(); 1177 if (index == -1) 1178 return; 1179 TableItem item= fTable.getItem(index); 1180 Object 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 fTable.notifyListeners(SWT.Selection, new Event()); 1205 } 1206 } 1207 } 1208 1209 1211 private void clear(int ticket) { 1212 syncExec(ticket, new Runnable () { 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 () { 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 elements, final List imageDescriptors, final List labels) { 1235 addAll(ticket, elements, imageDescriptors, labels); 1236 } 1237 1238 private void addAll(int ticket, final List elements, final List imageDescriptors, final List labels) { 1239 syncExec(ticket, new Runnable () { 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 )labels.get(i)); 1246 } 1247 } 1248 }); 1249 } 1250 1251 private void addDashLineAndUpdateLastHistoryEntry(int ticket, final TypeNameMatch next) { 1252 syncExec(ticket, new Runnable () { 1253 public void run() { 1254 if (fNextElement > 0) { 1255 TableItem item= fTable.getItem(fNextElement - 1); 1256 String label= item.getText(); 1257 String 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 element, ImageDescriptor imageDescriptor, String label) { 1286 TableItem item= null; 1287 Object 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 [] { label }; 1306 } 1307 } else { 1308 item.setText(label); 1309 } 1310 fNextElement++; 1311 } 1312 1313 private boolean needsSelectionChange(Object oldElement, Object 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 () { 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 () { 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 1369 private void setHistoryResult(int ticket, final TypeNameMatch[] types) { 1370 syncExec(ticket, new Runnable () { 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 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 () { 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 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 1448 private void scheduleSyncJob() { 1449 fSyncJob= new SyncJob(this); 1450 fSyncJob.schedule(); 1451 } 1452 1453 private void syncJobDone() { 1454 syncExec(new Runnable () { 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 1470 private void scheduleProgressUpdateJob() { 1471 syncExec(new Runnable () { 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 () { 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 message) { 1497 fProgressMessage= message; 1498 } 1499 1500 private void clearProgressMessage() { 1501 fProgressMessage= ""; fProgressLabel.setText(fProgressMessage); 1503 } 1504 1505 private void updateProgressMessage() { 1506 fProgressLabel.setText(fProgressMessage); 1507 } 1508 1509 1511 private void syncExec(final Runnable runnable) { 1512 if (fDisplay.isDisposed()) 1513 return; 1514 fDisplay.syncExec(new Runnable () { 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 runnable) { 1524 if (fDisplay.isDisposed()) 1525 return; 1526 fDisplay.syncExec(new Runnable () { 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 getQualifiedText(TypeNameMatch type) { 1587 return fFullyQualifySelection 1588 ? fLabelProvider.getFullyQualifiedText(type) 1589 : fLabelProvider.getQualifiedText(type); 1590 } 1591} 1592 | Popular Tags |