comparison dwtx/jface/viewers/AbstractTreeViewer.d @ 70:46a6e0e6ccd4

Merge with d-fied sources of 3.4M7
author Frank Benoit <benoit@tionex.de>
date Thu, 22 May 2008 01:36:46 +0200
parents a6683645b0d7
children 4878bef4a38e
comparison
equal deleted inserted replaced
69:07b9d96fd764 70:46a6e0e6ccd4
1 /******************************************************************************* 1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 IBM Corporation and others. 2 * Copyright (c) 2000, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials 3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0 4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at 5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html 6 * http://www.eclipse.org/legal/epl-v10.html
7 * 7 *
8 * Contributors: 8 * Contributors:
9 * IBM Corporation - initial API and implementation 9 * IBM Corporation - initial API and implementation
10 * Tom Schindl <tom.schindl@bestsolution.at> - bug 153993, bug 167323, bug 175192 10 * Tom Schindl <tom.schindl@bestsolution.at> - bug 153993, bug 167323, bug 175192
11 * Lasse Knudsen, bug 205700
12 * Micah Hainline, bug 210448
13 * Michael Schneider, bug 210747
14 * Bruce Sutton, bug 221768
15 * Matthew Hall, bug 221988
11 * Port to the D programming language: 16 * Port to the D programming language:
12 * Frank Benoit <benoit@tionex.de> 17 * Frank Benoit <benoit@tionex.de>
13 *******************************************************************************/ 18 *******************************************************************************/
14 19
15 module dwtx.jface.viewers.AbstractTreeViewer; 20 module dwtx.jface.viewers.AbstractTreeViewer;
158 * the child elements to add 163 * the child elements to add
159 */ 164 */
160 public void add(Object parentElementOrTreePath, Object[] childElements) { 165 public void add(Object parentElementOrTreePath, Object[] childElements) {
161 Assert.isNotNull(parentElementOrTreePath); 166 Assert.isNotNull(parentElementOrTreePath);
162 assertElementsNotNull(childElements); 167 assertElementsNotNull(childElements);
163 if (isBusy()) 168 if (checkBusy())
164 return; 169 return;
165 Widget[] widgets = internalFindItems(parentElementOrTreePath); 170 Widget[] widgets = internalFindItems(parentElementOrTreePath);
166 // If parent hasn't been realized yet, just ignore the add. 171 // If parent hasn't been realized yet, just ignore the add.
167 if (widgets.length is 0) { 172 if (widgets.length is 0) {
168 return; 173 return;
344 349
345 ViewerComparator comparator = getComparator(); 350 ViewerComparator comparator = getComparator();
346 TreePath parentPath = internalGetSorterParentPath(widget, comparator); 351 TreePath parentPath = internalGetSorterParentPath(widget, comparator);
347 Item[] items = getChildren(widget); 352 Item[] items = getChildren(widget);
348 353
349 // As the items are sorted already we optimize for a
350 // start position
351 int lastInsertion = 0;
352
353 // Optimize for the empty case 354 // Optimize for the empty case
354 if (items.length is 0) { 355 if (items.length is 0) {
355 for (int i = 0; i < elements.length; i++) { 356 for (int i = 0; i < elements.length; i++) {
356 createTreeItem(widget, elements[i], -1); 357 createTreeItem(widget, elements[i], -1);
357 } 358 }
358 return; 359 return;
359 } 360 }
360 361
361 for (int i = 0; i < elements.length; i++) { 362 // Optimize for no comparator
362 bool newItem = true; 363 if (comparator is null) {
363 Object element = elements[i]; 364 for (int i = 0; i < elements.length; i++) {
364 int index; 365 Object element = elements[i];
365 if (comparator is null) {
366 if (itemExists(items, element)) { 366 if (itemExists(items, element)) {
367 internalRefresh(element); 367 internalRefresh(element);
368 newItem = false; 368 } else {
369 } 369 createTreeItem(widget, element, -1);
370 index = -1; 370 }
371 }
372 return;
373 }
374 // As the items are sorted already we optimize for a
375 // start position. This is the insertion position relative to the
376 // original item array.
377 int indexInItems = 0;
378
379 // Count of elements we have added. See bug 205700 for why this is needed.
380 int newItems = 0;
381
382 elementloop: for (int i = 0; i < elements.length; i++) {
383 Object element = elements[i];
384 // update the index relative to the original item array
385 indexInItems = insertionPosition(items, comparator,
386 indexInItems, element, parentPath);
387 if (indexInItems is items.length) {
388 createTreeItem(widget, element, -1);
389 newItems++;
371 } else { 390 } else {
372 lastInsertion = insertionPosition(items, comparator, 391 // Search for an item for the element. The comparator might
373 lastInsertion, element, parentPath); 392 // regard elements as equal when they are not.
374 // As we are only searching the original array we keep track of 393
375 // those positions only 394 // Use a separate index variable to search within the existing
376 if (lastInsertion is items.length) { 395 // elements that compare equally, see
377 index = -1; 396 // TreeViewerTestBug205700.testAddEquallySortedElements.
378 } else {// See if we should just refresh 397 int insertionIndexInItems = indexInItems;
379 while (lastInsertion < items.length 398 while( insertionIndexInItems < items.length
380 && internalCompare(comparator, parentPath, element, 399 && internalCompare(comparator, parentPath, element,
381 items[lastInsertion].getData()) is 0) { 400 items[insertionIndexInItems].getData()) is 0) {
382 // As we cannot assume the sorter is consistent with 401 // As we cannot assume the sorter is consistent with
383 // equals() - therefore we can 402 // equals() - therefore we can
384 // just check against the item prior to this index (if 403 // just check against the item prior to this index (if
385 // any) 404 // any)
386 if (items[lastInsertion].getData().opEquals(element)) { 405 if (items[insertionIndexInItems].getData().opEquals(element)) {
387 // refresh the element in case it has new children 406 // Found the item for the element.
388 internalRefresh(element); 407 // Refresh the element in case it has new children.
389 newItem = false; 408 internalRefresh(element);
390 } 409 // Do not create a new item - continue with the next element.
391 lastInsertion++;// We had an insertion so increment 410 continue elementloop;
392 } 411 }
393 // Did we get to the end? 412 insertionIndexInItems++;
394 if (lastInsertion is items.length) { 413 }
395 index = -1; 414 // Did we get to the end?
396 } else { 415 if (insertionIndexInItems is items.length) {
397 index = lastInsertion + i; // Add the index as the 416 createTreeItem(widget, element, -1);
398 // array is growing 417 newItems++;
399 } 418 } else {
400 } 419 // InsertionIndexInItems is the index in the original array. We
401 } 420 // need to correct by the number of new items we have
402 if (newItem) { 421 // created. See bug 205700.
403 createTreeItem(widget, element, index); 422 createTreeItem(widget, element, insertionIndexInItems + newItems);
423 newItems++;
424 }
404 } 425 }
405 } 426 }
406 } 427 }
407 428
408 /** 429 /**
767 * 788 *
768 * @param widget 789 * @param widget
769 * the widget 790 * the widget
770 */ 791 */
771 protected void createChildren(Widget widget) { 792 protected void createChildren(Widget widget) {
772 bool oldBusy = busy; 793 bool oldBusy = isBusy();
773 busy = true; 794 setBusy(true);
774 try { 795 try {
775 Item[] tis = getChildren(widget); 796 Item[] tis = getChildren(widget);
776 if (tis !is null && tis.length > 0) { 797 if (tis !is null && tis.length > 0) {
777 Object data = tis[0].getData(); 798 Object data = tis[0].getData();
778 if (data !is null) { 799 if (data !is null) {
817 } 838 }
818 } 839 }
819 840
820 }); 841 });
821 } finally { 842 } finally {
822 busy = oldBusy; 843 setBusy(oldBusy);
823 } 844 }
824 } 845 }
825 846
826 /** 847 /**
827 * Creates a single item for the given parent and synchronizes it with the 848 * Creates a single item for the given parent and synchronizes it with the
1000 1021
1001 1022
1002 1023
1003 /* (non-Javadoc) Method declared on StructuredViewer. */ 1024 /* (non-Javadoc) Method declared on StructuredViewer. */
1004 protected override void doUpdateItem(Widget widget, Object element, bool fullMap) { 1025 protected override void doUpdateItem(Widget widget, Object element, bool fullMap) {
1005 bool oldBusy = busy; 1026 bool oldBusy = isBusy();
1006 busy = true; 1027 setBusy(true);
1007 try { 1028 try {
1008 if ( auto item = cast(Item)widget ) { 1029 if ( auto item = cast(Item)widget ) {
1009 1030
1010 // ensure that back pointer is correct 1031 // ensure that back pointer is correct
1011 if (fullMap) { 1032 if (fullMap) {
1021 1042
1022 // update icon and label 1043 // update icon and label
1023 SafeRunnable.run(new UpdateItemSafeRunnable(item, element)); 1044 SafeRunnable.run(new UpdateItemSafeRunnable(item, element));
1024 } 1045 }
1025 } finally { 1046 } finally {
1026 busy = oldBusy; 1047 setBusy(oldBusy);
1027 } 1048 }
1028 } 1049 }
1029 1050
1030 /** 1051 /**
1031 * Expands all nodes of the viewer's tree, starting with the root. This 1052 * Expands all nodes of the viewer's tree, starting with the root. This
1056 * @param level 1077 * @param level
1057 * non-negative level, or <code>ALL_LEVELS</code> to expand all 1078 * non-negative level, or <code>ALL_LEVELS</code> to expand all
1058 * levels of the tree 1079 * levels of the tree
1059 */ 1080 */
1060 public void expandToLevel(Object elementOrTreePath, int level) { 1081 public void expandToLevel(Object elementOrTreePath, int level) {
1061 if (isBusy()) 1082 if (checkBusy())
1062 return; 1083 return;
1063 Widget w = internalExpand(elementOrTreePath, true); 1084 Widget w = internalExpand(elementOrTreePath, true);
1064 if (w !is null) { 1085 if (w !is null) {
1065 internalExpandToLevel(w, level); 1086 internalExpandToLevel(w, level);
1066 } 1087 }
1074 * the tree expansion event 1095 * the tree expansion event
1075 * @see ITreeViewerListener#treeCollapsed 1096 * @see ITreeViewerListener#treeCollapsed
1076 */ 1097 */
1077 protected void fireTreeCollapsed(TreeExpansionEvent event) { 1098 protected void fireTreeCollapsed(TreeExpansionEvent event) {
1078 Object[] listeners = treeListeners.getListeners(); 1099 Object[] listeners = treeListeners.getListeners();
1079 for (int i = 0; i < listeners.length; ++i) { 1100 bool oldBusy = isBusy();
1080 SafeRunnable.run(new class(event,cast(ITreeViewerListener) listeners[i]) SafeRunnable { 1101 setBusy(true);
1081 TreeExpansionEvent event_; 1102 try {
1082 ITreeViewerListener l; 1103 for (int i = 0; i < listeners.length; ++i) {
1083 this(TreeExpansionEvent a,ITreeViewerListener b){ 1104 SafeRunnable.run(new class(event,cast(ITreeViewerListener) listeners[i]) SafeRunnable {
1084 event_=a; 1105 TreeExpansionEvent event_;
1085 l = b; 1106 ITreeViewerListener l;
1086 } 1107 this(TreeExpansionEvent a,ITreeViewerListener b){
1087 public void run() { 1108 event_=a;
1088 l.treeCollapsed(event_); 1109 l = b;
1089 } 1110 }
1090 }); 1111 public void run() {
1112 l.treeCollapsed(event_);
1113 }
1114 });
1115 }
1116 } finally {
1117 setBusy(oldBusy);
1091 } 1118 }
1092 } 1119 }
1093 1120
1094 /** 1121 /**
1095 * Fires a tree expanded event. Only listeners registered at the time this 1122 * Fires a tree expanded event. Only listeners registered at the time this
1099 * the tree expansion event 1126 * the tree expansion event
1100 * @see ITreeViewerListener#treeExpanded 1127 * @see ITreeViewerListener#treeExpanded
1101 */ 1128 */
1102 protected void fireTreeExpanded(TreeExpansionEvent event) { 1129 protected void fireTreeExpanded(TreeExpansionEvent event) {
1103 Object[] listeners = treeListeners.getListeners(); 1130 Object[] listeners = treeListeners.getListeners();
1104 for (int i = 0; i < listeners.length; ++i) { 1131 bool oldBusy = isBusy();
1105 SafeRunnable.run(new class( event, cast(ITreeViewerListener) listeners[i]) SafeRunnable { 1132 setBusy(true);
1106 TreeExpansionEvent event_; 1133 try {
1107 ITreeViewerListener l; 1134 for (int i = 0; i < listeners.length; ++i) {
1108 this(TreeExpansionEvent a,ITreeViewerListener b){ 1135 SafeRunnable.run(new class( event, cast(ITreeViewerListener) listeners[i]) SafeRunnable {
1109 event_=a; 1136 TreeExpansionEvent event_;
1110 l = b; 1137 ITreeViewerListener l;
1111 } 1138 this(TreeExpansionEvent a,ITreeViewerListener b){
1112 public void run() { 1139 event_=a;
1113 l.treeExpanded(event_); 1140 l = b;
1114 } 1141 }
1115 }); 1142 public void run() {
1116 } 1143 l.treeExpanded(event_);
1117 1144 }
1145 });
1146 }
1147 } finally {
1148 setBusy(oldBusy);
1149 }
1118 } 1150 }
1119 1151
1120 /** 1152 /**
1121 * Returns the auto-expand level. 1153 * Returns the auto-expand level.
1122 * 1154 *
1321 return null; 1353 return null;
1322 } 1354 }
1323 1355
1324 /* (non-Javadoc) Method declared on StructuredViewer. */ 1356 /* (non-Javadoc) Method declared on StructuredViewer. */
1325 protected override Object[] getRawChildren(Object parentElementOrTreePath) { 1357 protected override Object[] getRawChildren(Object parentElementOrTreePath) {
1326 bool oldBusy = busy; 1358 bool oldBusy = isBusy();
1327 busy = true; 1359 setBusy(true);
1328 try { 1360 try {
1329 Object parent; 1361 Object parent;
1330 TreePath path; 1362 TreePath path;
1331 if ( auto p = cast(TreePath)parentElementOrTreePath ) { 1363 if ( auto p = cast(TreePath)parentElementOrTreePath ) {
1332 path = p; 1364 path = p;
1362 } 1394 }
1363 } 1395 }
1364 } 1396 }
1365 return null; 1397 return null;
1366 } finally { 1398 } finally {
1367 busy = oldBusy; 1399 setBusy(oldBusy);
1368 } 1400 }
1369 } 1401 }
1370 1402
1371 /** 1403 /**
1372 * Returns all selected items for the given DWT control. 1404 * Returns all selected items for the given DWT control.
1473 */ 1505 */
1474 protected override void inputChanged(Object input, Object oldInput) { 1506 protected override void inputChanged(Object input, Object oldInput) {
1475 preservingSelection(new class Runnable { 1507 preservingSelection(new class Runnable {
1476 public void run() { 1508 public void run() {
1477 Control tree = getControl(); 1509 Control tree = getControl();
1478 bool useRedraw = true; 1510 tree.setRedraw(false);
1479 // (size > REDRAW_THRESHOLD) || (table.getItemCount() > 1511 try {
1480 // REDRAW_THRESHOLD); 1512 removeAll(tree);
1481 if (useRedraw) { 1513 tree.setData(getRoot());
1482 tree.setRedraw(false); 1514 internalInitializeTree(tree);
1483 } 1515 } finally {
1484 removeAll(tree);
1485 tree.setData(getRoot());
1486 internalInitializeTree(tree);
1487 if (useRedraw) {
1488 tree.setRedraw(true); 1516 tree.setRedraw(true);
1489 } 1517 }
1490 } 1518 }
1491
1492 }); 1519 });
1493 } 1520 }
1494 1521
1495 /** 1522 /**
1496 * Initializes the tree with root items, expanding to the appropriate 1523 * Initializes the tree with root items, expanding to the appropriate
1643 IContentProvider cp = getContentProvider(); 1670 IContentProvider cp = getContentProvider();
1644 if ( auto tpcp = cast(ITreePathContentProvider)cp ) { 1671 if ( auto tpcp = cast(ITreePathContentProvider)cp ) {
1645 TreePath[] paths = tpcp.getParents(elementOrTreePath); 1672 TreePath[] paths = tpcp.getParents(elementOrTreePath);
1646 if (paths.length > 0) { 1673 if (paths.length > 0) {
1647 if (paths[0].getSegmentCount() is 0) { 1674 if (paths[0].getSegmentCount() is 0) {
1648 return getInput(); 1675 return getRoot();
1649 } 1676 }
1650 return paths[0].getLastSegment(); 1677 return paths[0].getLastSegment();
1651 } 1678 }
1652 } 1679 }
1653 if ( auto tcp = cast(ITreeContentProvider) cp ) { 1680 if ( auto tcp = cast(ITreeContentProvider) cp ) {
1894 if (opEquals(element, input)) { 1921 if (opEquals(element, input)) {
1895 setInput(null); 1922 setInput(null);
1896 return; 1923 return;
1897 } 1924 }
1898 Widget[] childItems = internalFindItems(element); 1925 Widget[] childItems = internalFindItems(element);
1899 for (int j = 0; j < childItems.length; j++) { 1926 if (childItems.length > 0) {
1900 Widget childItem = childItems[j]; 1927 for (int j = 0; j < childItems.length; j++) {
1901 if ( auto it = cast(Item)childItem ) { 1928 Widget childItem = childItems[j];
1902 disassociate(it); 1929 if ( auto it = cast(Item)childItem ) {
1903 childItem.dispose(); 1930 disassociate(it);
1931 childItem.dispose();
1932 }
1933 }
1934 } else {
1935 // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=210747
1936 Object parent = getParentElement(element);
1937 if (parent !is null
1938 && !equals(parent, getRoot())
1939 && !(parent instanceof TreePath && ((TreePath) parent)
1940 .getSegmentCount() is 0)) {
1941 Widget[] parentItems = internalFindItems(parent);
1942 for (int j = 0; j < parentItems.length; j++) {
1943 Widget parentItem = parentItems[j];
1944 if (parentItem instanceof Item) {
1945 updatePlus((Item) parentItem, parent);
1946 }
1947 }
1904 } 1948 }
1905 } 1949 }
1906 } 1950 }
1907 } 1951 }
1908 1952
1925 // Find each place the parent appears in the tree 1969 // Find each place the parent appears in the tree
1926 Widget[] parentItemArray = findItems(parent); 1970 Widget[] parentItemArray = findItems(parent);
1927 for (int i = 0; i < parentItemArray.length; i++) { 1971 for (int i = 0; i < parentItemArray.length; i++) {
1928 Widget parentItem = parentItemArray[i]; 1972 Widget parentItem = parentItemArray[i];
1929 1973
1974 // May happen if parent element is a descendent of of a previously
1975 // removed element
1976 if (parentItem.isDisposed())
1977 continue;
1978
1930 // Iterate over the child items and remove each one 1979 // Iterate over the child items and remove each one
1931 Item[] children = getChildren(parentItem); 1980 Item[] children = getChildren(parentItem);
1932 1981
1933 for (int j = 0; j < children.length; j++) { 1982 if (children.length is 1 && children[0].getData() is null &&
1934 Item child = children[j]; 1983 parentItem instanceof Item) { // dummy node
1935 1984 // Remove plus if parent element has no children
1936 Object data = child.getData(); 1985 updatePlus((Item) parentItem, parent);
1937 if (data !is null && toRemove.containsKey(data)) { 1986 } else {
1938 disassociate(child); 1987 for (int j = 0; j < children.length; j++) {
1939 child.dispose(); 1988 Item child = children[j];
1989
1990 Object data = child.getData();
1991 if (data !is null && toRemove.containsKey(data)) {
1992 disassociate(child);
1993 child.dispose();
1994 }
1940 } 1995 }
1941 } 1996 }
1942 } 1997 }
1943 } 1998 }
1944 1999
2117 public void remove(Object[] elementsOrTreePaths) { 2172 public void remove(Object[] elementsOrTreePaths) {
2118 assertElementsNotNull(elementsOrTreePaths); 2173 assertElementsNotNull(elementsOrTreePaths);
2119 if (elementsOrTreePaths.length is 0) { 2174 if (elementsOrTreePaths.length is 0) {
2120 return; 2175 return;
2121 } 2176 }
2122 if (isBusy()) 2177 if (checkBusy())
2123 return; 2178 return;
2124 preservingSelection(new class(elementsOrTreePaths) Runnable { 2179 preservingSelection(new class(elementsOrTreePaths) Runnable {
2125 Object[] elementsOrTreePaths_; 2180 Object[] elementsOrTreePaths_;
2126 this(Object[] a){ 2181 this(Object[] a){
2127 elementsOrTreePaths_=a; 2182 elementsOrTreePaths_=a;
2153 public void remove(Object parent, Object[] elements) { 2208 public void remove(Object parent, Object[] elements) {
2154 assertElementsNotNull(elements); 2209 assertElementsNotNull(elements);
2155 if (elements.length is 0) { 2210 if (elements.length is 0) {
2156 return; 2211 return;
2157 } 2212 }
2158 if (isBusy()) 2213 if (checkBusy())
2159 return; 2214 return;
2160 preservingSelection(new class(parent,elements) Runnable { 2215 preservingSelection(new class(parent,elements) Runnable {
2161 Object parent_; 2216 Object parent_;
2162 Object[] elements_; 2217 Object[] elements_;
2163 this(Object a,Object[] b){ 2218 this(Object a,Object[] b){
2256 } 2311 }
2257 return null; 2312 return null;
2258 } 2313 }
2259 2314
2260 /** 2315 /**
2261 * Sets the auto-expand level. The value 0 means that there is no 2316 * Sets the auto-expand level to be used when the input of the viewer is set
2262 * auto-expand; 1 means that top-level elements are expanded, but not their 2317 * using {@link #setInput(Object)}. The value 0 means that there is no
2263 * children; 2 means that top-level elements are expanded, and their 2318 * auto-expand; 1 means that the invisible root element is expanded (since
2264 * children, but not grandchildren; and so on. 2319 * most concrete subclasses do not show the root element, there is usually
2320 * no practical difference between using the values 0 and 1); 2 means that
2321 * top-level elements are expanded, but not their children; 3 means that
2322 * top-level elements are expanded, and their children, but not
2323 * grandchildren; and so on.
2265 * <p> 2324 * <p>
2266 * The value <code>ALL_LEVELS</code> means that all subtrees should be 2325 * The value <code>ALL_LEVELS</code> means that all subtrees should be
2267 * expanded. 2326 * expanded.
2327 * </p>
2328 * <p>
2329 * Note that in previous releases, the Javadoc for this method had an off-by
2330 * one error. See bug 177669 for details.
2268 * </p> 2331 * </p>
2269 * 2332 *
2270 * @param level 2333 * @param level
2271 * non-negative level, or <code>ALL_LEVELS</code> to expand all 2334 * non-negative level, or <code>ALL_LEVELS</code> to expand all
2272 * levels of the tree 2335 * levels of the tree
2313 * the array of expanded elements 2376 * the array of expanded elements
2314 * @see #getExpandedElements 2377 * @see #getExpandedElements
2315 */ 2378 */
2316 public void setExpandedElements(Object[] elements) { 2379 public void setExpandedElements(Object[] elements) {
2317 assertElementsNotNull(elements); 2380 assertElementsNotNull(elements);
2318 if (isBusy()) { 2381 if (checkBusy()) {
2319 return; 2382 return;
2320 } 2383 }
2321 CustomHashtable expandedElements = newHashtable(elements.length * 2 + 1); 2384 CustomHashtable expandedElements = newHashtable(elements.length * 2 + 1);
2322 for (int i = 0; i < elements.length; ++i) { 2385 for (int i = 0; i < elements.length; ++i) {
2323 Object element = elements[i]; 2386 Object element = elements[i];
2350 * 2413 *
2351 * @since 3.2 2414 * @since 3.2
2352 */ 2415 */
2353 public void setExpandedTreePaths(TreePath[] treePaths) { 2416 public void setExpandedTreePaths(TreePath[] treePaths) {
2354 assertElementsNotNull(treePaths); 2417 assertElementsNotNull(treePaths);
2355 if (isBusy()) 2418 if (checkBusy())
2356 return; 2419 return;
2357 IElementComparer treePathComparer = new class(getComparer()) IElementComparer { 2420 IElementComparer treePathComparer = new class(getComparer()) IElementComparer {
2358 IElementComparer comparer; 2421 IElementComparer comparer;
2359 this(IElementComparer c){ 2422 this(IElementComparer c){
2360 comparer = c; 2423 comparer = c;
2396 * <code>true</code> if the node is expanded, and 2459 * <code>true</code> if the node is expanded, and
2397 * <code>false</code> if collapsed 2460 * <code>false</code> if collapsed
2398 */ 2461 */
2399 public void setExpandedState(Object elementOrTreePath, bool expanded) { 2462 public void setExpandedState(Object elementOrTreePath, bool expanded) {
2400 Assert.isNotNull(elementOrTreePath); 2463 Assert.isNotNull(elementOrTreePath);
2401 if (isBusy()) 2464 if (checkBusy())
2402 return; 2465 return;
2403 Widget item = internalExpand(elementOrTreePath, false); 2466 Widget item = internalExpand(elementOrTreePath, false);
2404 if ( cast(Item)item ) { 2467 if ( cast(Item)item ) {
2405 if (expanded) { 2468 if (expanded) {
2406 createChildren(item); 2469 createChildren(item);
2450 } 2513 }
2451 setSelection(newSelection); 2514 setSelection(newSelection);
2452 2515
2453 // Although setting the selection in the control should reveal it, 2516 // Although setting the selection in the control should reveal it,
2454 // setSelection may be a no-op if the selection is unchanged, 2517 // setSelection may be a no-op if the selection is unchanged,
2455 // so explicitly reveal the first item in the selection here. 2518 // so explicitly reveal items in the selection here.
2456 // See bug 100565 for more details. 2519 // See bug 100565 for more details.
2457 if (reveal && newSelection.size() > 0) { 2520 if (reveal && newSelection.size() > 0) {
2458 showItem(cast(Item) newSelection.get(0)); 2521 // Iterate backwards so the first item in the list
2522 // is the one guaranteed to be visible
2523 for (int i = (newSelection.size()-1); i >= 0; i--) {
2524 showItem(cast(Item) newSelection.get(i));
2525 }
2459 } 2526 }
2460 } 2527 }
2461 2528
2462 /** 2529 /**
2463 * Shows the given item. 2530 * Shows the given item.
2550 int oldCnt = -1; 2617 int oldCnt = -1;
2551 if (widget is tree) { 2618 if (widget is tree) {
2552 oldCnt = getItemCount(tree); 2619 oldCnt = getItemCount(tree);
2553 } 2620 }
2554 2621
2555 Item[] items = getChildren(widget); 2622 Item[] items = getChildren(widget,elementChildren);
2556 2623
2557 // save the expanded elements 2624 // save the expanded elements
2558 CustomHashtable expanded = newHashtable(CustomHashtable.DEFAULT_CAPACITY); // assume 2625 CustomHashtable expanded = newHashtable(CustomHashtable.DEFAULT_CAPACITY); // assume
2559 // num 2626 // num
2560 // expanded 2627 // expanded
2561 // is 2628 // is
2698 tree.setRedraw(true); 2765 tree.setRedraw(true);
2699 } 2766 }
2700 } 2767 }
2701 2768
2702 /** 2769 /**
2770 * Return the items to be refreshed as part of an update. elementChildren are the
2771 * new elements.
2772 * @param widget
2773 * @param elementChildren
2774 * @since 3.4
2775 * @return Item[]
2776 * <strong>NOTE:</strong> This API is experimental and may be deleted
2777 * before 3.4 is released.
2778 */
2779 public Item[] getChildren(Widget widget, Object[] elementChildren) {
2780 return getChildren(widget);
2781 }
2782
2783 /**
2703 * Updates the "+"/"-" icon of the tree node from the given element. It 2784 * Updates the "+"/"-" icon of the tree node from the given element. It
2704 * calls <code>isExpandable</code> to determine whether an element is 2785 * calls <code>isExpandable</code> to determine whether an element is
2705 * expandable. 2786 * expandable.
2706 * 2787 *
2707 * @param item 2788 * @param item
2889 */ 2970 */
2890 public void insert(Object parentElementOrTreePath, Object element, 2971 public void insert(Object parentElementOrTreePath, Object element,
2891 int position) { 2972 int position) {
2892 Assert.isNotNull(parentElementOrTreePath); 2973 Assert.isNotNull(parentElementOrTreePath);
2893 Assert.isNotNull(element); 2974 Assert.isNotNull(element);
2894 if (isBusy()) 2975 if (checkBusy())
2895 return; 2976 return;
2896 if (getComparator() !is null || hasFilters()) { 2977 if (getComparator() !is null || hasFilters()) {
2897 add(parentElementOrTreePath, [ element ]); 2978 add(parentElementOrTreePath, [ element ]);
2898 return; 2979 return;
2899 } 2980 }
2916 if (insertionPosition is -1) { 2997 if (insertionPosition is -1) {
2917 insertionPosition = getItemCount(item); 2998 insertionPosition = getItemCount(item);
2918 } 2999 }
2919 3000
2920 createTreeItem(item, element, insertionPosition); 3001 createTreeItem(item, element, insertionPosition);
3002 } else {
3003 Object parentElement = parentElementOrTreePath;
3004 if (element instanceof TreePath)
3005 parentElement = ((TreePath) parentElement).getLastSegment();
3006 updatePlus(item, parentElement);
2921 } 3007 }
2922 } else { 3008 } else {
2923 int insertionPosition = position; 3009 int insertionPosition = position;
2924 if (insertionPosition is -1) { 3010 if (insertionPosition is -1) {
2925 insertionPosition = getItemCount(cast(Control) widget); 3011 insertionPosition = getItemCount(cast(Control) widget);
3008 * @return <code>true</code> if the given object is either the input or an empty tree path, 3094 * @return <code>true</code> if the given object is either the input or an empty tree path,
3009 * <code>false</code> otherwise. 3095 * <code>false</code> otherwise.
3010 * @since 3.3 3096 * @since 3.3
3011 */ 3097 */
3012 final protected bool internalIsInputOrEmptyPath(Object elementOrTreePath) { 3098 final protected bool internalIsInputOrEmptyPath(Object elementOrTreePath) {
3013 if (elementOrTreePath.opEquals(getInput())) 3099 if (elementOrTreePath.opEquals(getRoot()))
3014 return true; 3100 return true;
3015 if (!(cast(TreePath)elementOrTreePath )) 3101 if (!(cast(TreePath)elementOrTreePath ))
3016 return false; 3102 return false;
3017 return (cast(TreePath) elementOrTreePath).getSegmentCount() is 0; 3103 return (cast(TreePath) elementOrTreePath).getSegmentCount() is 0;
3018 } 3104 }