1 11 package org.eclipse.ui.dialogs; 12 13 import org.eclipse.core.runtime.IProgressMonitor; 14 import org.eclipse.core.runtime.IStatus; 15 import org.eclipse.core.runtime.Status; 16 import org.eclipse.core.runtime.jobs.Job; 17 import org.eclipse.jface.action.Action; 18 import org.eclipse.jface.action.IAction; 19 import org.eclipse.jface.action.ToolBarManager; 20 import org.eclipse.jface.resource.ImageDescriptor; 21 import org.eclipse.jface.resource.JFaceResources; 22 import org.eclipse.jface.viewers.IContentProvider; 23 import org.eclipse.jface.viewers.ISelection; 24 import org.eclipse.jface.viewers.TreeViewer; 25 import org.eclipse.swt.SWT; 26 import org.eclipse.swt.accessibility.AccessibleAdapter; 27 import org.eclipse.swt.accessibility.AccessibleEvent; 28 import org.eclipse.swt.events.DisposeEvent; 29 import org.eclipse.swt.events.DisposeListener; 30 import org.eclipse.swt.events.FocusAdapter; 31 import org.eclipse.swt.events.FocusEvent; 32 import org.eclipse.swt.events.KeyAdapter; 33 import org.eclipse.swt.events.KeyEvent; 34 import org.eclipse.swt.events.ModifyEvent; 35 import org.eclipse.swt.events.ModifyListener; 36 import org.eclipse.swt.events.TraverseEvent; 37 import org.eclipse.swt.events.TraverseListener; 38 import org.eclipse.swt.graphics.Color; 39 import org.eclipse.swt.graphics.Font; 40 import org.eclipse.swt.layout.GridData; 41 import org.eclipse.swt.layout.GridLayout; 42 import org.eclipse.swt.widgets.Composite; 43 import org.eclipse.swt.widgets.Control; 44 import org.eclipse.swt.widgets.Display; 45 import org.eclipse.swt.widgets.Text; 46 import org.eclipse.swt.widgets.TreeItem; 47 import org.eclipse.ui.IWorkbenchPreferenceConstants; 48 import org.eclipse.ui.PlatformUI; 49 import org.eclipse.ui.internal.WorkbenchMessages; 50 import org.eclipse.ui.plugin.AbstractUIPlugin; 51 import org.eclipse.ui.progress.WorkbenchJob; 52 53 60 public class FilteredTree extends Composite { 61 62 67 protected Text filterText; 68 69 74 protected ToolBarManager filterToolBar; 75 76 80 protected TreeViewer treeViewer; 81 82 86 protected Composite filterComposite; 87 88 91 private PatternFilter patternFilter; 92 93 96 protected String initialText = ""; 98 101 private Job refreshJob; 102 103 107 protected Composite parent; 108 109 117 protected boolean showFilterControls; 118 119 122 protected Composite treeComposite; 123 124 127 private static final String CLEAR_ICON = "org.eclipse.ui.internal.dialogs.CLEAR_ICON"; 129 132 private static final String DCLEAR_ICON = "org.eclipse.ui.internal.dialogs.DCLEAR_ICON"; 134 138 private static final long SOFT_MAX_EXPAND_TIME = 200; 139 140 143 static { 144 ImageDescriptor descriptor = AbstractUIPlugin 145 .imageDescriptorFromPlugin(PlatformUI.PLUGIN_ID, 146 "$nl$/icons/full/etool16/clear_co.gif"); if (descriptor != null) { 148 JFaceResources.getImageRegistry().put(CLEAR_ICON, descriptor); 149 } 150 descriptor = AbstractUIPlugin.imageDescriptorFromPlugin( 151 PlatformUI.PLUGIN_ID, "$nl$/icons/full/dtool16/clear_co.gif"); if (descriptor != null) { 153 JFaceResources.getImageRegistry().put(DCLEAR_ICON, descriptor); 154 } 155 } 156 157 167 public FilteredTree(Composite parent, int treeStyle, PatternFilter filter) { 168 super(parent, SWT.NONE); 169 this.parent = parent; 170 init(treeStyle, filter); 171 } 172 173 185 protected FilteredTree(Composite parent) { 186 super(parent, SWT.NONE); 187 this.parent = parent; 188 } 189 190 200 protected void init(int treeStyle, PatternFilter filter) { 201 patternFilter = filter; 202 showFilterControls = PlatformUI.getPreferenceStore().getBoolean( 203 IWorkbenchPreferenceConstants.SHOW_FILTERED_TEXTS); 204 createControl(parent, treeStyle); 205 createRefreshJob(); 206 setInitialText(WorkbenchMessages.FilteredTree_FilterMessage); 207 setFont(parent.getFont()); 208 } 209 210 217 protected void createControl(Composite parent, int treeStyle){ 218 GridLayout layout = new GridLayout(); 219 layout.marginHeight = 0; 220 layout.marginWidth = 0; 221 setLayout(layout); 222 setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 223 224 if (showFilterControls){ 225 filterComposite = new Composite(this, SWT.NONE); 226 GridLayout filterLayout = new GridLayout(2, false); 227 filterLayout.marginHeight = 0; 228 filterLayout.marginWidth = 0; 229 filterComposite.setLayout(filterLayout); 230 filterComposite.setFont(parent.getFont()); 231 232 createFilterControls(filterComposite); 233 filterComposite.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, 234 true, false)); 235 } 236 237 treeComposite = new Composite(this, SWT.NONE); 238 GridLayout treeCompositeLayout = new GridLayout(); 239 treeCompositeLayout.marginHeight = 0; 240 treeCompositeLayout.marginWidth = 0; 241 treeComposite.setLayout(treeCompositeLayout); 242 GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); 243 treeComposite.setLayoutData(data); 244 createTreeControl(treeComposite, treeStyle); 245 } 246 247 255 protected Composite createFilterControls(Composite parent){ 256 createFilterText(parent); 257 createClearText(parent); 258 if (filterToolBar != null) { 259 filterToolBar.update(false); 260 filterToolBar.getControl().setVisible(false); 262 } 263 return parent; 264 } 265 266 278 protected Control createTreeControl(Composite parent, int style){ 279 treeViewer = doCreateTreeViewer(parent, style); 280 GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); 281 treeViewer.getControl().setLayoutData(data); 282 treeViewer.getControl().addDisposeListener(new DisposeListener(){ 283 286 public void widgetDisposed(DisposeEvent e) { 287 refreshJob.cancel(); 288 } 289 }); 290 if (treeViewer instanceof NotifyingTreeViewer) { 291 patternFilter.setUseCache(true); 292 } 293 treeViewer.addFilter(patternFilter); 294 return treeViewer.getControl(); 295 } 296 297 306 protected TreeViewer doCreateTreeViewer(Composite parent, int style) { 307 return new NotifyingTreeViewer(parent, style); 308 } 309 310 316 private TreeItem getFirstMatchingItem(TreeItem[] items){ 317 for (int i = 0; i < items.length; i++){ 318 if (patternFilter.isLeafMatch(treeViewer, items[i].getData()) 319 && patternFilter.isElementSelectable(items[i].getData())) { 320 return items[i]; 321 } 322 return getFirstMatchingItem(items[i].getItems()); 323 } 324 return null; 325 } 326 327 331 private void createRefreshJob() { 332 refreshJob = new WorkbenchJob("Refresh Filter"){ 336 public IStatus runInUIThread(IProgressMonitor monitor) { 337 if(treeViewer.getControl().isDisposed()) { 338 return Status.CANCEL_STATUS; 339 } 340 341 String text = getFilterString(); 342 if (text == null) { 343 return Status.OK_STATUS; 344 } 345 346 boolean initial = initialText != null && initialText.equals(text); 347 if (initial) { 348 patternFilter.setPattern(null); 349 } else if (text != null){ 350 patternFilter.setPattern(text); 351 } 352 353 Control redrawFalseControl = treeComposite != null ? treeComposite : treeViewer.getControl(); 354 try { 355 redrawFalseControl.setRedraw(false); 358 if (!narrowingDown) { 359 TreeItem[] is = treeViewer.getTree().getItems(); 361 for (int i = 0; i < is.length; i++) { 362 TreeItem item = is[i]; 363 if (item.getExpanded()) { 364 treeViewer.setExpandedState(item.getData(), false); 365 } 366 } 367 } 368 treeViewer.refresh(true); 369 370 if (text.length() > 0 && !initial) { 371 376 TreeItem[] items = getViewer().getTree().getItems(); 377 int treeHeight = getViewer().getTree().getBounds().height; 378 int numVisibleItems = treeHeight / getViewer().getTree().getItemHeight(); 379 long stopTime = SOFT_MAX_EXPAND_TIME + System.currentTimeMillis(); 380 if (items.length > 0 381 && recursiveExpand(items, monitor, stopTime, new int[] { numVisibleItems })) { 382 return Status.CANCEL_STATUS; 383 } 384 385 updateToolbar(true); 388 } else { 389 updateToolbar(false); 392 } 393 } 394 finally { 395 TreeItem[] items = getViewer().getTree().getItems(); 397 if (items.length > 0 && getViewer().getTree().getSelectionCount()==0) { 398 treeViewer.getTree().setTopItem(items[0]); 399 } 400 redrawFalseControl.setRedraw(true); 401 } 402 return Status.OK_STATUS; 403 } 404 405 414 private boolean recursiveExpand(TreeItem[] items, 415 IProgressMonitor monitor, long cancelTime, int[] numItemsLeft) { 416 boolean canceled = false; 417 for (int i = 0; !canceled && i < items.length; i++) { 418 TreeItem item = items[i]; 419 boolean visible = numItemsLeft[0]-- >= 0; 420 if (monitor.isCanceled() 421 || (!visible && System.currentTimeMillis() > cancelTime)) { 422 canceled = true; 423 } else { 424 Object itemData = item.getData(); 425 if (itemData != null) { 426 if (!item.getExpanded()) { 427 treeViewer.setExpandedState(itemData, true); 429 } 430 TreeItem[] children = item.getItems(); 431 if (items.length > 0) { 432 canceled = recursiveExpand(children, 433 monitor, cancelTime, numItemsLeft); 434 } 435 } 436 } 437 } 438 return canceled; 439 } 440 441 }; 442 refreshJob.setSystem(true); 443 } 444 445 protected void updateToolbar(boolean visible){ 446 if (filterToolBar != null) { 447 filterToolBar.getControl().setVisible(visible); 448 } 449 } 450 451 459 protected void createFilterText(Composite parent) { 460 filterText = doCreateFilterText(parent); 461 filterText.getAccessible().addAccessibleListener( 462 new AccessibleAdapter(){ 463 466 public void getName(AccessibleEvent e) { 467 String filterTextString = filterText.getText(); 468 if(filterTextString.length() == 0){ 469 e.result = initialText; 470 } else { 471 e.result = filterTextString; 472 } 473 } 474 }); 475 476 filterText.addFocusListener( 477 new FocusAdapter(){ 478 481 public void focusGained(FocusEvent e) { 482 485 Display display = filterText.getDisplay(); 486 display.asyncExec(new Runnable () { 487 public void run() { 488 if (!filterText.isDisposed()){ 489 if (getInitialText().equals(filterText.getText().trim())){ 490 filterText.selectAll(); 491 } 492 } 493 } 494 }); 495 } 496 }); 497 498 filterText.addKeyListener(new KeyAdapter() { 499 504 public void keyPressed(KeyEvent e) { 505 boolean hasItems = getViewer().getTree().getItemCount() > 0; 507 if(hasItems && e.keyCode == SWT.ARROW_DOWN){ 508 treeViewer.getTree().setFocus(); 509 } else if (e.character == SWT.CR){ 510 return; 511 } 512 } 513 }); 514 515 filterText.addTraverseListener(new TraverseListener () { 517 public void keyTraversed(TraverseEvent e) { 518 if (e.detail == SWT.TRAVERSE_RETURN) { 519 e.doit = false; 520 if (getViewer().getTree().getItemCount() == 0) { 521 Display.getCurrent().beep(); 522 } else { 523 boolean hasFocus = getViewer().getTree().setFocus(); 525 boolean textChanged = !getInitialText().equals( 526 filterText.getText().trim()); 527 if (hasFocus && textChanged 528 && filterText.getText().trim().length() > 0) { 529 TreeItem item = getFirstMatchingItem(getViewer() 530 .getTree().getItems()); 531 if (item != null) { 532 getViewer().getTree().setSelection( 533 new TreeItem[] { item }); 534 ISelection sel = getViewer().getSelection(); 535 getViewer().setSelection(sel, true); 536 } 537 } 538 } 539 } 540 } 541 }); 542 543 filterText.addModifyListener(new ModifyListener(){ 544 547 public void modifyText(ModifyEvent e) { 548 textChanged(); 549 } 550 }); 551 552 GridData gridData = new GridData(SWT.FILL, SWT.BEGINNING, true, false); 553 if ((filterText.getStyle() & SWT.CANCEL) != 0) 556 gridData.horizontalSpan = 2; 557 filterText.setLayoutData(gridData); 558 } 559 560 570 protected Text doCreateFilterText(Composite parent) { 571 return new Text(parent, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.CANCEL); 572 } 573 574 private String previousFilterText; 575 576 private boolean narrowingDown; 577 578 581 protected void textChanged() { 582 narrowingDown = previousFilterText==null || getFilterString().startsWith(previousFilterText); 583 previousFilterText = getFilterString(); 584 refreshJob.cancel(); 586 refreshJob.schedule(200); 587 } 588 589 594 public void setBackground(Color background) { 595 super.setBackground(background); 596 if (filterComposite != null) { 597 filterComposite.setBackground(background); 598 } 599 if (filterToolBar != null && filterToolBar.getControl() != null) { 600 filterToolBar.getControl().setBackground(background); 601 } 602 } 603 604 609 private void createClearText(Composite parent) { 610 if ((filterText.getStyle() & SWT.CANCEL) == 0) { 612 filterToolBar = new ToolBarManager(SWT.FLAT | SWT.HORIZONTAL); 613 filterToolBar.createControl(parent); 614 615 IAction clearTextAction = new Action("", IAction.AS_PUSH_BUTTON) { 621 public void run() { 622 clearText(); 623 } 624 }; 625 626 clearTextAction 627 .setToolTipText(WorkbenchMessages.FilteredTree_ClearToolTip); 628 clearTextAction.setImageDescriptor(JFaceResources 629 .getImageRegistry().getDescriptor(CLEAR_ICON)); 630 clearTextAction.setDisabledImageDescriptor(JFaceResources 631 .getImageRegistry().getDescriptor(DCLEAR_ICON)); 632 633 filterToolBar.add(clearTextAction); 634 } 635 } 636 637 641 protected void clearText() { 642 setFilterText(""); textChanged(); 644 } 645 646 650 protected void setFilterText(String string) { 651 if (filterText != null){ 652 filterText.setText(string); 653 selectAll(); 654 } 655 } 656 657 662 public final PatternFilter getPatternFilter() { 663 return patternFilter; 664 } 665 666 671 public TreeViewer getViewer() { 672 return treeViewer; 673 } 674 675 681 public Text getFilterControl() { 682 return filterText; 683 } 684 685 691 protected String getFilterString(){ 692 return filterText != null ? filterText.getText() : null; 693 } 694 695 702 public void setInitialText(String text) { 703 initialText = text; 704 setFilterText(initialText); 705 textChanged(); 706 } 707 708 712 protected void selectAll() { 713 if (filterText != null) { 714 filterText.selectAll(); 715 } 716 } 717 718 722 protected String getInitialText() { 723 return initialText; 724 } 725 726 740 public static Font getBoldFont(Object element, FilteredTree tree, 741 PatternFilter filter) { 742 String filterText = tree.getFilterString(); 743 744 if (filterText == null) { 745 return null; 746 } 747 748 String initialText = tree.getInitialText(); 750 if (!("".equals(filterText) || initialText.equals(filterText))) { boolean initial = initialText != null 752 && initialText.equals(filterText); 753 if (initial) { 754 filter.setPattern(null); 755 } else if (filterText != null){ 756 filter.setPattern(filterText); 757 } 758 759 if (filter.isElementVisible(tree.getViewer(), element) && 760 filter.isLeafMatch(tree.getViewer(),element)) { 761 return JFaceResources.getFontRegistry().getBold( 762 JFaceResources.DIALOG_FONT); 763 } 764 } 765 return null; 766 } 767 768 775 class NotifyingTreeViewer extends TreeViewer { 776 777 781 public NotifyingTreeViewer(Composite parent, int style) { 782 super(parent, style); 783 } 784 785 public void add(Object parentElementOrTreePath, Object childElement) { 786 getPatternFilter().clearCaches(); 787 super.add(parentElementOrTreePath, childElement); 788 } 789 790 public void add(Object parentElementOrTreePath, Object [] childElements) { 791 getPatternFilter().clearCaches(); 792 super.add(parentElementOrTreePath, childElements); 793 } 794 795 protected void inputChanged(Object input, Object oldInput) { 796 getPatternFilter().clearCaches(); 797 super.inputChanged(input, oldInput); 798 } 799 800 public void insert(Object parentElementOrTreePath, Object element, 801 int position) { 802 getPatternFilter().clearCaches(); 803 super.insert(parentElementOrTreePath, element, position); 804 } 805 806 public void refresh() { 807 getPatternFilter().clearCaches(); 808 super.refresh(); 809 } 810 811 public void refresh(boolean updateLabels) { 812 getPatternFilter().clearCaches(); 813 super.refresh(updateLabels); 814 } 815 816 public void refresh(Object element) { 817 getPatternFilter().clearCaches(); 818 super.refresh(element); 819 } 820 821 public void refresh(Object element, boolean updateLabels) { 822 getPatternFilter().clearCaches(); 823 super.refresh(element, updateLabels); 824 } 825 826 public void remove(Object elementsOrTreePaths) { 827 getPatternFilter().clearCaches(); 828 super.remove(elementsOrTreePaths); 829 } 830 831 public void remove(Object parent, Object [] elements) { 832 getPatternFilter().clearCaches(); 833 super.remove(parent, elements); 834 } 835 836 public void remove(Object [] elementsOrTreePaths) { 837 getPatternFilter().clearCaches(); 838 super.remove(elementsOrTreePaths); 839 } 840 841 public void replace(Object parentElementOrTreePath, int index, 842 Object element) { 843 getPatternFilter().clearCaches(); 844 super.replace(parentElementOrTreePath, index, element); 845 } 846 847 public void setChildCount(Object elementOrTreePath, int count) { 848 getPatternFilter().clearCaches(); 849 super.setChildCount(elementOrTreePath, count); 850 } 851 852 public void setContentProvider(IContentProvider provider) { 853 getPatternFilter().clearCaches(); 854 super.setContentProvider(provider); 855 } 856 857 public void setHasChildren(Object elementOrTreePath, boolean hasChildren) { 858 getPatternFilter().clearCaches(); 859 super.setHasChildren(elementOrTreePath, hasChildren); 860 } 861 862 } 863 864 } 865 | Popular Tags |