Mercurial > projects > dwt-addons
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 } |