1 13 package org.eclipse.ui.dialogs; 14 15 import com.ibm.icu.text.Collator; 16 import java.util.ArrayList ; 17 import java.util.Arrays ; 18 import java.util.Collections ; 19 import java.util.Comparator ; 20 21 import org.eclipse.core.resources.IContainer; 22 import org.eclipse.core.resources.IResource; 23 import org.eclipse.core.resources.IResourceProxy; 24 import org.eclipse.core.resources.IResourceProxyVisitor; 25 import org.eclipse.core.runtime.CoreException; 26 import org.eclipse.jface.dialogs.IDialogConstants; 27 import org.eclipse.jface.dialogs.IDialogSettings; 28 import org.eclipse.swt.SWT; 29 import org.eclipse.swt.custom.BusyIndicator; 30 import org.eclipse.swt.events.KeyAdapter; 31 import org.eclipse.swt.events.KeyEvent; 32 import org.eclipse.swt.events.ModifyEvent; 33 import org.eclipse.swt.events.ModifyListener; 34 import org.eclipse.swt.events.SelectionAdapter; 35 import org.eclipse.swt.events.SelectionEvent; 36 import org.eclipse.swt.graphics.Image; 37 import org.eclipse.swt.layout.GridData; 38 import org.eclipse.swt.widgets.Button; 39 import org.eclipse.swt.widgets.Composite; 40 import org.eclipse.swt.widgets.Control; 41 import org.eclipse.swt.widgets.Display; 42 import org.eclipse.swt.widgets.Label; 43 import org.eclipse.swt.widgets.Shell; 44 import org.eclipse.swt.widgets.Table; 45 import org.eclipse.swt.widgets.TableItem; 46 import org.eclipse.swt.widgets.Text; 47 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; 48 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; 49 import org.eclipse.ui.internal.ide.StringMatcher; 50 import org.eclipse.ui.model.WorkbenchLabelProvider; 51 52 59 public class ResourceListSelectionDialog extends SelectionDialog { 60 61 private static final String DIALOG_SETTINGS_SECTION = "ResourceListSelectionDialogSettings"; 63 Text pattern; 64 65 Table resourceNames; 66 67 Table folderNames; 68 69 String patternString; 70 71 IContainer container; 72 73 int typeMask; 74 75 private static Collator collator = Collator.getInstance(); 76 77 boolean gatherResourcesDynamically = true; 78 79 StringMatcher stringMatcher; 80 81 UpdateFilterThread updateFilterThread; 82 83 UpdateGatherThread updateGatherThread; 84 85 ResourceDescriptor[] descriptors; 86 87 int descriptorsSize; 88 89 WorkbenchLabelProvider labelProvider = new WorkbenchLabelProvider(); 90 91 boolean okEnabled = false; 92 93 private boolean showDerived = false; 94 95 private Button showDerivedButton; 96 97 private boolean allowUserToToggleDerived; 98 99 static class ResourceDescriptor implements Comparable { 100 String label; 101 102 ArrayList resources = new ArrayList (); 103 104 boolean resourcesSorted = true; 105 106 public int compareTo(Object o) { 107 return collator.compare(label, ((ResourceDescriptor) o).label); 108 } 109 } 110 111 class UpdateFilterThread extends Thread { 112 boolean stop = false; 113 114 int firstMatch = 0; 115 116 int lastMatch = descriptorsSize - 1; 117 118 public void run() { 119 Display display = resourceNames.getDisplay(); 120 final int itemIndex[] = { 0 }; 121 final int itemCount[] = { 0 }; 122 final boolean[] disposed = { false }; 125 display.syncExec(new Runnable () { 126 public void run() { 127 if (resourceNames.isDisposed()) { 129 disposed[0] = true; 130 return; 131 } 132 itemCount[0] = resourceNames.getItemCount(); 133 } 134 }); 135 136 if (disposed[0]) { 137 return; 138 } 139 140 int last; 141 if ((patternString.indexOf('?') == -1) 142 && (patternString.endsWith("*")) && (patternString.indexOf('*') == patternString.length() - 1)) { 144 firstMatch = getFirstMatch(); 149 if (firstMatch == -1) { 150 firstMatch = 0; 151 lastMatch = -1; 152 } else { 153 lastMatch = getLastMatch(); 154 } 155 last = lastMatch; 156 for (int i = firstMatch; i <= lastMatch; i++) { 157 if (i % 50 == 0) { 158 try { 159 Thread.sleep(10); 160 } catch (InterruptedException e) { 161 } 163 } 164 if (stop || resourceNames.isDisposed()) { 165 disposed[0] = true; 166 return; 167 } 168 final int index = i; 169 display.syncExec(new Runnable () { 170 public void run() { 171 if (stop || resourceNames.isDisposed()) { 172 return; 173 } 174 updateItem(index, itemIndex[0], itemCount[0]); 175 itemIndex[0]++; 176 } 177 }); 178 } 179 } else { 180 last = lastMatch; 181 boolean setFirstMatch = true; 182 for (int i = firstMatch; i <= lastMatch; i++) { 183 if (i % 50 == 0) { 184 try { 185 Thread.sleep(10); 186 } catch (InterruptedException e) { 187 } 189 } 190 if (stop || resourceNames.isDisposed()) { 191 disposed[0] = true; 192 return; 193 } 194 final int index = i; 195 if (match(descriptors[index].label)) { 196 if (setFirstMatch) { 197 setFirstMatch = false; 198 firstMatch = index; 199 } 200 last = index; 201 display.syncExec(new Runnable () { 202 public void run() { 203 if (stop || resourceNames.isDisposed()) { 204 return; 205 } 206 updateItem(index, itemIndex[0], itemCount[0]); 207 itemIndex[0]++; 208 } 209 }); 210 } 211 } 212 } 213 214 if (disposed[0]) { 215 return; 216 } 217 218 lastMatch = last; 219 display.syncExec(new Runnable () { 220 public void run() { 221 if (resourceNames.isDisposed()) { 222 return; 223 } 224 itemCount[0] = resourceNames.getItemCount(); 225 if (itemIndex[0] < itemCount[0]) { 226 resourceNames.setRedraw(false); 227 resourceNames.remove(itemIndex[0], itemCount[0] - 1); 228 resourceNames.setRedraw(true); 229 } 230 if (resourceNames.getItemCount() == 0) { 232 folderNames.removeAll(); 233 updateOKState(false); 234 } 235 } 236 }); 237 } 238 } 239 240 class UpdateGatherThread extends Thread { 241 boolean stop = false; 242 243 int lastMatch = -1; 244 245 int firstMatch = 0; 246 247 boolean refilter = false; 248 249 public void run() { 250 Display display = resourceNames.getDisplay(); 251 final int itemIndex[] = { 0 }; 252 final int itemCount[] = { 0 }; 253 final boolean[] disposed = { false }; 256 display.syncExec(new Runnable () { 257 public void run() { 258 if (resourceNames.isDisposed()) { 260 disposed[0] = true; 261 return; 262 } 263 itemCount[0] = resourceNames.getItemCount(); 264 } 265 }); 266 267 if (disposed[0]) { 268 return; 269 } 270 271 if (!refilter) { 272 for (int i = 0; i <= lastMatch; i++) { 273 if (i % 50 == 0) { 274 try { 275 Thread.sleep(10); 276 } catch (InterruptedException e) { 277 } 279 } 280 if (stop || resourceNames.isDisposed()) { 281 disposed[0] = true; 282 return; 283 } 284 final int index = i; 285 display.syncExec(new Runnable () { 286 public void run() { 287 if (stop || resourceNames.isDisposed()) { 288 return; 289 } 290 updateItem(index, itemIndex[0], itemCount[0]); 291 itemIndex[0]++; 292 } 293 }); 294 } 295 } else { 296 for (int i = firstMatch; i <= lastMatch; i++) { 298 if (i % 50 == 0) { 299 try { 300 Thread.sleep(10); 301 } catch (InterruptedException e) { 302 } 304 } 305 if (stop || resourceNames.isDisposed()) { 306 disposed[0] = true; 307 return; 308 } 309 final int index = i; 310 if (match(descriptors[index].label)) { 311 display.syncExec(new Runnable () { 312 public void run() { 313 if (stop || resourceNames.isDisposed()) { 314 return; 315 } 316 updateItem(index, itemIndex[0], itemCount[0]); 317 itemIndex[0]++; 318 } 319 }); 320 } 321 } 322 } 323 324 if (disposed[0]) { 325 return; 326 } 327 328 display.syncExec(new Runnable () { 329 public void run() { 330 if (resourceNames.isDisposed()) { 331 return; 332 } 333 itemCount[0] = resourceNames.getItemCount(); 334 if (itemIndex[0] < itemCount[0]) { 335 resourceNames.setRedraw(false); 336 resourceNames.remove(itemIndex[0], itemCount[0] - 1); 337 resourceNames.setRedraw(true); 338 } 339 if (resourceNames.getItemCount() == 0) { 341 folderNames.removeAll(); 342 updateOKState(false); 343 } 344 } 345 }); 346 } 347 } 348 349 355 public ResourceListSelectionDialog(Shell parentShell, IResource[] resources) { 356 super(parentShell); 357 setShellStyle(getShellStyle() | SWT.RESIZE); 358 gatherResourcesDynamically = false; 359 initDescriptors(resources); 360 } 361 362 373 public ResourceListSelectionDialog(Shell parentShell, IContainer container, 374 int typeMask) { 375 super(parentShell); 376 this.container = container; 377 this.typeMask = typeMask; 378 setShellStyle(getShellStyle() | SWT.RESIZE); 379 } 380 381 384 protected String adjustPattern() { 385 String text = pattern.getText().trim(); 386 if (text.endsWith("<")) { return text.substring(0, text.length() - 1); 389 } 390 if (!text.equals("") && !text.endsWith("*")) { return text + "*"; } 393 return text; 394 } 395 396 399 protected void cancelPressed() { 400 setResult(null); 401 super.cancelPressed(); 402 } 403 404 407 public boolean close() { 408 boolean result = super.close(); 409 labelProvider.dispose(); 410 return result; 411 } 412 413 416 public void create() { 417 super.create(); 418 pattern.setFocus(); 419 getButton(IDialogConstants.OK_ID).setEnabled(okEnabled); 420 } 421 422 428 protected Control createDialogArea(Composite parent) { 429 430 Composite dialogArea = (Composite) super.createDialogArea(parent); 431 Label l = new Label(dialogArea, SWT.NONE); 432 l.setText(IDEWorkbenchMessages.ResourceSelectionDialog_label); 433 GridData data = new GridData(GridData.FILL_HORIZONTAL); 434 l.setLayoutData(data); 435 436 pattern = new Text(dialogArea, SWT.SINGLE | SWT.BORDER); 437 pattern.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 438 l = new Label(dialogArea, SWT.NONE); 439 l.setText(IDEWorkbenchMessages.ResourceSelectionDialog_matching); 440 data = new GridData(GridData.FILL_HORIZONTAL); 441 l.setLayoutData(data); 442 resourceNames = new Table(dialogArea, SWT.SINGLE | SWT.BORDER 443 | SWT.V_SCROLL); 444 data = new GridData(GridData.FILL_BOTH); 445 data.heightHint = 12 * resourceNames.getItemHeight(); 446 resourceNames.setLayoutData(data); 447 448 l = new Label(dialogArea, SWT.NONE); 449 l.setText(IDEWorkbenchMessages.ResourceSelectionDialog_folders); 450 data = new GridData(GridData.FILL_HORIZONTAL); 451 l.setLayoutData(data); 452 453 folderNames = new Table(dialogArea, SWT.SINGLE | SWT.BORDER 454 | SWT.V_SCROLL | SWT.H_SCROLL); 455 data = new GridData(GridData.FILL_BOTH); 456 data.widthHint = 300; 457 data.heightHint = 4 * folderNames.getItemHeight(); 458 folderNames.setLayoutData(data); 459 460 if (gatherResourcesDynamically) { 461 updateGatherThread = new UpdateGatherThread(); 462 } else { 463 updateFilterThread = new UpdateFilterThread(); 464 } 465 466 pattern.addKeyListener(new KeyAdapter() { 467 public void keyReleased(KeyEvent e) { 468 if (e.keyCode == SWT.ARROW_DOWN) { 469 resourceNames.setFocus(); 470 } 471 } 472 }); 473 474 pattern.addModifyListener(new ModifyListener() { 475 public void modifyText(ModifyEvent e) { 476 refresh(false); 477 } 478 }); 479 480 resourceNames.addSelectionListener(new SelectionAdapter() { 481 public void widgetSelected(SelectionEvent e) { 482 updateFolders((ResourceDescriptor) e.item.getData()); 483 } 484 485 public void widgetDefaultSelected(SelectionEvent e) { 486 okPressed(); 487 } 488 }); 489 490 folderNames.addSelectionListener(new SelectionAdapter() { 491 public void widgetDefaultSelected(SelectionEvent e) { 492 okPressed(); 493 } 494 }); 495 496 if (getAllowUserToToggleDerived()) { 497 showDerivedButton = new Button(dialogArea, SWT.CHECK); 498 showDerivedButton.setText(IDEWorkbenchMessages.ResourceSelectionDialog_showDerived); 499 showDerivedButton.addSelectionListener(new SelectionAdapter() { 500 public void widgetSelected(SelectionEvent e) { 501 setShowDerived(showDerivedButton.getSelection()); 502 refresh(true); 503 } 504 }); 505 showDerivedButton.setSelection(getShowDerived()); 506 } 507 508 applyDialogFont(dialogArea); 509 return dialogArea; 510 } 511 512 519 public boolean getAllowUserToToggleDerived() { 520 return allowUserToToggleDerived; 521 } 522 523 529 public void setAllowUserToToggleDerived(boolean allow) { 530 allowUserToToggleDerived = allow; 531 } 532 533 535 private void filterResources(boolean force) { 536 String oldPattern = force ? null : patternString; 537 patternString = adjustPattern(); 538 if (!force && patternString.equals(oldPattern)) { 539 return; 540 } 541 542 updateFilterThread.stop = true; 543 stringMatcher = new StringMatcher(patternString, true, false); 544 UpdateFilterThread oldThread = updateFilterThread; 545 updateFilterThread = new UpdateFilterThread(); 546 if (patternString.equals("")) { updateFilterThread.firstMatch = 0; 548 updateFilterThread.lastMatch = -1; 549 updateFilterThread.start(); 550 return; 551 } 552 553 if (oldPattern != null && (oldPattern.length() != 0) 554 && oldPattern.endsWith("*") && patternString.endsWith("*")) { int matchLength = oldPattern.length() - 1; 556 if (patternString.regionMatches(0, oldPattern, 0, matchLength)) { 557 updateFilterThread.firstMatch = oldThread.firstMatch; 560 updateFilterThread.lastMatch = oldThread.lastMatch; 561 updateFilterThread.start(); 562 return; 563 } 564 } 565 566 updateFilterThread.firstMatch = 0; 568 updateFilterThread.lastMatch = descriptorsSize - 1; 569 updateFilterThread.start(); 570 } 571 572 578 private int getFirstMatch() { 579 int high = descriptorsSize; 580 int low = -1; 581 boolean match = false; 582 ResourceDescriptor desc = new ResourceDescriptor(); 583 desc.label = patternString.substring(0, patternString.length() - 1); 584 while (high - low > 1) { 585 int index = (high + low) / 2; 586 String label = descriptors[index].label; 587 if (match(label)) { 588 high = index; 589 match = true; 590 } else { 591 int compare = descriptors[index].compareTo(desc); 592 if (compare == -1) { 593 low = index; 594 } else { 595 high = index; 596 } 597 } 598 } 599 if (match) { 600 return high; 601 } 602 return -1; 603 } 604 605 607 private void gatherResources(boolean force) { 608 String oldPattern = force ? null : patternString; 609 patternString = adjustPattern(); 610 if (!force && patternString.equals(oldPattern)) { 611 return; 612 } 613 614 updateGatherThread.stop = true; 615 updateGatherThread = new UpdateGatherThread(); 616 617 if (patternString.equals("")) { updateGatherThread.start(); 619 return; 620 } 621 stringMatcher = new StringMatcher(patternString, true, false); 622 623 if (oldPattern != null && (oldPattern.length() != 0) 624 && oldPattern.endsWith("*") && patternString.endsWith("*")) { int matchLength = oldPattern.length() - 1; 627 if (patternString.regionMatches(0, oldPattern, 0, matchLength)) { 628 updateGatherThread.refilter = true; 629 updateGatherThread.firstMatch = 0; 630 updateGatherThread.lastMatch = descriptorsSize - 1; 631 updateGatherThread.start(); 632 return; 633 } 634 } 635 636 final ArrayList resources = new ArrayList (); 637 BusyIndicator.showWhile(getShell().getDisplay(), new Runnable () { 638 public void run() { 639 getMatchingResources(resources); 640 IResource resourcesArray[] = new IResource[resources.size()]; 641 resources.toArray(resourcesArray); 642 initDescriptors(resourcesArray); 643 } 644 }); 645 646 updateGatherThread.firstMatch = 0; 647 updateGatherThread.lastMatch = descriptorsSize - 1; 648 updateGatherThread.start(); 649 } 650 651 657 private Image getImage(ResourceDescriptor desc) { 658 IResource r = (IResource) desc.resources.get(0); 659 return labelProvider.getImage(r); 660 } 661 662 668 private int getLastMatch() { 669 int high = descriptorsSize; 670 int low = -1; 671 boolean match = false; 672 ResourceDescriptor desc = new ResourceDescriptor(); 673 desc.label = patternString.substring(0, patternString.length() - 1); 674 while (high - low > 1) { 675 int index = (high + low) / 2; 676 String label = descriptors[index].label; 677 if (match(label)) { 678 low = index; 679 match = true; 680 } else { 681 int compare = descriptors[index].compareTo(desc); 682 if (compare == -1) { 683 low = index; 684 } else { 685 high = index; 686 } 687 } 688 } 689 if (match) { 690 return low; 691 } 692 return -1; 693 } 694 695 702 private void getMatchingResources(final ArrayList resources) { 703 try { 704 container.accept(new IResourceProxyVisitor() { 705 public boolean visit(IResourceProxy proxy) { 706 if (!getShowDerived() && proxy.isDerived()) { 708 return false; 709 } 710 int type = proxy.getType(); 711 if ((typeMask & type) != 0) { 712 if (match(proxy.getName())) { 713 IResource res = proxy.requestResource(); 714 if (select(res)) { 715 resources.add(res); 716 return true; 717 } 718 return false; 719 } 720 } 721 if (type == IResource.FILE) { 722 return false; 723 } 724 return true; 725 } 726 }, IResource.NONE); 727 } catch (CoreException e) { 728 } 730 } 731 732 private Image getParentImage(IResource resource) { 733 IResource parent = resource.getParent(); 734 return labelProvider.getImage(parent); 735 } 736 737 private String getParentLabel(IResource resource) { 738 IResource parent = resource.getParent(); 739 String text; 740 if (parent.getType() == IResource.ROOT) { 741 text = labelProvider.getText(parent); 743 } else { 744 text = parent.getFullPath().makeRelative().toString(); 745 } 746 if(text == null) { 747 return ""; } 749 return text; 750 } 751 752 759 protected boolean getShowDerived() { 760 return showDerived ; 761 } 762 763 769 protected void setShowDerived(boolean show) { 770 showDerived = show; 771 } 772 773 779 private void initDescriptors(final IResource resources[]) { 780 BusyIndicator.showWhile(null, new Runnable () { 781 public void run() { 782 descriptors = new ResourceDescriptor[resources.length]; 783 for (int i = 0; i < resources.length; i++) { 784 IResource r = resources[i]; 785 ResourceDescriptor d = new ResourceDescriptor(); 786 d.label = r.getName(); 788 d.resources.add(r); 789 descriptors[i] = d; 790 } 791 Arrays.sort(descriptors); 792 descriptorsSize = descriptors.length; 793 794 int index = 0; 796 if (descriptorsSize < 2) { 797 return; 798 } 799 ResourceDescriptor current = descriptors[index]; 800 IResource currentResource = (IResource) current.resources 801 .get(0); 802 for (int i = 1; i < descriptorsSize; i++) { 803 ResourceDescriptor next = descriptors[i]; 804 IResource nextResource = (IResource) next.resources.get(0); 805 if (nextResource.getType() == currentResource.getType() 806 && next.label.equals(current.label)) { 807 current.resources.add(nextResource); 808 current.resourcesSorted = false; 813 } else { 814 if (current.resources.size() > 1) { 815 current.resourcesSorted = false; 816 } 817 descriptors[index + 1] = descriptors[i]; 818 index++; 819 current = descriptors[index]; 820 currentResource = (IResource) current.resources.get(0); 821 } 822 } 823 descriptorsSize = index + 1; 824 } 825 }); 826 } 827 828 835 private boolean match(String label) { 836 if ((patternString == null) 837 || (patternString.equals("")) || (patternString.equals("*"))) { return true; 839 } 840 return stringMatcher.match(label); 841 } 842 843 847 protected void okPressed() { 848 TableItem items[] = folderNames.getSelection(); 849 if (items.length == 1) { 850 ArrayList result = new ArrayList (); 851 result.add(items[0].getData()); 852 setResult(result); 853 } 854 super.okPressed(); 855 } 856 857 863 protected boolean select(IResource resource) { 864 return true; 865 } 866 867 876 protected void refresh(boolean force) { 877 if (gatherResourcesDynamically) { 878 gatherResources(force); 879 } else { 880 filterResources(force); 881 } 882 } 883 884 890 private void updateFolders(final ResourceDescriptor desc) { 891 BusyIndicator.showWhile(getShell().getDisplay(), new Runnable () { 892 public void run() { 893 if (!desc.resourcesSorted) { 894 Collections.sort(desc.resources, new Comparator () { 896 public int compare(Object o1, Object o2) { 897 String s1 = getParentLabel((IResource) o1); 898 String s2 = getParentLabel((IResource) o2); 899 return collator.compare(s1, s2); 900 } 901 }); 902 desc.resourcesSorted = true; 903 } 904 folderNames.removeAll(); 905 for (int i = 0; i < desc.resources.size(); i++) { 906 TableItem newItem = new TableItem(folderNames, SWT.NONE); 907 IResource r = (IResource) desc.resources.get(i); 908 newItem.setText(getParentLabel(r)); 909 newItem.setImage(getParentImage(r)); 910 newItem.setData(r); 911 } 912 folderNames.setSelection(0); 913 } 914 }); 915 } 916 917 926 private void updateItem(int index, int itemPos, int itemCount) { 927 ResourceDescriptor desc = descriptors[index]; 928 TableItem item; 929 if (itemPos < itemCount) { 930 item = resourceNames.getItem(itemPos); 931 if (item.getData() != desc) { 932 item.setText(desc.label); 933 item.setData(desc); 934 item.setImage(getImage(desc)); 935 if (itemPos == 0) { 936 resourceNames.setSelection(0); 937 updateFolders(desc); 938 } 939 } 940 } else { 941 item = new TableItem(resourceNames, SWT.NONE); 942 item.setText(desc.label); 943 item.setData(desc); 944 item.setImage(getImage(desc)); 945 if (itemPos == 0) { 946 resourceNames.setSelection(0); 947 updateFolders(desc); 948 } 949 } 950 updateOKState(true); 951 } 952 953 958 protected void updateOKState(boolean state) { 959 Button okButton = getButton(IDialogConstants.OK_ID); 960 if(okButton != null && !okButton.isDisposed() && state != okEnabled) { 961 okButton.setEnabled(state); 962 okEnabled = state; 963 } 964 } 965 966 967 972 protected IDialogSettings getDialogBoundsSettings() { 973 IDialogSettings settings = IDEWorkbenchPlugin.getDefault().getDialogSettings(); 974 IDialogSettings section = settings.getSection(DIALOG_SETTINGS_SECTION); 975 if (section == null) { 976 section = settings.addNewSection(DIALOG_SETTINGS_SECTION); 977 } 978 return section; 979 } 980 } 981 982 | Popular Tags |