| 1 12 13 package org.eclipse.jface.viewers; 14 15 import java.util.ArrayList ; 16 import java.util.Arrays ; 17 import java.util.Iterator ; 18 import java.util.LinkedList ; 19 import java.util.List ; 20 21 import org.eclipse.core.runtime.Assert; 22 import org.eclipse.core.runtime.ListenerList; 23 import org.eclipse.jface.util.SafeRunnable; 24 import org.eclipse.swt.SWT; 25 import org.eclipse.swt.custom.BusyIndicator; 26 import org.eclipse.swt.events.SelectionEvent; 27 import org.eclipse.swt.events.SelectionListener; 28 import org.eclipse.swt.events.TreeEvent; 29 import org.eclipse.swt.events.TreeListener; 30 import org.eclipse.swt.graphics.Point; 31 import org.eclipse.swt.widgets.Control; 32 import org.eclipse.swt.widgets.Item; 33 import org.eclipse.swt.widgets.Widget; 34 35 57 public abstract class AbstractTreeViewer extends ColumnViewer { 58 59 66 public static final int ALL_LEVELS = -1; 67 68 72 private ListenerList treeListeners = new ListenerList(); 73 74 81 private int expandToLevel = 0; 82 83 86 class UpdateItemSafeRunnable extends SafeRunnable { 87 private Object element; 88 89 private Item item; 90 91 UpdateItemSafeRunnable(Item item, Object element) { 92 this.item = item; 93 this.element = element; 94 } 95 96 public void run() { 97 doUpdateItem(item, element); 98 } 99 100 } 101 102 107 protected AbstractTreeViewer() { 108 } 110 111 127 public void add(Object parentElementOrTreePath, Object [] childElements) { 128 Assert.isNotNull(parentElementOrTreePath); 129 assertElementsNotNull(childElements); 130 if (isBusy()) 131 return; 132 Widget[] widgets = internalFindItems(parentElementOrTreePath); 133 if (widgets.length == 0) { 135 return; 136 } 137 138 for (int i = 0; i < widgets.length; i++) { 139 internalAdd(widgets[i], parentElementOrTreePath, childElements); 140 } 141 } 142 143 152 final protected Widget[] internalFindItems(Object parentElementOrTreePath) { 153 Widget[] widgets; 154 if (parentElementOrTreePath instanceof TreePath) { 155 TreePath path = (TreePath) parentElementOrTreePath; 156 Widget w = internalFindItem(path); 157 if (w == null) { 158 widgets = new Widget[] {}; 159 } else { 160 widgets = new Widget[] { w }; 161 } 162 } else { 163 widgets = findItems(parentElementOrTreePath); 164 } 165 return widgets; 166 } 167 168 175 private Widget internalFindItem(TreePath path) { 176 Widget[] widgets = findItems(path.getLastSegment()); 177 for (int i = 0; i < widgets.length; i++) { 178 Widget widget = widgets[i]; 179 if (widget instanceof Item) { 180 Item item = (Item) widget; 181 TreePath p = getTreePathFromItem(item); 182 if (p.equals(path)) { 183 return widget; 184 } 185 } 186 } 187 return null; 188 } 189 190 209 protected void internalAdd(Widget widget, Object parentElementOrTreePath, 210 Object [] childElements) { 211 Object parent; 212 TreePath path; 213 if (parentElementOrTreePath instanceof TreePath) { 214 path = (TreePath) parentElementOrTreePath; 215 parent = path.getLastSegment(); 216 } else { 217 parent = parentElementOrTreePath; 218 path = null; 219 } 220 221 if (widget instanceof Item) { 224 Item ti = (Item) widget; 225 if (!getExpanded(ti)) { 226 boolean needDummy = isExpandable(ti, path, parent); 227 boolean haveDummy = false; 228 Item[] items = getItems(ti); 230 for (int i = 0; i < items.length; i++) { 231 if (items[i].getData() != null) { 232 disassociate(items[i]); 233 items[i].dispose(); 234 } else { 235 if (needDummy && !haveDummy) { 236 haveDummy = true; 237 } else { 238 items[i].dispose(); 239 } 240 } 241 } 242 if (needDummy && !haveDummy) { 244 newItem(ti, SWT.NULL, -1); 245 } 246 return; 247 } 248 } 249 250 if (childElements.length > 0) { 251 Object [] filtered = filter(parentElementOrTreePath, childElements); 253 ViewerComparator comparator = getComparator(); 254 if (comparator != null) { 255 if (comparator instanceof TreePathViewerSorter) { 256 TreePathViewerSorter tpvs = (TreePathViewerSorter) comparator; 257 if (path == null) { 258 path = internalGetSorterParentPath(widget, comparator); 259 } 260 tpvs.sort(this, path, filtered); 261 } else { 262 comparator.sort(this, filtered); 263 } 264 } 265 createAddedElements(widget, filtered); 266 } 267 } 268 269 278 private Object [] filter(Object parentElementOrTreePath, Object [] elements) { 279 ViewerFilter[] filters = getFilters(); 280 if (filters != null) { 281 ArrayList filtered = new ArrayList (elements.length); 282 for (int i = 0; i < elements.length; i++) { 283 boolean add = true; 284 for (int j = 0; j < filters.length; j++) { 285 add = filters[j].select(this, parentElementOrTreePath, 286 elements[i]); 287 if (!add) { 288 break; 289 } 290 } 291 if (add) { 292 filtered.add(elements[i]); 293 } 294 } 295 return filtered.toArray(); 296 } 297 return elements; 298 } 299 300 308 private void createAddedElements(Widget widget, Object [] elements) { 309 310 if (elements.length == 1) { 311 if (equals(elements[0], widget.getData())) { 312 return; 313 } 314 } 315 316 ViewerComparator comparator = getComparator(); 317 TreePath parentPath = internalGetSorterParentPath(widget, comparator); 318 Item[] items = getChildren(widget); 319 320 int lastInsertion = 0; 323 324 if (items.length == 0) { 326 for (int i = 0; i < elements.length; i++) { 327 createTreeItem(widget, elements[i], -1); 328 } 329 return; 330 } 331 332 for (int i = 0; i < elements.length; i++) { 333 boolean newItem = true; 334 Object element = elements[i]; 335 int index; 336 if (comparator == null) { 337 if (itemExists(items, element)) { 338 internalRefresh(element); 339 newItem = false; 340 } 341 index = -1; 342 } else { 343 lastInsertion = insertionPosition(items, comparator, 344 lastInsertion, element, parentPath); 345 if (lastInsertion == items.length) { 348 index = -1; 349 } else { while (lastInsertion < items.length 351 && internalCompare(comparator, parentPath, element, 352 items[lastInsertion].getData()) == 0) { 353 if (items[lastInsertion].getData().equals(element)) { 358 internalRefresh(element); 360 newItem = false; 361 } 362 lastInsertion++; } 364 if (lastInsertion == items.length) { 366 index = -1; 367 } else { 368 index = lastInsertion + i; } 371 } 372 } 373 if (newItem) { 374 createTreeItem(widget, element, index); 375 } 376 } 377 } 378 379 386 private boolean itemExists(Item[] items, Object element) { 387 if (usingElementMap()) { 388 Widget[] existingItems = findItems(element); 389 if (existingItems.length == 0) { 391 return false; 392 } else if (existingItems.length == 1) { 393 if (items.length > 0 && existingItems[0] instanceof Item) { 394 Item existingItem = (Item) existingItems[0]; 395 return getParentItem(existingItem) == getParentItem(items[0]); 396 } 397 } 398 } 399 for (int i = 0; i < items.length; i++) { 400 if (items[i].getData().equals(element)) { 401 return true; 402 } 403 } 404 return false; 405 } 406 407 429 430 private int insertionPosition(Item[] items, ViewerComparator comparator, 431 int lastInsertion, Object element, TreePath parentPath) { 432 433 int size = items.length; 434 if (comparator == null) { 435 return size; 436 } 437 int min = lastInsertion, max = size - 1; 438 439 while (min <= max) { 440 int mid = (min + max) / 2; 441 Object data = items[mid].getData(); 442 int compare = internalCompare(comparator, parentPath, data, element); 443 if (compare == 0) { 444 return mid; } 446 if (compare < 0) { 447 min = mid + 1; 448 } else { 449 max = mid - 1; 450 } 451 } 452 return min; 453 454 } 455 456 476 477 486 protected int indexForElement(Widget parent, Object element) { 487 ViewerComparator comparator = getComparator(); 488 TreePath parentPath = internalGetSorterParentPath(parent, comparator); 489 490 Item[] items = getChildren(parent); 491 int count = items.length; 492 493 if (comparator == null) { 494 return count; 495 } 496 int min = 0, max = count - 1; 497 498 while (min <= max) { 499 int mid = (min + max) / 2; 500 Object data = items[mid].getData(); 501 int compare = internalCompare(comparator, parentPath, data, element); 502 if (compare == 0) { 503 while (compare == 0) { 505 ++mid; 506 if (mid >= count) { 507 break; 508 } 509 data = items[mid].getData(); 510 compare = internalCompare(comparator, parentPath, data, 511 element); 512 } 513 return mid; 514 } 515 if (compare < 0) { 516 min = mid + 1; 517 } else { 518 max = mid - 1; 519 } 520 } 521 return min; 522 } 523 524 537 private TreePath internalGetSorterParentPath(Widget parent, 538 ViewerComparator comparator) { 539 TreePath path; 540 if (comparator instanceof TreePathViewerSorter 541 && parent instanceof Item) { 542 Item item = (Item) parent; 543 path = getTreePathFromItem(item); 544 } else { 545 path = null; 546 } 547 return path; 548 } 549 550 566 private int internalCompare(ViewerComparator comparator, 567 TreePath parentPath, Object e1, Object e2) { 568 if (comparator instanceof TreePathViewerSorter) { 569 TreePathViewerSorter tpvs = (TreePathViewerSorter) comparator; 570 return tpvs.compare(this, parentPath, e1, e2); 571 } 572 return comparator.compare(this, e1, e2); 573 } 574 575 580 protected Object [] getSortedChildren(Object parentElementOrTreePath) { 581 Object [] result = getFilteredChildren(parentElementOrTreePath); 582 ViewerComparator comparator = getComparator(); 583 if (parentElementOrTreePath != null 584 && comparator instanceof TreePathViewerSorter) { 585 TreePathViewerSorter tpvs = (TreePathViewerSorter) comparator; 586 587 result = (Object []) result.clone(); 589 590 TreePath path = null; 591 if (parentElementOrTreePath instanceof TreePath) { 592 path = (TreePath) parentElementOrTreePath; 593 } else { 594 Object parent = parentElementOrTreePath; 595 Widget w = internalGetWidgetToSelect(parent); 596 if (w != null) { 597 path = internalGetSorterParentPath(w, comparator); 598 } 599 } 600 tpvs.sort(this, path, result); 601 } else if (comparator != null) { 602 result = (Object []) result.clone(); 604 comparator.sort(this, result); 605 } 606 return result; 607 } 608 609 614 protected Object [] getFilteredChildren(Object parentElementOrTreePath) { 615 Object [] result = getRawChildren(parentElementOrTreePath); 616 ViewerFilter[] filters = getFilters(); 617 for (int i = 0; i < filters.length; i++) { 618 ViewerFilter filter = filters[i]; 619 result = filter.filter(this, parentElementOrTreePath, result); 620 } 621 return result; 622 } 623 624 642 public void add(Object parentElementOrTreePath, Object childElement) { 643 add(parentElementOrTreePath, new Object [] { childElement }); 644 } 645 646 655 protected void addSelectionListener(Control control, 656 SelectionListener listener) { 657 } 659 660 667 public void addTreeListener(ITreeViewerListener listener) { 668 treeListeners.add(listener); 669 } 670 671 679 protected abstract void addTreeListener(Control control, 680 TreeListener listener); 681 682 687 protected void associate(Object element, Item item) { 688 Object data = item.getData(); 689 if (data != null && data != element && equals(data, element)) { 690 unmapElement(data, item); 694 item.setData(element); 695 mapElement(element, item); 696 } else { 697 super.associate(element, item); 699 } 700 } 701 702 706 public void collapseAll() { 707 Object root = getRoot(); 708 if (root != null) { 709 collapseToLevel(root, ALL_LEVELS); 710 } 711 } 712 713 723 public void collapseToLevel(Object elementOrTreePath, int level) { 724 Assert.isNotNull(elementOrTreePath); 725 Widget w = internalGetWidgetToSelect(elementOrTreePath); 726 if (w != null) { 727 internalCollapseToLevel(w, level); 728 } 729 } 730 731 743 protected void createChildren(final Widget widget) { 744 boolean oldBusy = busy; 745 busy = true; 746 try { 747 final Item[] tis = getChildren(widget); 748 if (tis != null && tis.length > 0) { 749 Object data = tis[0].getData(); 750 if (data != null) { 751 return; } 753 } 754 755 BusyIndicator.showWhile(widget.getDisplay(), new Runnable () { 756 public void run() { 757 if (tis != null) { 760 for (int i = 0; i < tis.length; i++) { 761 if (tis[i].getData() != null) { 762 disassociate(tis[i]); 763 Assert.isTrue(tis[i].getData() == null, 764 "Second or later child is non -null"); 766 } 767 tis[i].dispose(); 768 } 769 } 770 Object d = widget.getData(); 771 if (d != null) { 772 Object parentElement = d; 773 Object [] children; 774 if (isTreePathContentProvider() && widget instanceof Item) { 775 TreePath path = getTreePathFromItem((Item) widget); 776 children = getSortedChildren(path); 777 } else { 778 children = getSortedChildren(parentElement); 779 } 780 for (int i = 0; i < children.length; i++) { 781 createTreeItem(widget, children[i], -1); 782 } 783 } 784 } 785 786 }); 787 } finally { 788 busy = oldBusy; 789 } 790 } 791 792 804 protected void createTreeItem(Widget parent, Object element, int index) { 805 Item item = newItem(parent, SWT.NULL, index); 806 updateItem(item, element); 807 updatePlus(item, element); 808 } 809 810 814 protected void disassociate(Item item) { 815 super.disassociate(item); 816 if (usingElementMap()) { 820 disassociateChildren(item); 821 } 822 } 823 824 831 private void disassociateChildren(Item item) { 832 Item[] items = getChildren(item); 833 for (int i = 0; i < items.length; i++) { 834 if (items[i].getData() != null) { 835 disassociat
|