Source Code Cross Referenced for AbstractTreeViewer.java in  » IDE-Eclipse » jface » org » eclipse » jface » viewers » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Eclipse » jface » org.eclipse.jface.viewers 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * Copyright (c) 2000, 2007 IBM Corporation and others.
0003:         * All rights reserved. This program and the accompanying materials
0004:         * are made available under the terms of the Eclipse Public License v1.0
0005:         * which accompanies this distribution, and is available at
0006:         * http://www.eclipse.org/legal/epl-v10.html
0007:         *
0008:         * Contributors:
0009:         *     IBM Corporation - initial API and implementation
0010:         *     Tom Schindl <tom.schindl@bestsolution.at> - bug 153993, bug 167323, bug 175192
0011:         *******************************************************************************/package org.eclipse.jface.viewers;
0012:
0013:        import java.util.ArrayList;
0014:        import java.util.Arrays;
0015:        import java.util.Iterator;
0016:        import java.util.LinkedList;
0017:        import java.util.List;
0018:
0019:        import org.eclipse.core.runtime.Assert;
0020:        import org.eclipse.core.runtime.ListenerList;
0021:        import org.eclipse.jface.util.SafeRunnable;
0022:        import org.eclipse.swt.SWT;
0023:        import org.eclipse.swt.custom.BusyIndicator;
0024:        import org.eclipse.swt.events.SelectionEvent;
0025:        import org.eclipse.swt.events.SelectionListener;
0026:        import org.eclipse.swt.events.TreeEvent;
0027:        import org.eclipse.swt.events.TreeListener;
0028:        import org.eclipse.swt.graphics.Point;
0029:        import org.eclipse.swt.widgets.Control;
0030:        import org.eclipse.swt.widgets.Item;
0031:        import org.eclipse.swt.widgets.Widget;
0032:
0033:        /**
0034:         * Abstract base implementation for tree-structure-oriented viewers (trees and
0035:         * table trees).
0036:         * <p>
0037:         * Nodes in the tree can be in either an expanded or a collapsed state,
0038:         * depending on whether the children on a node are visible. This class
0039:         * introduces public methods for controlling the expanding and collapsing of
0040:         * nodes.
0041:         * </p>
0042:         * <p>
0043:         * As of 3.2, AbstractTreeViewer supports multiple equal elements (each with a
0044:         * different parent chain) in the tree. This support requires that clients
0045:         * enable the element map by calling <code>setUseHashLookup(true)</code>.
0046:         * </p>
0047:         * <p>
0048:         * Content providers for abstract tree viewers must implement one of the
0049:         * interfaces <code>ITreeContentProvider</code> or (as of 3.2, to support
0050:         * multiple equal elements) <code>ITreePathContentProvider</code>.
0051:         * </p>
0052:         * 
0053:         * @see TreeViewer
0054:         */
0055:        public abstract class AbstractTreeViewer extends ColumnViewer {
0056:
0057:            /**
0058:             * Constant indicating that all levels of the tree should be expanded or
0059:             * collapsed.
0060:             * 
0061:             * @see #expandToLevel(int)
0062:             * @see #collapseToLevel(Object, int)
0063:             */
0064:            public static final int ALL_LEVELS = -1;
0065:
0066:            /**
0067:             * List of registered tree listeners (element type:
0068:             * <code>TreeListener</code>).
0069:             */
0070:            private ListenerList treeListeners = new ListenerList();
0071:
0072:            /**
0073:             * The level to which the tree is automatically expanded each time the
0074:             * viewer's input is changed (that is, by <code>setInput</code>). A value
0075:             * of 0 means that auto-expand is off.
0076:             * 
0077:             * @see #setAutoExpandLevel
0078:             */
0079:            private int expandToLevel = 0;
0080:
0081:            /**
0082:             * Safe runnable used to update an item.
0083:             */
0084:            class UpdateItemSafeRunnable extends SafeRunnable {
0085:                private Object element;
0086:
0087:                private Item item;
0088:
0089:                UpdateItemSafeRunnable(Item item, Object element) {
0090:                    this .item = item;
0091:                    this .element = element;
0092:                }
0093:
0094:                public void run() {
0095:                    doUpdateItem(item, element);
0096:                }
0097:
0098:            }
0099:
0100:            /**
0101:             * Creates an abstract tree viewer. The viewer has no input, no content
0102:             * provider, a default label provider, no sorter, no filters, and has
0103:             * auto-expand turned off.
0104:             */
0105:            protected AbstractTreeViewer() {
0106:                // do nothing
0107:            }
0108:
0109:            /**
0110:             * Adds the given child elements to this viewer as children of the given
0111:             * parent element. If this viewer does not have a sorter, the elements are
0112:             * added at the end of the parent's list of children in the order given;
0113:             * otherwise, the elements are inserted at the appropriate positions.
0114:             * <p>
0115:             * This method should be called (by the content provider) when elements have
0116:             * been added to the model, in order to cause the viewer to accurately
0117:             * reflect the model. This method only affects the viewer, not the model.
0118:             * </p>
0119:             * 
0120:             * @param parentElementOrTreePath
0121:             *            the parent element
0122:             * @param childElements
0123:             *            the child elements to add
0124:             */
0125:            public void add(Object parentElementOrTreePath,
0126:                    Object[] childElements) {
0127:                Assert.isNotNull(parentElementOrTreePath);
0128:                assertElementsNotNull(childElements);
0129:                if (isBusy())
0130:                    return;
0131:                Widget[] widgets = internalFindItems(parentElementOrTreePath);
0132:                // If parent hasn't been realized yet, just ignore the add.
0133:                if (widgets.length == 0) {
0134:                    return;
0135:                }
0136:
0137:                for (int i = 0; i < widgets.length; i++) {
0138:                    internalAdd(widgets[i], parentElementOrTreePath,
0139:                            childElements);
0140:                }
0141:            }
0142:
0143:            /**
0144:             * Find the items for the given element of tree path
0145:             * 
0146:             * @param parentElementOrTreePath
0147:             *            the element or tree path
0148:             * @return the items for that element
0149:             *
0150:             * @since 3.3
0151:             */
0152:            final protected Widget[] internalFindItems(
0153:                    Object parentElementOrTreePath) {
0154:                Widget[] widgets;
0155:                if (parentElementOrTreePath instanceof  TreePath) {
0156:                    TreePath path = (TreePath) parentElementOrTreePath;
0157:                    Widget w = internalFindItem(path);
0158:                    if (w == null) {
0159:                        widgets = new Widget[] {};
0160:                    } else {
0161:                        widgets = new Widget[] { w };
0162:                    }
0163:                } else {
0164:                    widgets = findItems(parentElementOrTreePath);
0165:                }
0166:                return widgets;
0167:            }
0168:
0169:            /**
0170:             * Return the item at the given path or <code>null</code>
0171:             * 
0172:             * @param path
0173:             *            the path
0174:             * @return {@link Widget} the item at that path 
0175:             */
0176:            private Widget internalFindItem(TreePath path) {
0177:                Widget[] widgets = findItems(path.getLastSegment());
0178:                for (int i = 0; i < widgets.length; i++) {
0179:                    Widget widget = widgets[i];
0180:                    if (widget instanceof  Item) {
0181:                        Item item = (Item) widget;
0182:                        TreePath p = getTreePathFromItem(item);
0183:                        if (p.equals(path)) {
0184:                            return widget;
0185:                        }
0186:                    }
0187:                }
0188:                return null;
0189:            }
0190:
0191:            /**
0192:             * Adds the given child elements to this viewer as children of the given
0193:             * parent element.
0194:             * <p>
0195:             * EXPERIMENTAL. Not to be used except by JDT. This method was added to
0196:             * support JDT's explorations into grouping by working sets, which requires
0197:             * viewers to support multiple equal elements. See bug 76482 for more
0198:             * details. This support will likely be removed in Eclipse 3.2 in favor of
0199:             * proper support for multiple equal elements.
0200:             * </p>
0201:             * 
0202:             * @param widget
0203:             *            the widget for the parent element
0204:             * @param parentElementOrTreePath
0205:             *            the parent element
0206:             * @param childElements
0207:             *            the child elements to add
0208:             * @since 3.1
0209:             */
0210:            protected void internalAdd(Widget widget,
0211:                    Object parentElementOrTreePath, Object[] childElements) {
0212:                Object parent;
0213:                TreePath path;
0214:                if (parentElementOrTreePath instanceof  TreePath) {
0215:                    path = (TreePath) parentElementOrTreePath;
0216:                    parent = path.getLastSegment();
0217:                } else {
0218:                    parent = parentElementOrTreePath;
0219:                    path = null;
0220:                }
0221:
0222:                // optimization!
0223:                // if the widget is not expanded we just invalidate the subtree
0224:                if (widget instanceof  Item) {
0225:                    Item ti = (Item) widget;
0226:                    if (!getExpanded(ti)) {
0227:                        boolean needDummy = isExpandable(ti, path, parent);
0228:                        boolean haveDummy = false;
0229:                        // remove all children
0230:                        Item[] items = getItems(ti);
0231:                        for (int i = 0; i < items.length; i++) {
0232:                            if (items[i].getData() != null) {
0233:                                disassociate(items[i]);
0234:                                items[i].dispose();
0235:                            } else {
0236:                                if (needDummy && !haveDummy) {
0237:                                    haveDummy = true;
0238:                                } else {
0239:                                    items[i].dispose();
0240:                                }
0241:                            }
0242:                        }
0243:                        // append a dummy if necessary
0244:                        if (needDummy && !haveDummy) {
0245:                            newItem(ti, SWT.NULL, -1);
0246:                        }
0247:                        return;
0248:                    }
0249:                }
0250:
0251:                if (childElements.length > 0) {
0252:                    // TODO: Add filtering back?
0253:                    Object[] filtered = filter(parentElementOrTreePath,
0254:                            childElements);
0255:                    ViewerComparator comparator = getComparator();
0256:                    if (comparator != null) {
0257:                        if (comparator instanceof  TreePathViewerSorter) {
0258:                            TreePathViewerSorter tpvs = (TreePathViewerSorter) comparator;
0259:                            if (path == null) {
0260:                                path = internalGetSorterParentPath(widget,
0261:                                        comparator);
0262:                            }
0263:                            tpvs.sort(this , path, filtered);
0264:                        } else {
0265:                            comparator.sort(this , filtered);
0266:                        }
0267:                    }
0268:                    createAddedElements(widget, filtered);
0269:                }
0270:            }
0271:
0272:            /**
0273:             * Filter the children elements.
0274:             * 
0275:             * @param parentElementOrTreePath
0276:             *            the parent element or path
0277:             * @param elements
0278:             *            the child elements
0279:             * @return the filter list of children
0280:             */
0281:            private Object[] filter(Object parentElementOrTreePath,
0282:                    Object[] elements) {
0283:                ViewerFilter[] filters = getFilters();
0284:                if (filters != null) {
0285:                    ArrayList filtered = new ArrayList(elements.length);
0286:                    for (int i = 0; i < elements.length; i++) {
0287:                        boolean add = true;
0288:                        for (int j = 0; j < filters.length; j++) {
0289:                            add = filters[j].select(this ,
0290:                                    parentElementOrTreePath, elements[i]);
0291:                            if (!add) {
0292:                                break;
0293:                            }
0294:                        }
0295:                        if (add) {
0296:                            filtered.add(elements[i]);
0297:                        }
0298:                    }
0299:                    return filtered.toArray();
0300:                }
0301:                return elements;
0302:            }
0303:
0304:            /**
0305:             * Create the new elements in the parent widget. If the child already exists
0306:             * do nothing.
0307:             * 
0308:             * @param widget
0309:             * @param elements
0310:             *            Sorted list of elements to add.
0311:             */
0312:            private void createAddedElements(Widget widget, Object[] elements) {
0313:
0314:                if (elements.length == 1) {
0315:                    if (equals(elements[0], widget.getData())) {
0316:                        return;
0317:                    }
0318:                }
0319:
0320:                ViewerComparator comparator = getComparator();
0321:                TreePath parentPath = internalGetSorterParentPath(widget,
0322:                        comparator);
0323:                Item[] items = getChildren(widget);
0324:
0325:                // As the items are sorted already we optimize for a
0326:                // start position
0327:                int lastInsertion = 0;
0328:
0329:                // Optimize for the empty case
0330:                if (items.length == 0) {
0331:                    for (int i = 0; i < elements.length; i++) {
0332:                        createTreeItem(widget, elements[i], -1);
0333:                    }
0334:                    return;
0335:                }
0336:
0337:                for (int i = 0; i < elements.length; i++) {
0338:                    boolean newItem = true;
0339:                    Object element = elements[i];
0340:                    int index;
0341:                    if (comparator == null) {
0342:                        if (itemExists(items, element)) {
0343:                            internalRefresh(element);
0344:                            newItem = false;
0345:                        }
0346:                        index = -1;
0347:                    } else {
0348:                        lastInsertion = insertionPosition(items, comparator,
0349:                                lastInsertion, element, parentPath);
0350:                        // As we are only searching the original array we keep track of
0351:                        // those positions only
0352:                        if (lastInsertion == items.length) {
0353:                            index = -1;
0354:                        } else {// See if we should just refresh
0355:                            while (lastInsertion < items.length
0356:                                    && internalCompare(comparator, parentPath,
0357:                                            element, items[lastInsertion]
0358:                                                    .getData()) == 0) {
0359:                                // As we cannot assume the sorter is consistent with
0360:                                // equals() - therefore we can
0361:                                // just check against the item prior to this index (if
0362:                                // any)
0363:                                if (items[lastInsertion].getData().equals(
0364:                                        element)) {
0365:                                    // refresh the element in case it has new children
0366:                                    internalRefresh(element);
0367:                                    newItem = false;
0368:                                }
0369:                                lastInsertion++;// We had an insertion so increment
0370:                            }
0371:                            // Did we get to the end?
0372:                            if (lastInsertion == items.length) {
0373:                                index = -1;
0374:                            } else {
0375:                                index = lastInsertion + i; // Add the index as the
0376:                                // array is growing
0377:                            }
0378:                        }
0379:                    }
0380:                    if (newItem) {
0381:                        createTreeItem(widget, element, index);
0382:                    }
0383:                }
0384:            }
0385:
0386:            /**
0387:             * See if element is the data of one of the elements in items.
0388:             * 
0389:             * @param items
0390:             * @param element
0391:             * @return <code>true</code> if the element matches.
0392:             */
0393:            private boolean itemExists(Item[] items, Object element) {
0394:                if (usingElementMap()) {
0395:                    Widget[] existingItems = findItems(element);
0396:                    // optimization for two common cases
0397:                    if (existingItems.length == 0) {
0398:                        return false;
0399:                    } else if (existingItems.length == 1) {
0400:                        if (items.length > 0
0401:                                && existingItems[0] instanceof  Item) {
0402:                            Item existingItem = (Item) existingItems[0];
0403:                            return getParentItem(existingItem) == getParentItem(items[0]);
0404:                        }
0405:                    }
0406:                }
0407:                for (int i = 0; i < items.length; i++) {
0408:                    if (items[i].getData().equals(element)) {
0409:                        return true;
0410:                    }
0411:                }
0412:                return false;
0413:            }
0414:
0415:            /**
0416:             * Returns the index where the item should be inserted. It uses sorter to
0417:             * determine the correct position, if sorter is not assigned, returns the
0418:             * index of the element after the last.
0419:             * 
0420:             * @param items
0421:             *            the items to search
0422:             * @param comparator
0423:             *            The comparator to use.
0424:             * @param lastInsertion
0425:             *            the start index to start search for position from this allows
0426:             *            optimizing search for multiple elements that are sorted
0427:             *            themselves.
0428:             * @param element
0429:             *            element to find position for.
0430:             * @param parentPath
0431:             *            the tree path for the element's parent or <code>null</code>
0432:             *            if the element is a root element or the sorter is not a
0433:             *            {@link TreePathViewerSorter}
0434:             * @return the index to use when inserting the element.
0435:             * 
0436:             */
0437:
0438:            private int insertionPosition(Item[] items,
0439:                    ViewerComparator comparator, int lastInsertion,
0440:                    Object element, TreePath parentPath) {
0441:
0442:                int size = items.length;
0443:                if (comparator == null) {
0444:                    return size;
0445:                }
0446:                int min = lastInsertion, max = size - 1;
0447:
0448:                while (min <= max) {
0449:                    int mid = (min + max) / 2;
0450:                    Object data = items[mid].getData();
0451:                    int compare = internalCompare(comparator, parentPath, data,
0452:                            element);
0453:                    if (compare == 0) {
0454:                        return mid;// Return if we already match
0455:                    }
0456:                    if (compare < 0) {
0457:                        min = mid + 1;
0458:                    } else {
0459:                        max = mid - 1;
0460:                    }
0461:                }
0462:                return min;
0463:
0464:            }
0465:
0466:            /**
0467:             * Returns the index where the item should be inserted. It uses sorter to
0468:             * determine the correct position, if sorter is not assigned, returns the
0469:             * index of the element after the last.
0470:             * 
0471:             * @param parent
0472:             *            The parent widget
0473:             * @param sorter
0474:             *            The sorter to use.
0475:             * @param startIndex
0476:             *            the start index to start search for position from this allows
0477:             *            optimizing search for multiple elements that are sorted
0478:             *            themselves.
0479:             * @param element
0480:             *            element to find position for.
0481:             * @param currentSize
0482:             *            the current size of the collection
0483:             * @return the index to use when inserting the element.
0484:             * 
0485:             */
0486:
0487:            /**
0488:             * Returns the index where the item should be inserted.
0489:             * 
0490:             * @param parent
0491:             *            The parent widget the element will be inserted into.
0492:             * @param element
0493:             *            The element to insert.
0494:             * @return the index of the element
0495:             */
0496:            protected int indexForElement(Widget parent, Object element) {
0497:                ViewerComparator comparator = getComparator();
0498:                TreePath parentPath = internalGetSorterParentPath(parent,
0499:                        comparator);
0500:
0501:                Item[] items = getChildren(parent);
0502:                int count = items.length;
0503:
0504:                if (comparator == null) {
0505:                    return count;
0506:                }
0507:                int min = 0, max = count - 1;
0508:
0509:                while (min <= max) {
0510:                    int mid = (min + max) / 2;
0511:                    Object data = items[mid].getData();
0512:                    int compare = internalCompare(comparator, parentPath, data,
0513:                            element);
0514:                    if (compare == 0) {
0515:                        // find first item > element
0516:                        while (compare == 0) {
0517:                            ++mid;
0518:                            if (mid >= count) {
0519:                                break;
0520:                            }
0521:                            data = items[mid].getData();
0522:                            compare = internalCompare(comparator, parentPath,
0523:                                    data, element);
0524:                        }
0525:                        return mid;
0526:                    }
0527:                    if (compare < 0) {
0528:                        min = mid + 1;
0529:                    } else {
0530:                        max = mid - 1;
0531:                    }
0532:                }
0533:                return min;
0534:            }
0535:
0536:            /**
0537:             * Return the tree path that should be used as the parent path for the given
0538:             * widget and sorter. A <code>null</code> is returned if either the sorter
0539:             * is not a {@link TreePathViewerSorter} or if the parent widget is not an
0540:             * {@link Item} (i.e. is the root of the tree).
0541:             * 
0542:             * @param parent
0543:             *            the parent widget
0544:             * @param comparator
0545:             *            the sorter
0546:             * @return the tree path that should be used as the parent path for the
0547:             *         given widget and sorter
0548:             */
0549:            private TreePath internalGetSorterParentPath(Widget parent,
0550:                    ViewerComparator comparator) {
0551:                TreePath path;
0552:                if (comparator instanceof  TreePathViewerSorter
0553:                        && parent instanceof  Item) {
0554:                    Item item = (Item) parent;
0555:                    path = getTreePathFromItem(item);
0556:                } else {
0557:                    path = null;
0558:                }
0559:                return path;
0560:            }
0561:
0562:            /**
0563:             * Compare the two elements using the given sorter. If the sorter is a
0564:             * {@link TreePathViewerSorter}, the provided tree path will be used. If
0565:             * the tree path is null and the sorter is a tree path sorter, then the
0566:             * elements are root elements
0567:             * 
0568:             * @param comparator
0569:             *            the sorter
0570:             * @param parentPath
0571:             *            the path of the elements' parent
0572:             * @param e1
0573:             *            the first element
0574:             * @param e2
0575:             *            the second element
0576:             * @return the result of comparing the two elements
0577:             */
0578:            private int internalCompare(ViewerComparator comparator,
0579:                    TreePath parentPath, Object e1, Object e2) {
0580:                if (comparator instanceof  TreePathViewerSorter) {
0581:                    TreePathViewerSorter tpvs = (TreePathViewerSorter) comparator;
0582:                    return tpvs.compare(this , parentPath, e1, e2);
0583:                }
0584:                return comparator.compare(this , e1, e2);
0585:            }
0586:
0587:            /*
0588:             * (non-Javadoc)
0589:             * 
0590:             * @see org.eclipse.jface.viewers.StructuredViewer#getSortedChildren(java.lang.Object)
0591:             */
0592:            protected Object[] getSortedChildren(Object parentElementOrTreePath) {
0593:                Object[] result = getFilteredChildren(parentElementOrTreePath);
0594:                ViewerComparator comparator = getComparator();
0595:                if (parentElementOrTreePath != null
0596:                        && comparator instanceof  TreePathViewerSorter) {
0597:                    TreePathViewerSorter tpvs = (TreePathViewerSorter) comparator;
0598:
0599:                    // be sure we're not modifying the original array from the model
0600:                    result = (Object[]) result.clone();
0601:
0602:                    TreePath path = null;
0603:                    if (parentElementOrTreePath instanceof  TreePath) {
0604:                        path = (TreePath) parentElementOrTreePath;
0605:                    } else {
0606:                        Object parent = parentElementOrTreePath;
0607:                        Widget w = internalGetWidgetToSelect(parent);
0608:                        if (w != null) {
0609:                            path = internalGetSorterParentPath(w, comparator);
0610:                        }
0611:                    }
0612:                    tpvs.sort(this , path, result);
0613:                } else if (comparator != null) {
0614:                    // be sure we're not modifying the original array from the model
0615:                    result = (Object[]) result.clone();
0616:                    comparator.sort(this , result);
0617:                }
0618:                return result;
0619:            }
0620:
0621:            /*
0622:             * (non-Javadoc)
0623:             * 
0624:             * @see org.eclipse.jface.viewers.StructuredViewer#getFilteredChildren(java.lang.Object)
0625:             */
0626:            protected Object[] getFilteredChildren(
0627:                    Object parentElementOrTreePath) {
0628:                Object[] result = getRawChildren(parentElementOrTreePath);
0629:                ViewerFilter[] filters = getFilters();
0630:                for (int i = 0; i < filters.length; i++) {
0631:                    ViewerFilter filter = filters[i];
0632:                    result = filter.filter(this , parentElementOrTreePath,
0633:                            result);
0634:                }
0635:                return result;
0636:            }
0637:
0638:            /**
0639:             * Adds the given child element to this viewer as a child of the given
0640:             * parent element. If this viewer does not have a sorter, the element is
0641:             * added at the end of the parent's list of children; otherwise, the element
0642:             * is inserted at the appropriate position.
0643:             * <p>
0644:             * This method should be called (by the content provider) when a single
0645:             * element has been added to the model, in order to cause the viewer to
0646:             * accurately reflect the model. This method only affects the viewer, not
0647:             * the model. Note that there is another method for efficiently processing
0648:             * the simultaneous addition of multiple elements.
0649:             * </p>
0650:             * 
0651:             * @param parentElementOrTreePath
0652:             *            the parent element or path
0653:             * @param childElement
0654:             *            the child element
0655:             */
0656:            public void add(Object parentElementOrTreePath, Object childElement) {
0657:                add(parentElementOrTreePath, new Object[] { childElement });
0658:            }
0659:
0660:            /**
0661:             * Adds the given SWT selection listener to the given SWT control.
0662:             * 
0663:             * @param control
0664:             *            the SWT control
0665:             * @param listener
0666:             *            the SWT selection listener
0667:             * @deprecated
0668:             */
0669:            protected void addSelectionListener(Control control,
0670:                    SelectionListener listener) {
0671:                // do nothing
0672:            }
0673:
0674:            /**
0675:             * Adds a listener for expand and collapse events in this viewer. Has no
0676:             * effect if an identical listener is already registered.
0677:             * 
0678:             * @param listener
0679:             *            a tree viewer listener
0680:             */
0681:            public void addTreeListener(ITreeViewerListener listener) {
0682:                treeListeners.add(listener);
0683:            }
0684:
0685:            /**
0686:             * Adds the given SWT tree listener to the given SWT control.
0687:             * 
0688:             * @param control
0689:             *            the SWT control
0690:             * @param listener
0691:             *            the SWT tree listener
0692:             */
0693:            protected abstract void addTreeListener(Control control,
0694:                    TreeListener listener);
0695:
0696:            /*
0697:             * (non-Javadoc)
0698:             * 
0699:             * @see StructuredViewer#associate(Object, Item)
0700:             */
0701:            protected void associate(Object element, Item item) {
0702:                Object data = item.getData();
0703:                if (data != null && data != element && equals(data, element)) {
0704:                    // workaround for PR 1FV62BT
0705:                    // assumption: elements are equal but not identical
0706:                    // -> remove from map but don't touch children
0707:                    unmapElement(data, item);
0708:                    item.setData(element);
0709:                    mapElement(element, item);
0710:                } else {
0711:                    // recursively disassociate all
0712:                    super .associate(element, item);
0713:                }
0714:            }
0715:
0716:            /**
0717:             * Collapses all nodes of the viewer's tree, starting with the root. This
0718:             * method is equivalent to <code>collapseToLevel(ALL_LEVELS)</code>.
0719:             */
0720:            public void collapseAll() {
0721:                Object root = getRoot();
0722:                if (root != null) {
0723:                    collapseToLevel(root, ALL_LEVELS);
0724:                }
0725:            }
0726:
0727:            /**
0728:             * Collapses the subtree rooted at the given element or tree path to the
0729:             * given level.
0730:             * 
0731:             * @param elementOrTreePath
0732:             *            the element or tree path
0733:             * @param level
0734:             *            non-negative level, or <code>ALL_LEVELS</code> to collapse
0735:             *            all levels of the tree
0736:             */
0737:            public void collapseToLevel(Object elementOrTreePath, int level) {
0738:                Assert.isNotNull(elementOrTreePath);
0739:                Widget w = internalGetWidgetToSelect(elementOrTreePath);
0740:                if (w != null) {
0741:                    internalCollapseToLevel(w, level);
0742:                }
0743:            }
0744:
0745:            /**
0746:             * Creates all children for the given widget.
0747:             * <p>
0748:             * The default implementation of this framework method assumes that
0749:             * <code>widget.getData()</code> returns the element corresponding to the
0750:             * node. Note: the node is not visually expanded! You may have to call
0751:             * <code>parent.setExpanded(true)</code>.
0752:             * </p>
0753:             * 
0754:             * @param widget
0755:             *            the widget
0756:             */
0757:            protected void createChildren(final Widget widget) {
0758:                boolean oldBusy = busy;
0759:                busy = true;
0760:                try {
0761:                    final Item[] tis = getChildren(widget);
0762:                    if (tis != null && tis.length > 0) {
0763:                        Object data = tis[0].getData();
0764:                        if (data != null) {
0765:                            return; // children already there!
0766:                        }
0767:                    }
0768:
0769:                    BusyIndicator.showWhile(widget.getDisplay(),
0770:                            new Runnable() {
0771:                                public void run() {
0772:                                    // fix for PR 1FW89L7:
0773:                                    // don't complain and remove all "dummies" ...
0774:                                    if (tis != null) {
0775:                                        for (int i = 0; i < tis.length; i++) {
0776:                                            if (tis[i].getData() != null) {
0777:                                                disassociate(tis[i]);
0778:                                                Assert
0779:                                                        .isTrue(
0780:                                                                tis[i]
0781:                                                                        .getData() == null,
0782:                                                                "Second or later child is non -null");//$NON-NLS-1$
0783:
0784:                                            }
0785:                                            tis[i].dispose();
0786:                                        }
0787:                                    }
0788:                                    Object d = widget.getData();
0789:                                    if (d != null) {
0790:                                        Object parentElement = d;
0791:                                        Object[] children;
0792:                                        if (isTreePathContentProvider()
0793:                                                && widget instanceof  Item) {
0794:                                            TreePath path = getTreePathFromItem((Item) widget);
0795:                                            children = getSortedChildren(path);
0796:                                        } else {
0797:                                            children = getSortedChildren(parentElement);
0798:                                        }
0799:                                        for (int i = 0; i < children.length; i++) {
0800:                                            createTreeItem(widget, children[i],
0801:                                                    -1);
0802:                                        }
0803:                                    }
0804:                                }
0805:
0806:                            });
0807:                } finally {
0808:                    busy = oldBusy;
0809:                }
0810:            }
0811:
0812:            /**
0813:             * Creates a single item for the given parent and synchronizes it with the
0814:             * given element.
0815:             * 
0816:             * @param parent
0817:             *            the parent widget
0818:             * @param element
0819:             *            the element
0820:             * @param index
0821:             *            if non-negative, indicates the position to insert the item
0822:             *            into its parent
0823:             */
0824:            protected void createTreeItem(Widget parent, Object element,
0825:                    int index) {
0826:                Item item = newItem(parent, SWT.NULL, index);
0827:                updateItem(item, element);
0828:                updatePlus(item, element);
0829:            }
0830:
0831:            /**
0832:             * The <code>AbstractTreeViewer</code> implementation of this method also
0833:             * recurses over children of the corresponding element.
0834:             */
0835:            protected void disassociate(Item item) {
0836:                super .disassociate(item);
0837:                // recursively unmapping the items is only required when
0838:                // the hash map is used. In the other case disposing
0839:                // an item will recursively dispose its children.
0840:                if (usingElementMap()) {
0841:                    disassociateChildren(item);
0842:                }
0843:            }
0844:
0845:            /**
0846:             * Disassociates the children of the given SWT item from their corresponding
0847:             * elements.
0848:             * 
0849:             * @param item
0850:             *            the widget
0851:             */
0852:            private void disassociateChildren(Item item) {
0853:                Item[] items = getChildren(item);
0854:                for (int i = 0; i < items.length; i++) {
0855:                    if (items[i].getData() != null) {
0856:                        disassociate(items[i]);
0857:                    }
0858:                }
0859:            }
0860:
0861:            /* (non-Javadoc) Method declared on StructuredViewer. */
0862:            protected Widget doFindInputItem(Object element) {
0863:                // compare with root
0864:                Object root = getRoot();
0865:                if (root == null) {
0866:                    return null;
0867:                }
0868:
0869:                if (equals(root, element)) {
0870:                    return getControl();
0871:                }
0872:                return null;
0873:            }
0874:
0875:            /* (non-Javadoc) Method declared on StructuredViewer. */
0876:            protected Widget doFindItem(Object element) {
0877:                // compare with root
0878:                Object root = getRoot();
0879:                if (root == null) {
0880:                    return null;
0881:                }
0882:
0883:                Item[] items = getChildren(getControl());
0884:                if (items != null) {
0885:                    for (int i = 0; i < items.length; i++) {
0886:                        Widget o = internalFindItem(items[i], element);
0887:                        if (o != null) {
0888:                            return o;
0889:                        }
0890:                    }
0891:                }
0892:                return null;
0893:            }
0894:
0895:            /**
0896:             * Copies the attributes of the given element into the given SWT item.
0897:             * 
0898:             * @param item
0899:             *            the SWT item
0900:             * @param element
0901:             *            the element
0902:             */
0903:            protected void doUpdateItem(final Item item, Object element) {
0904:                if (item.isDisposed()) {
0905:                    unmapElement(element, item);
0906:                    return;
0907:                }
0908:
0909:                int columnCount = doGetColumnCount();
0910:                if (columnCount == 0)// If no columns are created then fake one
0911:                    columnCount = 1;
0912:
0913:                ViewerRow viewerRowFromItem = getViewerRowFromItem(item);
0914:
0915:                boolean isVirtual = (getControl().getStyle() & SWT.VIRTUAL) != 0;
0916:
0917:                // If the control is virtual, we cannot use the cached viewer row object. See bug 188663.
0918:                if (isVirtual) {
0919:                    viewerRowFromItem = (ViewerRow) viewerRowFromItem.clone();
0920:                }
0921:
0922:                for (int column = 0; column < columnCount; column++) {
0923:                    ViewerColumn columnViewer = getViewerColumn(column);
0924:                    ViewerCell cellToUpdate = updateCell(viewerRowFromItem,
0925:                            column, element);
0926:
0927:                    // If the control is virtual, we cannot use the cached cell object. See bug 188663.
0928:                    if (isVirtual) {
0929:                        cellToUpdate = new ViewerCell(cellToUpdate
0930:                                .getViewerRow(), cellToUpdate.getColumnIndex(),
0931:                                element);
0932:                    }
0933:
0934:                    columnViewer.refresh(cellToUpdate);
0935:
0936:                    // As it is possible for user code to run the event
0937:                    // loop check here.
0938:                    if (item.isDisposed()) {
0939:                        unmapElement(element, item);
0940:                        return;
0941:                    }
0942:
0943:                }
0944:            }
0945:
0946:            /**
0947:             * Returns <code>true</code> if the given list and array of items refer to
0948:             * the same model elements. Order is unimportant.
0949:             * <p>
0950:             * This method is not intended to be overridden by subclasses.
0951:             * </p>
0952:             * 
0953:             * @param items
0954:             *            the list of items
0955:             * @param current
0956:             *            the array of items
0957:             * @return <code>true</code> if the refer to the same elements,
0958:             *         <code>false</code> otherwise
0959:             * 
0960:             * @since 3.1 in TreeViewer, moved to AbstractTreeViewer in 3.3
0961:             */
0962:            protected boolean isSameSelection(List items, Item[] current) {
0963:                // If they are not the same size then they are not equivalent
0964:                int n = items.size();
0965:                if (n != current.length) {
0966:                    return false;
0967:                }
0968:
0969:                CustomHashtable itemSet = newHashtable(n * 2 + 1);
0970:                for (Iterator i = items.iterator(); i.hasNext();) {
0971:                    Item item = (Item) i.next();
0972:                    Object element = item.getData();
0973:                    itemSet.put(element, element);
0974:                }
0975:
0976:                // Go through the items of the current collection
0977:                // If there is a mismatch return false
0978:                for (int i = 0; i < current.length; i++) {
0979:                    if (current[i].getData() == null
0980:                            || !itemSet.containsKey(current[i].getData())) {
0981:                        return false;
0982:                    }
0983:                }
0984:
0985:                return true;
0986:            }
0987:
0988:            /* (non-Javadoc) Method declared on StructuredViewer. */
0989:            protected void doUpdateItem(Widget widget, Object element,
0990:                    boolean fullMap) {
0991:                boolean oldBusy = busy;
0992:                busy = true;
0993:                try {
0994:                    if (widget instanceof  Item) {
0995:                        Item item = (Item) widget;
0996:
0997:                        // ensure that back pointer is correct
0998:                        if (fullMap) {
0999:                            associate(element, item);
1000:                        } else {
1001:                            Object data = item.getData();
1002:                            if (data != null) {
1003:                                unmapElement(data, item);
1004:                            }
1005:                            item.setData(element);
1006:                            mapElement(element, item);
1007:                        }
1008:
1009:                        // update icon and label
1010:                        SafeRunnable.run(new UpdateItemSafeRunnable(item,
1011:                                element));
1012:                    }
1013:                } finally {
1014:                    busy = oldBusy;
1015:                }
1016:            }
1017:
1018:            /**
1019:             * Expands all nodes of the viewer's tree, starting with the root. This
1020:             * method is equivalent to <code>expandToLevel(ALL_LEVELS)</code>.
1021:             */
1022:            public void expandAll() {
1023:                expandToLevel(ALL_LEVELS);
1024:            }
1025:
1026:            /**
1027:             * Expands the root of the viewer's tree to the given level.
1028:             * 
1029:             * @param level
1030:             *            non-negative level, or <code>ALL_LEVELS</code> to expand all
1031:             *            levels of the tree
1032:             */
1033:            public void expandToLevel(int level) {
1034:                expandToLevel(getRoot(), level);
1035:            }
1036:
1037:            /**
1038:             * Expands all ancestors of the given element or tree path so that the given
1039:             * element becomes visible in this viewer's tree control, and then expands
1040:             * the subtree rooted at the given element to the given level.
1041:             * 
1042:             * @param elementOrTreePath
1043:             *            the element
1044:             * @param level
1045:             *            non-negative level, or <code>ALL_LEVELS</code> to expand all
1046:             *            levels of the tree
1047:             */
1048:            public void expandToLevel(Object elementOrTreePath, int level) {
1049:                if (isBusy())
1050:                    return;
1051:                Widget w = internalExpand(elementOrTreePath, true);
1052:                if (w != null) {
1053:                    internalExpandToLevel(w, level);
1054:                }
1055:            }
1056:
1057:            /**
1058:             * Fires a tree collapsed event. Only listeners registered at the time this
1059:             * method is called are notified.
1060:             * 
1061:             * @param event
1062:             *            the tree expansion event
1063:             * @see ITreeViewerListener#treeCollapsed
1064:             */
1065:            protected void fireTreeCollapsed(final TreeExpansionEvent event) {
1066:                Object[] listeners = treeListeners.getListeners();
1067:                boolean oldBusy = busy;
1068:                busy = true;
1069:                try {
1070:                    for (int i = 0; i < listeners.length; ++i) {
1071:                        final ITreeViewerListener l = (ITreeViewerListener) listeners[i];
1072:                        SafeRunnable.run(new SafeRunnable() {
1073:                            public void run() {
1074:                                l.treeCollapsed(event);
1075:                            }
1076:                        });
1077:                    }
1078:                } finally {
1079:                    busy = oldBusy;
1080:                }
1081:            }
1082:
1083:            /**
1084:             * Fires a tree expanded event. Only listeners registered at the time this
1085:             * method is called are notified.
1086:             * 
1087:             * @param event
1088:             *            the tree expansion event
1089:             * @see ITreeViewerListener#treeExpanded
1090:             */
1091:            protected void fireTreeExpanded(final TreeExpansionEvent event) {
1092:                Object[] listeners = treeListeners.getListeners();
1093:                boolean oldBusy = busy;
1094:                busy = true;
1095:                try {
1096:                    for (int i = 0; i < listeners.length; ++i) {
1097:                        final ITreeViewerListener l = (ITreeViewerListener) listeners[i];
1098:                        SafeRunnable.run(new SafeRunnable() {
1099:                            public void run() {
1100:                                l.treeExpanded(event);
1101:                            }
1102:                        });
1103:                    }
1104:                } finally {
1105:                    busy = oldBusy;
1106:                }
1107:            }
1108:
1109:            /**
1110:             * Returns the auto-expand level.
1111:             * 
1112:             * @return non-negative level, or <code>ALL_LEVELS</code> if all levels of
1113:             *         the tree are expanded automatically
1114:             * @see #setAutoExpandLevel
1115:             */
1116:            public int getAutoExpandLevel() {
1117:                return expandToLevel;
1118:            }
1119:
1120:            /**
1121:             * Returns the SWT child items for the given SWT widget.
1122:             * 
1123:             * @param widget
1124:             *            the widget
1125:             * @return the child items
1126:             */
1127:            protected abstract Item[] getChildren(Widget widget);
1128:
1129:            /**
1130:             * Get the child for the widget at index. Note that the default
1131:             * implementation is not very efficient and should be overridden if this
1132:             * class is implemented.
1133:             * 
1134:             * @param widget
1135:             *            the widget to check
1136:             * @param index
1137:             *            the index of the widget
1138:             * @return Item or <code>null</code> if widget is not a type that can
1139:             *         contain items.
1140:             * 
1141:             * @throws ArrayIndexOutOfBoundsException
1142:             *             if the index is not valid.
1143:             * @since 3.1
1144:             */
1145:            protected Item getChild(Widget widget, int index) {
1146:                return getChildren(widget)[index];
1147:            }
1148:
1149:            /**
1150:             * Returns whether the given SWT item is expanded or collapsed.
1151:             * 
1152:             * @param item
1153:             *            the item
1154:             * @return <code>true</code> if the item is considered expanded and
1155:             *         <code>false</code> if collapsed
1156:             */
1157:            protected abstract boolean getExpanded(Item item);
1158:
1159:            /**
1160:             * Returns a list of elements corresponding to expanded nodes in this
1161:             * viewer's tree, including currently hidden ones that are marked as
1162:             * expanded but are under a collapsed ancestor.
1163:             * <p>
1164:             * This method is typically used when preserving the interesting state of a
1165:             * viewer; <code>setExpandedElements</code> is used during the restore.
1166:             * </p>
1167:             * 
1168:             * @return the array of expanded elements
1169:             * @see #setExpandedElements
1170:             */
1171:            public Object[] getExpandedElements() {
1172:                ArrayList items = new ArrayList();
1173:                internalCollectExpandedItems(items, getControl());
1174:                ArrayList result = new ArrayList(items.size());
1175:                for (Iterator it = items.iterator(); it.hasNext();) {
1176:                    Item item = (Item) it.next();
1177:                    Object data = item.getData();
1178:                    if (data != null) {
1179:                        result.add(data);
1180:                    }
1181:                }
1182:                return result.toArray();
1183:            }
1184:
1185:            /**
1186:             * Returns whether the node corresponding to the given element or tree path
1187:             * is expanded or collapsed.
1188:             * 
1189:             * @param elementOrTreePath
1190:             *            the element
1191:             * @return <code>true</code> if the node is expanded, and
1192:             *         <code>false</code> if collapsed
1193:             */
1194:            public boolean getExpandedState(Object elementOrTreePath) {
1195:                Assert.isNotNull(elementOrTreePath);
1196:                Widget item = internalGetWidgetToSelect(elementOrTreePath);
1197:                if (item instanceof  Item) {
1198:                    return getExpanded((Item) item);
1199:                }
1200:                return false;
1201:            }
1202:
1203:            /**
1204:             * Returns the number of child items of the given SWT control.
1205:             * 
1206:             * @param control
1207:             *            the control
1208:             * @return the number of children
1209:             */
1210:            protected abstract int getItemCount(Control control);
1211:
1212:            /**
1213:             * Returns the number of child items of the given SWT item.
1214:             * 
1215:             * @param item
1216:             *            the item
1217:             * @return the number of children
1218:             */
1219:            protected abstract int getItemCount(Item item);
1220:
1221:            /**
1222:             * Returns the child items of the given SWT item.
1223:             * 
1224:             * @param item
1225:             *            the item
1226:             * @return the child items
1227:             */
1228:            protected abstract Item[] getItems(Item item);
1229:
1230:            /**
1231:             * Returns the item after the given item in the tree, or <code>null</code>
1232:             * if there is no next item.
1233:             * 
1234:             * @param item
1235:             *            the item
1236:             * @param includeChildren
1237:             *            <code>true</code> if the children are considered in
1238:             *            determining which item is next, and <code>false</code> if
1239:             *            subtrees are ignored
1240:             * @return the next item, or <code>null</code> if none
1241:             */
1242:            protected Item getNextItem(Item item, boolean includeChildren) {
1243:                if (item == null) {
1244:                    return null;
1245:                }
1246:                if (includeChildren && getExpanded(item)) {
1247:                    Item[] children = getItems(item);
1248:                    if (children != null && children.length > 0) {
1249:                        return children[0];
1250:                    }
1251:                }
1252:
1253:                // next item is either next sibling or next sibling of first
1254:                // parent that has a next sibling.
1255:                Item parent = getParentItem(item);
1256:                if (parent == null) {
1257:                    return null;
1258:                }
1259:                Item[] siblings = getItems(parent);
1260:                if (siblings != null) {
1261:                    if (siblings.length <= 1) {
1262:                        return getNextItem(parent, false);
1263:                    }
1264:
1265:                    for (int i = 0; i < siblings.length; i++) {
1266:                        if (siblings[i] == item && i < (siblings.length - 1)) {
1267:                            return siblings[i + 1];
1268:                        }
1269:                    }
1270:                }
1271:                return getNextItem(parent, false);
1272:            }
1273:
1274:            /**
1275:             * Returns the parent item of the given item in the tree, or
1276:             * <code>null</code> if there is no parent item.
1277:             * 
1278:             * @param item
1279:             *            the item
1280:             * @return the parent item, or <code>null</code> if none
1281:             */
1282:            protected abstract Item getParentItem(Item item);
1283:
1284:            /**
1285:             * Returns the item before the given item in the tree, or <code>null</code>
1286:             * if there is no previous item.
1287:             * 
1288:             * @param item
1289:             *            the item
1290:             * @return the previous item, or <code>null</code> if none
1291:             */
1292:            protected Item getPreviousItem(Item item) {
1293:                // previous item is either right-most visible descendent of previous
1294:                // sibling or parent
1295:                Item parent = getParentItem(item);
1296:                if (parent == null) {
1297:                    return null;
1298:                }
1299:                Item[] siblings = getItems(parent);
1300:                if (siblings.length == 0 || siblings[0] == item) {
1301:                    return parent;
1302:                }
1303:                Item previous = siblings[0];
1304:                for (int i = 1; i < siblings.length; i++) {
1305:                    if (siblings[i] == item) {
1306:                        return rightMostVisibleDescendent(previous);
1307:                    }
1308:                    previous = siblings[i];
1309:                }
1310:                return null;
1311:            }
1312:
1313:            /* (non-Javadoc) Method declared on StructuredViewer. */
1314:            protected Object[] getRawChildren(Object parentElementOrTreePath) {
1315:                boolean oldBusy = busy;
1316:                busy = true;
1317:                try {
1318:                    Object parent;
1319:                    TreePath path;
1320:                    if (parentElementOrTreePath instanceof  TreePath) {
1321:                        path = (TreePath) parentElementOrTreePath;
1322:                        parent = path.getLastSegment();
1323:                    } else {
1324:                        parent = parentElementOrTreePath;
1325:                        path = null;
1326:                    }
1327:                    if (parent != null) {
1328:                        if (equals(parent, getRoot())) {
1329:                            return super .getRawChildren(parent);
1330:                        }
1331:                        IContentProvider cp = getContentProvider();
1332:                        if (cp instanceof  ITreePathContentProvider) {
1333:                            ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
1334:                            if (path == null) {
1335:                                // A path was not provided so try and find one
1336:                                Widget w = findItem(parent);
1337:                                if (w instanceof  Item) {
1338:                                    Item item = (Item) w;
1339:                                    path = getTreePathFromItem(item);
1340:                                }
1341:                                if (path == null) {
1342:                                    path = new TreePath(new Object[] { parent });
1343:                                }
1344:                            }
1345:                            Object[] result = tpcp.getChildren(path);
1346:                            if (result != null) {
1347:                                return result;
1348:                            }
1349:                        } else if (cp instanceof  ITreeContentProvider) {
1350:                            ITreeContentProvider tcp = (ITreeContentProvider) cp;
1351:                            Object[] result = tcp.getChildren(parent);
1352:                            if (result != null) {
1353:                                return result;
1354:                            }
1355:                        }
1356:                    }
1357:                    return new Object[0];
1358:                } finally {
1359:                    busy = oldBusy;
1360:                }
1361:            }
1362:
1363:            /**
1364:             * Returns all selected items for the given SWT control.
1365:             * 
1366:             * @param control
1367:             *            the control
1368:             * @return the list of selected items
1369:             */
1370:            protected abstract Item[] getSelection(Control control);
1371:
1372:            /*
1373:             * (non-Javadoc)
1374:             * 
1375:             * @see org.eclipse.jface.viewers.StructuredViewer#getSelectionFromWidget()
1376:             */
1377:            protected List getSelectionFromWidget() {
1378:                Widget[] items = getSelection(getControl());
1379:                ArrayList list = new ArrayList(items.length);
1380:                for (int i = 0; i < items.length; i++) {
1381:                    Widget item = items[i];
1382:                    Object e = item.getData();
1383:                    if (e != null) {
1384:                        list.add(e);
1385:                    }
1386:                }
1387:                return list;
1388:            }
1389:
1390:            /*
1391:             * Overridden in AbstractTreeViewer to fix bug 108102 (code copied from
1392:             * StructuredViewer to avoid introducing new API) (non-Javadoc)
1393:             * 
1394:             * @see org.eclipse.jface.viewers.StructuredViewer#handleDoubleSelect(org.eclipse.swt.events.SelectionEvent)
1395:             */
1396:            protected void handleDoubleSelect(SelectionEvent event) {
1397:                // handle case where an earlier selection listener disposed the control.
1398:                Control control = getControl();
1399:                if (control != null && !control.isDisposed()) {
1400:                    // If the double-clicked element can be obtained from the event, use
1401:                    // it
1402:                    // otherwise get it from the control. Some controls like List do
1403:                    // not have the notion of item.
1404:                    // For details, see bug 90161 [Navigator] DefaultSelecting folders
1405:                    // shouldn't always expand first one
1406:                    ISelection selection;
1407:                    if (event.item != null && event.item.getData() != null) {
1408:
1409:                        // changes to fix bug 108102 follow
1410:                        TreePath treePath = getTreePathFromItem((Item) event.item);
1411:                        selection = new TreeSelection(treePath);
1412:                        // end of changes
1413:
1414:                    } else {
1415:                        selection = getSelection();
1416:                        updateSelection(selection);
1417:                    }
1418:                    fireDoubleClick(new DoubleClickEvent(this , selection));
1419:                }
1420:            }
1421:
1422:            /**
1423:             * Handles a tree collapse event from the SWT widget.
1424:             * 
1425:             * @param event
1426:             *            the SWT tree event
1427:             */
1428:            protected void handleTreeCollapse(TreeEvent event) {
1429:                if (event.item.getData() != null) {
1430:                    fireTreeCollapsed(new TreeExpansionEvent(this , event.item
1431:                            .getData()));
1432:                }
1433:            }
1434:
1435:            /**
1436:             * Handles a tree expand event from the SWT widget.
1437:             * 
1438:             * @param event
1439:             *            the SWT tree event
1440:             */
1441:            protected void handleTreeExpand(TreeEvent event) {
1442:                createChildren(event.item);
1443:                if (event.item.getData() != null) {
1444:                    fireTreeExpanded(new TreeExpansionEvent(this , event.item
1445:                            .getData()));
1446:                }
1447:            }
1448:
1449:            /* (non-Javadoc) Method declared on Viewer. */
1450:            protected void hookControl(Control control) {
1451:                super .hookControl(control);
1452:                addTreeListener(control, new TreeListener() {
1453:                    public void treeExpanded(TreeEvent event) {
1454:                        handleTreeExpand(event);
1455:                    }
1456:
1457:                    public void treeCollapsed(TreeEvent event) {
1458:                        handleTreeCollapse(event);
1459:                    }
1460:                });
1461:            }
1462:
1463:            /*
1464:             * (non-Javadoc) Method declared on StructuredViewer. Builds the initial
1465:             * tree and handles the automatic expand feature.
1466:             */
1467:            protected void inputChanged(Object input, Object oldInput) {
1468:                preservingSelection(new Runnable() {
1469:                    public void run() {
1470:                        Control tree = getControl();
1471:                        boolean useRedraw = true;
1472:                        // (size > REDRAW_THRESHOLD) || (table.getItemCount() >
1473:                        // REDRAW_THRESHOLD);
1474:                        if (useRedraw) {
1475:                            tree.setRedraw(false);
1476:                        }
1477:                        removeAll(tree);
1478:                        tree.setData(getRoot());
1479:                        internalInitializeTree(tree);
1480:                        if (useRedraw) {
1481:                            tree.setRedraw(true);
1482:                        }
1483:                    }
1484:
1485:                });
1486:            }
1487:
1488:            /**
1489:             * Initializes the tree with root items, expanding to the appropriate
1490:             * level if necessary.
1491:             *
1492:             * @param tree the tree control
1493:             * @since 3.3
1494:             */
1495:            protected void internalInitializeTree(Control tree) {
1496:                createChildren(tree);
1497:                internalExpandToLevel(tree, expandToLevel);
1498:            }
1499:
1500:            /**
1501:             * Recursively collapses the subtree rooted at the given widget to the given
1502:             * level.
1503:             * <p>
1504:             * </p>
1505:             * Note that the default implementation of this method does not call
1506:             * <code>setRedraw</code>.
1507:             * 
1508:             * @param widget
1509:             *            the widget
1510:             * @param level
1511:             *            non-negative level, or <code>ALL_LEVELS</code> to collapse
1512:             *            all levels of the tree
1513:             */
1514:            protected void internalCollapseToLevel(Widget widget, int level) {
1515:                if (level == ALL_LEVELS || level > 0) {
1516:
1517:                    if (widget instanceof  Item) {
1518:                        setExpanded((Item) widget, false);
1519:                    }
1520:
1521:                    if (level == ALL_LEVELS || level > 1) {
1522:                        Item[] children = getChildren(widget);
1523:                        if (children != null) {
1524:                            int nextLevel = (level == ALL_LEVELS ? ALL_LEVELS
1525:                                    : level - 1);
1526:                            for (int i = 0; i < children.length; i++) {
1527:                                internalCollapseToLevel(children[i], nextLevel);
1528:                            }
1529:                        }
1530:                    }
1531:                }
1532:            }
1533:
1534:            /**
1535:             * Recursively collects all expanded items from the given widget.
1536:             * 
1537:             * @param result
1538:             *            a list (element type: <code>Item</code>) into which to
1539:             *            collect the elements
1540:             * @param widget
1541:             *            the widget
1542:             */
1543:            private void internalCollectExpandedItems(List result, Widget widget) {
1544:                Item[] items = getChildren(widget);
1545:                for (int i = 0; i < items.length; i++) {
1546:                    Item item = items[i];
1547:                    if (getExpanded(item)) {
1548:                        result.add(item);
1549:                    }
1550:                    internalCollectExpandedItems(result, item);
1551:                }
1552:            }
1553:
1554:            /**
1555:             * Tries to create a path of tree items for the given element or tree path.
1556:             * This method recursively walks up towards the root of the tree and in the
1557:             * case of an element (rather than a tree path) assumes that
1558:             * <code>getParent</code> returns the correct parent of an element.
1559:             * 
1560:             * @param elementOrPath
1561:             *            the element
1562:             * @param expand
1563:             *            <code>true</code> if all nodes on the path should be
1564:             *            expanded, and <code>false</code> otherwise
1565:             * @return Widget
1566:             */
1567:            protected Widget internalExpand(Object elementOrPath, boolean expand) {
1568:
1569:                if (elementOrPath == null) {
1570:                    return null;
1571:                }
1572:
1573:                Widget w = internalGetWidgetToSelect(elementOrPath);
1574:                if (w == null) {
1575:                    if (equals(elementOrPath, getRoot())) { // stop at root
1576:                        return null;
1577:                    }
1578:                    // my parent has to create me
1579:                    Object parent = getParentElement(elementOrPath);
1580:                    if (parent != null) {
1581:                        Widget pw = internalExpand(parent, false);
1582:                        if (pw != null) {
1583:                            // let my parent create me
1584:                            createChildren(pw);
1585:                            Object element = internalToElement(elementOrPath);
1586:                            w = internalFindChild(pw, element);
1587:                            if (expand && pw instanceof  Item) {
1588:                                // expand parent items top-down
1589:                                Item item = (Item) pw;
1590:                                LinkedList toExpandList = new LinkedList();
1591:                                while (item != null && !getExpanded(item)) {
1592:                                    toExpandList.addFirst(item);
1593:                                    item = getParentItem(item);
1594:                                }
1595:                                for (Iterator it = toExpandList.iterator(); it
1596:                                        .hasNext();) {
1597:                                    Item toExpand = (Item) it.next();
1598:                                    setExpanded(toExpand, true);
1599:                                }
1600:                            }
1601:                        }
1602:                    }
1603:                }
1604:                return w;
1605:            }
1606:
1607:            /**
1608:             * If the argument is a tree path, returns its last segment, otherwise
1609:             * return the argument
1610:             * 
1611:             * @param elementOrPath
1612:             *            an element or a tree path
1613:             * @return the element, or the last segment of the tree path
1614:             */
1615:            private Object internalToElement(Object elementOrPath) {
1616:                if (elementOrPath instanceof  TreePath) {
1617:                    return ((TreePath) elementOrPath).getLastSegment();
1618:                }
1619:                return elementOrPath;
1620:            }
1621:
1622:            /**
1623:             * This method takes a tree path or an element. If the argument is not a
1624:             * tree path, returns the parent of the given element or <code>null</code>
1625:             * if the parent is not known. If the argument is a tree path with more than
1626:             * one segment, returns its parent tree path, otherwise returns
1627:             * <code>null</code>.
1628:             * 
1629:             * @param elementOrTreePath
1630:             * @return the parent element, or parent path, or <code>null</code>
1631:             * 
1632:             * @since 3.2
1633:             */
1634:            protected Object getParentElement(Object elementOrTreePath) {
1635:                if (elementOrTreePath instanceof  TreePath) {
1636:                    TreePath treePath = (TreePath) elementOrTreePath;
1637:                    return (treePath).getParentPath();
1638:                }
1639:                IContentProvider cp = getContentProvider();
1640:                if (cp instanceof  ITreePathContentProvider) {
1641:                    ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
1642:                    TreePath[] paths = tpcp.getParents(elementOrTreePath);
1643:                    if (paths.length > 0) {
1644:                        if (paths[0].getSegmentCount() == 0) {
1645:                            return getInput();
1646:                        }
1647:                        return paths[0].getLastSegment();
1648:                    }
1649:                }
1650:                if (cp instanceof  ITreeContentProvider) {
1651:                    ITreeContentProvider tcp = (ITreeContentProvider) cp;
1652:                    return tcp.getParent(elementOrTreePath);
1653:                }
1654:                return null;
1655:            }
1656:
1657:            /**
1658:             * Returns the widget to be selected for the given element or tree path.
1659:             * 
1660:             * @param elementOrTreePath
1661:             *            the element or tree path to select
1662:             * @return the widget to be selected, or <code>null</code> if not found
1663:             * 
1664:             * @since 3.1
1665:             */
1666:            protected Widget internalGetWidgetToSelect(Object elementOrTreePath) {
1667:                if (elementOrTreePath instanceof  TreePath) {
1668:                    TreePath treePath = (TreePath) elementOrTreePath;
1669:                    if (treePath.getSegmentCount() == 0) {
1670:                        return getControl();
1671:                    }
1672:                    Widget[] candidates = findItems(treePath.getLastSegment());
1673:                    for (int i = 0; i < candidates.length; i++) {
1674:                        Widget candidate = candidates[i];
1675:                        if (!(candidate instanceof  Item)) {
1676:                            continue;
1677:                        }
1678:                        if (treePath.equals(
1679:                                getTreePathFromItem((Item) candidate),
1680:                                getComparer())) {
1681:                            return candidate;
1682:                        }
1683:                    }
1684:                    return null;
1685:                }
1686:                return findItem(elementOrTreePath);
1687:            }
1688:
1689:            /**
1690:             * Recursively expands the subtree rooted at the given widget to the given
1691:             * level.
1692:             * <p>
1693:             * </p>
1694:             * Note that the default implementation of this method does not call
1695:             * <code>setRedraw</code>.
1696:             * 
1697:             * @param widget
1698:             *            the widget
1699:             * @param level
1700:             *            non-negative level, or <code>ALL_LEVELS</code> to collapse
1701:             *            all levels of the tree
1702:             */
1703:            protected void internalExpandToLevel(Widget widget, int level) {
1704:                if (level == ALL_LEVELS || level > 0) {
1705:                    if (widget instanceof  Item
1706:                            && widget.getData() != null
1707:                            && !isExpandable((Item) widget, null, widget
1708:                                    .getData())) {
1709:                        return;
1710:                    }
1711:                    createChildren(widget);
1712:                    if (widget instanceof  Item) {
1713:                        setExpanded((Item) widget, true);
1714:                    }
1715:                    if (level == ALL_LEVELS || level > 1) {
1716:                        Item[] children = getChildren(widget);
1717:                        if (children != null) {
1718:                            int newLevel = (level == ALL_LEVELS ? ALL_LEVELS
1719:                                    : level - 1);
1720:                            for (int i = 0; i < children.length; i++) {
1721:                                internalExpandToLevel(children[i], newLevel);
1722:                            }
1723:                        }
1724:                    }
1725:                }
1726:            }
1727:
1728:            /**
1729:             * Non-recursively tries to find the given element as a child of the given
1730:             * parent (item or tree).
1731:             * 
1732:             * @param parent
1733:             *            the parent item
1734:             * @param element
1735:             *            the element
1736:             * @return Widget
1737:             */
1738:            private Widget internalFindChild(Widget parent, Object element) {
1739:                Item[] items = getChildren(parent);
1740:                for (int i = 0; i < items.length; i++) {
1741:                    Item item = items[i];
1742:                    Object data = item.getData();
1743:                    if (data != null && equals(data, element)) {
1744:                        return item;
1745:                    }
1746:                }
1747:                return null;
1748:            }
1749:
1750:            /**
1751:             * Recursively tries to find the given element.
1752:             * 
1753:             * @param parent
1754:             *            the parent item
1755:             * @param element
1756:             *            the element
1757:             * @return Widget
1758:             */
1759:            private Widget internalFindItem(Item parent, Object element) {
1760:
1761:                // compare with node
1762:                Object data = parent.getData();
1763:                if (data != null) {
1764:                    if (equals(data, element)) {
1765:                        return parent;
1766:                    }
1767:                }
1768:                // recurse over children
1769:                Item[] items = getChildren(parent);
1770:                for (int i = 0; i < items.length; i++) {
1771:                    Item item = items[i];
1772:                    Widget o = internalFindItem(item, element);
1773:                    if (o != null) {
1774:                        return o;
1775:                    }
1776:                }
1777:                return null;
1778:            }
1779:
1780:            /* (non-Javadoc) Method declared on StructuredViewer. */
1781:            protected void internalRefresh(Object element) {
1782:                internalRefresh(element, true);
1783:            }
1784:
1785:            /* (non-Javadoc) Method declared on StructuredViewer. */
1786:            protected void internalRefresh(Object element, boolean updateLabels) {
1787:                // If element is null, do a full refresh.
1788:                if (element == null) {
1789:                    internalRefresh(getControl(), getRoot(), true, updateLabels);
1790:                    return;
1791:                }
1792:                Widget[] items = findItems(element);
1793:                if (items.length != 0) {
1794:                    for (int i = 0; i < items.length; i++) {
1795:                        // pick up structure changes too
1796:                        internalRefresh(items[i], element, true, updateLabels);
1797:                    }
1798:                }
1799:            }
1800:
1801:            /**
1802:             * Refreshes the tree starting at the given widget.
1803:             * <p>
1804:             * EXPERIMENTAL. Not to be used except by JDT. This method was added to
1805:             * support JDT's explorations into grouping by working sets, which requires
1806:             * viewers to support multiple equal elements. See bug 76482 for more
1807:             * details. This support will likely be removed in Eclipse 3.2 in favor of
1808:             * proper support for multiple equal elements.
1809:             * </p>
1810:             * 
1811:             * @param widget
1812:             *            the widget
1813:             * @param element
1814:             *            the element
1815:             * @param doStruct
1816:             *            <code>true</code> if structural changes are to be picked up,
1817:             *            and <code>false</code> if only label provider changes are of
1818:             *            interest
1819:             * @param updateLabels
1820:             *            <code>true</code> to update labels for existing elements,
1821:             *            <code>false</code> to only update labels as needed, assuming
1822:             *            that labels for existing elements are unchanged.
1823:             * @since 3.1
1824:             */
1825:            protected void internalRefresh(Widget widget, Object element,
1826:                    boolean doStruct, boolean updateLabels) {
1827:
1828:                if (widget instanceof  Item) {
1829:                    if (doStruct) {
1830:                        updatePlus((Item) widget, element);
1831:                    }
1832:                    if (updateLabels || !equals(element, widget.getData())) {
1833:                        doUpdateItem(widget, element, true);
1834:                    } else {
1835:                        associate(element, (Item) widget);
1836:                    }
1837:                }
1838:
1839:                if (doStruct) {
1840:                    internalRefreshStruct(widget, element, updateLabels);
1841:                } else {
1842:                    Item[] children = getChildren(widget);
1843:                    if (children != null) {
1844:                        for (int i = 0; i < children.length; i++) {
1845:                            Widget item = children[i];
1846:                            Object data = item.getData();
1847:                            if (data != null) {
1848:                                internalRefresh(item, data, doStruct,
1849:                                        updateLabels);
1850:                            }
1851:                        }
1852:                    }
1853:                }
1854:            }
1855:
1856:            /**
1857:             * Update the structure and recurse. Items are updated in updateChildren, as
1858:             * needed.
1859:             * 
1860:             * @param widget
1861:             * @param element
1862:             * @param updateLabels
1863:             */
1864:            /* package */void internalRefreshStruct(Widget widget,
1865:                    Object element, boolean updateLabels) {
1866:                updateChildren(widget, element, null, updateLabels);
1867:                Item[] children = getChildren(widget);
1868:                if (children != null) {
1869:                    for (int i = 0; i < children.length; i++) {
1870:                        Widget item = children[i];
1871:                        Object data = item.getData();
1872:                        if (data != null) {
1873:                            internalRefreshStruct(item, data, updateLabels);
1874:                        }
1875:                    }
1876:                }
1877:            }
1878:
1879:            /**
1880:             * Removes the given elements from this viewer.
1881:             * <p>
1882:             * EXPERIMENTAL. Not to be used except by JDT. This method was added to
1883:             * support JDT's explorations into grouping by working sets, which requires
1884:             * viewers to support multiple equal elements. See bug 76482 for more
1885:             * details. This support will likely be removed in Eclipse 3.2 in favor of
1886:             * proper support for multiple equal elements.
1887:             * </p>
1888:             * 
1889:             * @param elementsOrPaths
1890:             *            the elements or element paths to remove
1891:             * @since 3.1
1892:             */
1893:            protected void internalRemove(Object[] elementsOrPaths) {
1894:                Object input = getInput();
1895:                for (int i = 0; i < elementsOrPaths.length; ++i) {
1896:                    Object element = elementsOrPaths[i];
1897:                    if (equals(element, input)) {
1898:                        setInput(null);
1899:                        return;
1900:                    }
1901:                    Widget[] childItems = internalFindItems(element);
1902:                    for (int j = 0; j < childItems.length; j++) {
1903:                        Widget childItem = childItems[j];
1904:                        if (childItem instanceof  Item) {
1905:                            disassociate((Item) childItem);
1906:                            childItem.dispose();
1907:                        }
1908:                    }
1909:                }
1910:            }
1911:
1912:            /**
1913:             * Removes the given elements from this viewer, whenever those elements
1914:             * appear as children of the given parent.
1915:             * 
1916:             * @param parent the parent element
1917:             * @param elements
1918:             *            the elements to remove
1919:             * @since 3.1
1920:             */
1921:            protected void internalRemove(Object parent, Object[] elements) {
1922:
1923:                CustomHashtable toRemove = new CustomHashtable(getComparer());
1924:                for (int i = 0; i < elements.length; i++) {
1925:                    toRemove.put(elements[i], elements[i]);
1926:                }
1927:
1928:                // Find each place the parent appears in the tree
1929:                Widget[] parentItemArray = findItems(parent);
1930:                for (int i = 0; i < parentItemArray.length; i++) {
1931:                    Widget parentItem = parentItemArray[i];
1932:
1933:                    // Iterate over the child items and remove each one
1934:                    Item[] children = getChildren(parentItem);
1935:
1936:                    for (int j = 0; j < children.length; j++) {
1937:                        Item child = children[j];
1938:
1939:                        Object data = child.getData();
1940:                        if (data != null && toRemove.containsKey(data)) {
1941:                            disassociate(child);
1942:                            child.dispose();
1943:                        }
1944:                    }
1945:                }
1946:            }
1947:
1948:            /**
1949:             * Sets the expanded state of all items to correspond to the given set of
1950:             * expanded elements.
1951:             * 
1952:             * @param expandedElements
1953:             *            the set (element type: <code>Object</code>) of elements
1954:             *            which are expanded
1955:             * @param widget
1956:             *            the widget
1957:             */
1958:            private void internalSetExpanded(CustomHashtable expandedElements,
1959:                    Widget widget) {
1960:                Item[] items = getChildren(widget);
1961:                for (int i = 0; i < items.length; i++) {
1962:                    Item item = items[i];
1963:                    Object data = item.getData();
1964:                    if (data != null) {
1965:                        // remove the element to avoid an infinite loop
1966:                        // if the same element appears on a child item
1967:                        boolean expanded = expandedElements.remove(data) != null;
1968:                        if (expanded != getExpanded(item)) {
1969:                            if (expanded) {
1970:                                createChildren(item);
1971:                            }
1972:                            setExpanded(item, expanded);
1973:                        }
1974:                    }
1975:                    if (expandedElements.size() > 0) {
1976:                        internalSetExpanded(expandedElements, item);
1977:                    }
1978:                }
1979:            }
1980:
1981:            /**
1982:             * Sets the expanded state of all items to correspond to the given set of
1983:             * expanded tree paths.
1984:             * 
1985:             * @param expandedTreePaths
1986:             *            the set (element type: <code>TreePath</code>) of elements
1987:             *            which are expanded
1988:             * @param widget
1989:             *            the widget
1990:             */
1991:            private void internalSetExpandedTreePaths(
1992:                    CustomHashtable expandedTreePaths, Widget widget,
1993:                    TreePath currentPath) {
1994:                Item[] items = getChildren(widget);
1995:                for (int i = 0; i < items.length; i++) {
1996:                    Item item = items[i];
1997:                    Object data = item.getData();
1998:                    TreePath childPath = data == null ? null : currentPath
1999:                            .createChildPath(data);
2000:                    if (data != null && childPath != null) {
2001:                        // remove the element to avoid an infinite loop
2002:                        // if the same element appears on a child item
2003:                        boolean expanded = expandedTreePaths.remove(childPath) != null;
2004:                        if (expanded != getExpanded(item)) {
2005:                            if (expanded) {
2006:                                createChildren(item);
2007:                            }
2008:                            setExpanded(item, expanded);
2009:                        }
2010:                    }
2011:                    internalSetExpandedTreePaths(expandedTreePaths, item,
2012:                            childPath);
2013:                }
2014:            }
2015:
2016:            /**
2017:             * Return whether the tree node representing the given element or path can
2018:             * be expanded. Clients should query expandability by path if the viewer's
2019:             * content provider is an {@link ITreePathContentProvider}.
2020:             * <p>
2021:             * The default implementation of this framework method calls
2022:             * <code>hasChildren</code> on this viewer's content provider. It may be
2023:             * overridden if necessary.
2024:             * </p>
2025:             * 
2026:             * @param elementOrTreePath
2027:             *            the element or path
2028:             * @return <code>true</code> if the tree node representing the given
2029:             *         element can be expanded, or <code>false</code> if not
2030:             */
2031:            public boolean isExpandable(Object elementOrTreePath) {
2032:                Object element;
2033:                TreePath path;
2034:                if (elementOrTreePath instanceof  TreePath) {
2035:                    path = (TreePath) elementOrTreePath;
2036:                    element = path.getLastSegment();
2037:                } else {
2038:                    element = elementOrTreePath;
2039:                    path = null;
2040:                }
2041:                IContentProvider cp = getContentProvider();
2042:                if (cp instanceof  ITreePathContentProvider) {
2043:                    ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
2044:                    if (path == null) {
2045:                        // A path was not provided so try and find one
2046:                        Widget w = findItem(element);
2047:                        if (w instanceof  Item) {
2048:                            Item item = (Item) w;
2049:                            path = getTreePathFromItem(item);
2050:                        }
2051:                        if (path == null) {
2052:                            path = new TreePath(new Object[] { element });
2053:                        }
2054:                    }
2055:                    return tpcp.hasChildren(path);
2056:                }
2057:                if (cp instanceof  ITreeContentProvider) {
2058:                    ITreeContentProvider tcp = (ITreeContentProvider) cp;
2059:                    return tcp.hasChildren(element);
2060:                }
2061:                return false;
2062:            }
2063:
2064:            /**
2065:             * Return whether the given element is expandable.
2066:             * 
2067:             * @param item
2068:             *            the tree item for the element
2069:             * @param parentPath
2070:             *            the parent path if it is known or <code>null</code> if it
2071:             *            needs to be determines
2072:             * @param element
2073:             *            the element
2074:             * @return whether the given element is expandable
2075:             */
2076:            private boolean isExpandable(Item item, TreePath parentPath,
2077:                    Object element) {
2078:                Object elementOrTreePath = element;
2079:                if (isTreePathContentProvider()) {
2080:                    if (parentPath != null) {
2081:                        elementOrTreePath = parentPath.createChildPath(element);
2082:                    } else {
2083:                        elementOrTreePath = getTreePathFromItem(item);
2084:                    }
2085:                }
2086:                return isExpandable(elementOrTreePath);
2087:            }
2088:
2089:            /* (non-Javadoc) Method declared on Viewer. */
2090:            protected void labelProviderChanged() {
2091:                // we have to walk the (visible) tree and update every item
2092:                Control tree = getControl();
2093:                tree.setRedraw(false);
2094:                // don't pick up structure changes, but do force label updates
2095:                internalRefresh(tree, getRoot(), false, true);
2096:                tree.setRedraw(true);
2097:            }
2098:
2099:            /**
2100:             * Creates a new item.
2101:             * 
2102:             * @param parent
2103:             *            the parent widget
2104:             * @param style
2105:             *            SWT style bits
2106:             * @param index
2107:             *            if non-negative, indicates the position to insert the item
2108:             *            into its parent
2109:             * @return the newly-created item
2110:             */
2111:            protected abstract Item newItem(Widget parent, int style, int index);
2112:
2113:            /**
2114:             * Removes the given elements from this viewer. The selection is updated if
2115:             * required.
2116:             * <p>
2117:             * This method should be called (by the content provider) when elements have
2118:             * been removed from the model, in order to cause the viewer to accurately
2119:             * reflect the model. This method only affects the viewer, not the model.
2120:             * </p>
2121:             * 
2122:             * @param elementsOrTreePaths
2123:             *            the elements to remove
2124:             */
2125:            public void remove(final Object[] elementsOrTreePaths) {
2126:                assertElementsNotNull(elementsOrTreePaths);
2127:                if (elementsOrTreePaths.length == 0) {
2128:                    return;
2129:                }
2130:                if (isBusy())
2131:                    return;
2132:                preservingSelection(new Runnable() {
2133:                    public void run() {
2134:                        internalRemove(elementsOrTreePaths);
2135:                    }
2136:                });
2137:            }
2138:
2139:            /**
2140:             * Removes the given elements from this viewer whenever they appear as
2141:             * children of the given parent element. If the given elements also appear
2142:             * as children of some other parent, the other parent will remain unchanged.
2143:             * The selection is updated if required.
2144:             * <p>
2145:             * This method should be called (by the content provider) when elements have
2146:             * been removed from the model, in order to cause the viewer to accurately
2147:             * reflect the model. This method only affects the viewer, not the model.
2148:             * </p>
2149:             * 
2150:             * @param parent
2151:             *            the parent of the elements to remove
2152:             * @param elements
2153:             *            the elements to remove
2154:             * 
2155:             * @since 3.2
2156:             */
2157:            public void remove(final Object parent, final Object[] elements) {
2158:                assertElementsNotNull(elements);
2159:                if (elements.length == 0) {
2160:                    return;
2161:                }
2162:                if (isBusy())
2163:                    return;
2164:                preservingSelection(new Runnable() {
2165:                    public void run() {
2166:                        internalRemove(parent, elements);
2167:                    }
2168:                });
2169:            }
2170:
2171:            /**
2172:             * Removes the given element from the viewer. The selection is updated if
2173:             * necessary.
2174:             * <p>
2175:             * This method should be called (by the content provider) when a single
2176:             * element has been removed from the model, in order to cause the viewer to
2177:             * accurately reflect the model. This method only affects the viewer, not
2178:             * the model. Note that there is another method for efficiently processing
2179:             * the simultaneous removal of multiple elements.
2180:             * </p>
2181:             * 
2182:             * @param elementsOrTreePaths
2183:             *            the element
2184:             */
2185:            public void remove(Object elementsOrTreePaths) {
2186:                remove(new Object[] { elementsOrTreePaths });
2187:            }
2188:
2189:            /**
2190:             * Removes all items from the given control.
2191:             * 
2192:             * @param control
2193:             *            the control
2194:             */
2195:            protected abstract void removeAll(Control control);
2196:
2197:            /**
2198:             * Removes a listener for expand and collapse events in this viewer. Has no
2199:             * affect if an identical listener is not registered.
2200:             * 
2201:             * @param listener
2202:             *            a tree viewer listener
2203:             */
2204:            public void removeTreeListener(ITreeViewerListener listener) {
2205:                treeListeners.remove(listener);
2206:            }
2207:
2208:            /**
2209:             * This implementation of reveal() reveals the given element or tree path.
2210:             */
2211:            public void reveal(Object elementOrTreePath) {
2212:                Assert.isNotNull(elementOrTreePath);
2213:                Widget w = internalExpand(elementOrTreePath, true);
2214:                if (w instanceof  Item) {
2215:                    showItem((Item) w);
2216:                }
2217:            }
2218:
2219:            /**
2220:             * Returns the rightmost visible descendent of the given item. Returns the
2221:             * item itself if it has no children.
2222:             * 
2223:             * @param item
2224:             *            the item to compute the descendent of
2225:             * @return the rightmost visible descendent or the item itself if it has no
2226:             *         children
2227:             */
2228:            private Item rightMostVisibleDescendent(Item item) {
2229:                Item[] children = getItems(item);
2230:                if (getExpanded(item) && children != null
2231:                        && children.length > 0) {
2232:                    return rightMostVisibleDescendent(children[children.length - 1]);
2233:                }
2234:                return item;
2235:            }
2236:
2237:            /* (non-Javadoc) Method declared on Viewer. */
2238:            public Item scrollDown(int x, int y) {
2239:                Item current = getItem(x, y);
2240:                if (current != null) {
2241:                    Item next = getNextItem(current, true);
2242:                    showItem(next == null ? current : next);
2243:                    return next;
2244:                }
2245:                return null;
2246:            }
2247:
2248:            /* (non-Javadoc) Method declared on Viewer. */
2249:            public Item scrollUp(int x, int y) {
2250:                Item current = getItem(x, y);
2251:                if (current != null) {
2252:                    Item previous = getPreviousItem(current);
2253:                    showItem(previous == null ? current : previous);
2254:                    return previous;
2255:                }
2256:                return null;
2257:            }
2258:
2259:            /**
2260:             * Sets the auto-expand level. The value 0 means that there is no
2261:             * auto-expand; 1 means that top-level elements are expanded, but not their
2262:             * children; 2 means that top-level elements are expanded, and their
2263:             * children, but not grandchildren; and so on.
2264:             * <p>
2265:             * The value <code>ALL_LEVELS</code> means that all subtrees should be
2266:             * expanded.
2267:             * </p>
2268:             * 
2269:             * @param level
2270:             *            non-negative level, or <code>ALL_LEVELS</code> to expand all
2271:             *            levels of the tree
2272:             */
2273:            public void setAutoExpandLevel(int level) {
2274:                expandToLevel = level;
2275:            }
2276:
2277:            /**
2278:             * The <code>AbstractTreeViewer</code> implementation of this method
2279:             * checks to ensure that the content provider is an
2280:             * <code>ITreeContentProvider</code>.
2281:             */
2282:            public void setContentProvider(IContentProvider provider) {
2283:                // the actual check is in assertContentProviderType
2284:                super .setContentProvider(provider);
2285:            }
2286:
2287:            protected void assertContentProviderType(IContentProvider provider) {
2288:                Assert.isTrue(provider instanceof  ITreeContentProvider
2289:                        || provider instanceof  ITreePathContentProvider);
2290:            }
2291:
2292:            /**
2293:             * Sets the expand state of the given item.
2294:             * 
2295:             * @param item
2296:             *            the item
2297:             * @param expand
2298:             *            the expand state of the item
2299:             */
2300:            protected abstract void setExpanded(Item item, boolean expand);
2301:
2302:            /**
2303:             * Sets which nodes are expanded in this viewer's tree. The given list
2304:             * contains the elements that are to be expanded; all other nodes are to be
2305:             * collapsed.
2306:             * <p>
2307:             * This method is typically used when restoring the interesting state of a
2308:             * viewer captured by an earlier call to <code>getExpandedElements</code>.
2309:             * </p>
2310:             * 
2311:             * @param elements
2312:             *            the array of expanded elements
2313:             * @see #getExpandedElements
2314:             */
2315:            public void setExpandedElements(Object[] elements) {
2316:                assertElementsNotNull(elements);
2317:                if (isBusy()) {
2318:                    return;
2319:                }
2320:                CustomHashtable expandedElements = newHashtable(elements.length * 2 + 1);
2321:                for (int i = 0; i < elements.length; ++i) {
2322:                    Object element = elements[i];
2323:                    // Ensure item exists for element. This will materialize items for
2324:                    // each element and their parents, if possible. This is important
2325:                    // to support expanding of inner tree nodes without necessarily
2326:                    // expanding their parents.
2327:                    internalExpand(element, false);
2328:                    expandedElements.put(element, element);
2329:                }
2330:                // this will traverse all existing items, and create children for
2331:                // elements that need to be expanded. If the tree contains multiple
2332:                // equal elements, and those are in the set of elements to be expanded,
2333:                // only the first item found for each element will be expanded.
2334:                internalSetExpanded(expandedElements, getControl());
2335:            }
2336:
2337:            /**
2338:             * Sets which nodes are expanded in this viewer's tree. The given list
2339:             * contains the tree paths that are to be expanded; all other nodes are to
2340:             * be collapsed.
2341:             * <p>
2342:             * This method is typically used when restoring the interesting state of a
2343:             * viewer captured by an earlier call to <code>getExpandedTreePaths</code>.
2344:             * </p>
2345:             * 
2346:             * @param treePaths
2347:             *            the array of expanded tree paths
2348:             * @see #getExpandedTreePaths()
2349:             * 
2350:             * @since 3.2
2351:             */
2352:            public void setExpandedTreePaths(TreePath[] treePaths) {
2353:                assertElementsNotNull(treePaths);
2354:                if (isBusy())
2355:                    return;
2356:                final IElementComparer comparer = getComparer();
2357:                IElementComparer treePathComparer = new IElementComparer() {
2358:
2359:                    public boolean equals(Object a, Object b) {
2360:                        return ((TreePath) a).equals(((TreePath) b), comparer);
2361:                    }
2362:
2363:                    public int hashCode(Object element) {
2364:                        return ((TreePath) element).hashCode(comparer);
2365:                    }
2366:                };
2367:                CustomHashtable expandedTreePaths = new CustomHashtable(
2368:                        treePaths.length * 2 + 1, treePathComparer);
2369:                for (int i = 0; i < treePaths.length; ++i) {
2370:                    TreePath treePath = treePaths[i];
2371:                    // Ensure item exists for element. This will materialize items for
2372:                    // each element and their parents, if possible. This is important
2373:                    // to support expanding of inner tree nodes without necessarily
2374:                    // expanding their parents.
2375:                    internalExpand(treePath, false);
2376:                    expandedTreePaths.put(treePath, treePath);
2377:                }
2378:                // this will traverse all existing items, and create children for
2379:                // elements that need to be expanded. If the tree contains multiple
2380:                // equal elements, and those are in the set of elements to be expanded,
2381:                // only the first item found for each element will be expanded.
2382:                internalSetExpandedTreePaths(expandedTreePaths, getControl(),
2383:                        new TreePath(new Object[0]));
2384:            }
2385:
2386:            /**
2387:             * Sets whether the node corresponding to the given element or tree path is
2388:             * expanded or collapsed.
2389:             * 
2390:             * @param elementOrTreePath
2391:             *            the element
2392:             * @param expanded
2393:             *            <code>true</code> if the node is expanded, and
2394:             *            <code>false</code> if collapsed
2395:             */
2396:            public void setExpandedState(Object elementOrTreePath,
2397:                    boolean expanded) {
2398:                Assert.isNotNull(elementOrTreePath);
2399:                if (isBusy())
2400:                    return;
2401:                Widget item = internalExpand(elementOrTreePath, false);
2402:                if (item instanceof  Item) {
2403:                    if (expanded) {
2404:                        createChildren(item);
2405:                    }
2406:                    setExpanded((Item) item, expanded);
2407:                }
2408:            }
2409:
2410:            /**
2411:             * Sets the selection to the given list of items.
2412:             * 
2413:             * @param items
2414:             *            list of items (element type:
2415:             *            <code>org.eclipse.swt.widgets.Item</code>)
2416:             */
2417:            protected abstract void setSelection(List items);
2418:
2419:            /**
2420:             * This implementation of setSelectionToWidget accepts a list of elements or
2421:             * a list of tree paths.
2422:             */
2423:            protected void setSelectionToWidget(List v, boolean reveal) {
2424:                if (v == null) {
2425:                    setSelection(new ArrayList(0));
2426:                    return;
2427:                }
2428:                int size = v.size();
2429:                List newSelection = new ArrayList(size);
2430:                for (int i = 0; i < size; ++i) {
2431:                    Object elementOrTreePath = v.get(i);
2432:                    // Use internalExpand since item may not yet be created. See
2433:                    // 1G6B1AR.
2434:                    Widget w = internalExpand(elementOrTreePath, false);
2435:                    if (w instanceof  Item) {
2436:                        newSelection.add(w);
2437:                    } else if (w == null
2438:                            && elementOrTreePath instanceof  TreePath) {
2439:                        TreePath treePath = (TreePath) elementOrTreePath;
2440:                        Object element = treePath.getLastSegment();
2441:                        if (element != null) {
2442:                            w = internalExpand(element, false);
2443:                            if (w instanceof  Item) {
2444:                                newSelection.add(w);
2445:                            }
2446:                        }
2447:                    }
2448:                }
2449:                setSelection(newSelection);
2450:
2451:                // Although setting the selection in the control should reveal it,
2452:                // setSelection may be a no-op if the selection is unchanged,
2453:                // so explicitly reveal the first item in the selection here.
2454:                // See bug 100565 for more details.
2455:                if (reveal && newSelection.size() > 0) {
2456:                    showItem((Item) newSelection.get(0));
2457:                }
2458:            }
2459:
2460:            /**
2461:             * Shows the given item.
2462:             * 
2463:             * @param item
2464:             *            the item
2465:             */
2466:            protected abstract void showItem(Item item);
2467:
2468:            /**
2469:             * Updates the tree items to correspond to the child elements of the given
2470:             * parent element. If null is passed for the children, this method obtains
2471:             * them (only if needed).
2472:             * 
2473:             * @param widget
2474:             *            the widget
2475:             * @param parent
2476:             *            the parent element
2477:             * @param elementChildren
2478:             *            the child elements, or null
2479:             * @deprecated this is no longer called by the framework
2480:             */
2481:            protected void updateChildren(Widget widget, Object parent,
2482:                    Object[] elementChildren) {
2483:                updateChildren(widget, parent, elementChildren, true);
2484:            }
2485:
2486:            /**
2487:             * Updates the tree items to correspond to the child elements of the given
2488:             * parent element. If null is passed for the children, this method obtains
2489:             * them (only if needed).
2490:             * 
2491:             * @param widget
2492:             *            the widget
2493:             * @param parent
2494:             *            the parent element
2495:             * @param elementChildren
2496:             *            the child elements, or null
2497:             * @param updateLabels
2498:             *            <code>true</code> to update labels for existing elements,
2499:             *            <code>false</code> to only update labels as needed, assuming
2500:             *            that labels for existing elements are unchanged.
2501:             * @since 2.1
2502:             */
2503:            private void updateChildren(Widget widget, Object parent,
2504:                    Object[] elementChildren, boolean updateLabels) {
2505:                // optimization! prune collapsed subtrees
2506:                if (widget instanceof  Item) {
2507:                    Item ti = (Item) widget;
2508:                    if (!getExpanded(ti)) {
2509:                        // need a dummy node if element is expandable;
2510:                        // but try to avoid recreating the dummy node
2511:                        boolean needDummy = isExpandable(ti, null, parent);
2512:                        boolean haveDummy = false;
2513:                        // remove all children
2514:                        Item[] items = getItems(ti);
2515:                        for (int i = 0; i < items.length; i++) {
2516:                            if (items[i].getData() != null) {
2517:                                disassociate(items[i]);
2518:                                items[i].dispose();
2519:                            } else {
2520:                                if (needDummy && !haveDummy) {
2521:                                    haveDummy = true;
2522:                                } else {
2523:                                    items[i].dispose();
2524:                                }
2525:                            }
2526:                        }
2527:                        if (needDummy && !haveDummy) {
2528:                            newItem(ti, SWT.NULL, -1);
2529:                        }
2530:
2531:                        return;
2532:                    }
2533:                }
2534:
2535:                // If the children weren't passed in, get them now since they're needed
2536:                // below.
2537:                if (elementChildren == null) {
2538:                    if (isTreePathContentProvider() && widget instanceof  Item) {
2539:                        TreePath path = getTreePathFromItem((Item) widget);
2540:                        elementChildren = getSortedChildren(path);
2541:                    } else {
2542:                        elementChildren = getSortedChildren(parent);
2543:                    }
2544:                }
2545:
2546:                Control tree = getControl();
2547:
2548:                // WORKAROUND
2549:                int oldCnt = -1;
2550:                if (widget == tree) {
2551:                    oldCnt = getItemCount(tree);
2552:                }
2553:
2554:                Item[] items = getChildren(widget);
2555:
2556:                // save the expanded elements
2557:                CustomHashtable expanded = newHashtable(CustomHashtable.DEFAULT_CAPACITY); // assume
2558:                // num
2559:                // expanded
2560:                // is
2561:                // small
2562:                for (int i = 0; i < items.length; ++i) {
2563:                    if (getExpanded(items[i])) {
2564:                        Object element = items[i].getData();
2565:                        if (element != null) {
2566:                            expanded.put(element, element);
2567:                        }
2568:                    }
2569:                }
2570:
2571:                int min = Math.min(elementChildren.length, items.length);
2572:
2573:                // dispose of surplus items, optimizing for the case where elements have
2574:                // been deleted but not reordered, or all elements have been removed.
2575:                int numItemsToDispose = items.length - min;
2576:                if (numItemsToDispose > 0) {
2577:                    CustomHashtable children = newHashtable(elementChildren.length * 2);
2578:                    for (int i = 0; i < elementChildren.length; i++) {
2579:                        Object elementChild = elementChildren[i];
2580:                        children.put(elementChild, elementChild);
2581:                    }
2582:                    int i = 0;
2583:                    while (numItemsToDispose > 0 && i < items.length) {
2584:                        Object data = items[i].getData();
2585:                        if (data == null
2586:                                || items.length - i <= numItemsToDispose
2587:                                || !children.containsKey(data)) {
2588:                            if (data != null) {
2589:                                disassociate(items[i]);
2590:                            }
2591:                            items[i].dispose();
2592:                            if (i + 1 < items.length) {
2593:                                // The components at positions i+1 through
2594:                                // items.length-1 in the source array are copied into
2595:                                // positions i through items.length-2
2596:                                System.arraycopy(items, i + 1, items, i,
2597:                                        items.length - (i + 1));
2598:                            }
2599:                            numItemsToDispose--;
2600:                        } else {
2601:                            i++;
2602:                        }
2603:                    }
2604:                }
2605:
2606:                // compare first min items, and update item if necessary
2607:                // need to do it in two passes:
2608:                // 1: disassociate old items
2609:                // 2: associate new items
2610:                // because otherwise a later disassociate can remove a mapping made for
2611:                // a previous associate,
2612:                // making the map inconsistent
2613:                for (int i = 0; i < min; ++i) {
2614:                    Item item = items[i];
2615:                    Object oldElement = item.getData();
2616:                    if (oldElement != null) {
2617:                        Object newElement = elementChildren[i];
2618:                        if (newElement != oldElement) {
2619:                            if (equals(newElement, oldElement)) {
2620:                                // update the data to be the new element, since
2621:                                // although the elements
2622:                                // may be equal, they may still have different labels
2623:                                // or children
2624:                                Object data = item.getData();
2625:                                if (data != null) {
2626:                                    unmapElement(data, item);
2627:                                }
2628:                                item.setData(newElement);
2629:                                mapElement(newElement, item);
2630:                            } else {
2631:                                disassociate(item);
2632:                                // Clear the text and image to force a label update
2633:                                item.setImage(null);
2634:                                item.setText("");//$NON-NLS-1$
2635:
2636:                            }
2637:                        }
2638:                    }
2639:                }
2640:
2641:                for (int i = 0; i < min; ++i) {
2642:                    Item item = items[i];
2643:                    Object newElement = elementChildren[i];
2644:                    if (item.getData() == null) {
2645:                        // old and new elements are not equal
2646:                        associate(newElement, item);
2647:                        updatePlus(item, newElement);
2648:                        updateItem(item, newElement);
2649:                    } else {
2650:                        // old and new elements are equal
2651:                        updatePlus(item, newElement);
2652:                        if (updateLabels) {
2653:                            updateItem(item, newElement);
2654:                        }
2655:                    }
2656:                }
2657:
2658:                // Restore expanded state for items that changed position.
2659:                // Make sure setExpanded is called after updatePlus, since
2660:                // setExpanded(false) fails if item has no children.
2661:                // Need to call setExpanded for both expanded and unexpanded
2662:                // cases since the expanded state can change either way.
2663:                // This needs to be done in a second loop, see bug 148025.
2664:                for (int i = 0; i < min; ++i) {
2665:                    Item item = items[i];
2666:                    Object newElement = elementChildren[i];
2667:                    setExpanded(item, expanded.containsKey(newElement));
2668:                }
2669:
2670:                // add any remaining elements
2671:                if (min < elementChildren.length) {
2672:                    for (int i = min; i < elementChildren.length; ++i) {
2673:                        createTreeItem(widget, elementChildren[i], i);
2674:                    }
2675:
2676:                    // Need to restore expanded state in a separate pass
2677:                    // because createTreeItem does not return the new item.
2678:                    // Avoid doing this unless needed.
2679:                    if (expanded.size() > 0) {
2680:                        // get the items again, to include the new items
2681:                        items = getChildren(widget);
2682:                        for (int i = min; i < elementChildren.length; ++i) {
2683:                            // Restore expanded state for items that changed position.
2684:                            // Make sure setExpanded is called after updatePlus (called
2685:                            // in createTreeItem), since
2686:                            // setExpanded(false) fails if item has no children.
2687:                            // Only need to call setExpanded if element was expanded
2688:                            // since new items are initially unexpanded.
2689:                            if (expanded.containsKey(elementChildren[i])) {
2690:                                setExpanded(items[i], true);
2691:                            }
2692:                        }
2693:                    }
2694:                }
2695:
2696:                // WORKAROUND
2697:                if (widget == tree && oldCnt == 0 && getItemCount(tree) != 0) {
2698:                    // System.out.println("WORKAROUND setRedraw");
2699:                    tree.setRedraw(false);
2700:                    tree.setRedraw(true);
2701:                }
2702:            }
2703:
2704:            /**
2705:             * Updates the "+"/"-" icon of the tree node from the given element. It
2706:             * calls <code>isExpandable</code> to determine whether an element is
2707:             * expandable.
2708:             * 
2709:             * @param item
2710:             *            the item
2711:             * @param element
2712:             *            the element
2713:             */
2714:            protected void updatePlus(Item item, Object element) {
2715:                boolean hasPlus = getItemCount(item) > 0;
2716:                boolean needsPlus = isExpandable(item, null, element);
2717:                boolean removeAll = false;
2718:                boolean addDummy = false;
2719:                Object data = item.getData();
2720:                if (data != null && equals(element, data)) {
2721:                    // item shows same element
2722:                    if (hasPlus != needsPlus) {
2723:                        if (needsPlus) {
2724:                            addDummy = true;
2725:                        } else {
2726:                            removeAll = true;
2727:                        }
2728:                    }
2729:                } else {
2730:                    // item shows different element
2731:                    removeAll = true;
2732:                    addDummy = needsPlus;
2733:
2734:                    // we cannot maintain expand state so collapse it
2735:                    setExpanded(item, false);
2736:                }
2737:                if (removeAll) {
2738:                    // remove all children
2739:                    Item[] items = getItems(item);
2740:                    for (int i = 0; i < items.length; i++) {
2741:                        if (items[i].getData() != null) {
2742:                            disassociate(items[i]);
2743:                        }
2744:                        items[i].dispose();
2745:                    }
2746:                }
2747:                if (addDummy) {
2748:                    newItem(item, SWT.NULL, -1); // append a dummy
2749:                }
2750:            }
2751:
2752:            /**
2753:             * Gets the expanded elements that are visible to the user. An expanded
2754:             * element is only visible if the parent is expanded.
2755:             * 
2756:             * @return the visible expanded elements
2757:             * @since 2.0
2758:             */
2759:            public Object[] getVisibleExpandedElements() {
2760:                ArrayList v = new ArrayList();
2761:                internalCollectVisibleExpanded(v, getControl());
2762:                return v.toArray();
2763:            }
2764:
2765:            private void internalCollectVisibleExpanded(ArrayList result,
2766:                    Widget widget) {
2767:                Item[] items = getChildren(widget);
2768:                for (int i = 0; i < items.length; i++) {
2769:                    Item item = items[i];
2770:                    if (getExpanded(item)) {
2771:                        Object data = item.getData();
2772:                        if (data != null) {
2773:                            result.add(data);
2774:                        }
2775:                        // Only recurse if it is expanded - if
2776:                        // not then the children aren't visible
2777:                        internalCollectVisibleExpanded(result, item);
2778:                    }
2779:                }
2780:            }
2781:
2782:            /**
2783:             * Returns the tree path for the given item.
2784:             * @param item
2785:             * @return {@link TreePath}
2786:             * 
2787:             * @since 3.2
2788:             */
2789:            protected TreePath getTreePathFromItem(Item item) {
2790:                LinkedList segments = new LinkedList();
2791:                while (item != null) {
2792:                    Object segment = item.getData();
2793:                    Assert.isNotNull(segment);
2794:                    segments.addFirst(segment);
2795:                    item = getParentItem(item);
2796:                }
2797:                return new TreePath(segments.toArray());
2798:            }
2799:
2800:            /**
2801:             * This implementation of getSelection() returns an instance of
2802:             * ITreeSelection.
2803:             * 
2804:             * @since 3.2
2805:             */
2806:            public ISelection getSelection() {
2807:                Control control = getControl();
2808:                if (control == null || control.isDisposed()) {
2809:                    return TreeSelection.EMPTY;
2810:                }
2811:                Widget[] items = getSelection(getControl());
2812:                ArrayList list = new ArrayList(items.length);
2813:                for (int i = 0; i < items.length; i++) {
2814:                    Widget item = items[i];
2815:                    if (item.getData() != null) {
2816:                        list.add(getTreePathFromItem((Item) item));
2817:                    }
2818:                }
2819:                return new TreeSelection((TreePath[]) list
2820:                        .toArray(new TreePath[list.size()]), getComparer());
2821:            }
2822:
2823:            protected void setSelectionToWidget(ISelection selection,
2824:                    boolean reveal) {
2825:                if (selection instanceof  ITreeSelection) {
2826:                    ITreeSelection treeSelection = (ITreeSelection) selection;
2827:                    setSelectionToWidget(Arrays
2828:                            .asList(treeSelection.getPaths()), reveal);
2829:                } else {
2830:                    super .setSelectionToWidget(selection, reveal);
2831:                }
2832:            }
2833:
2834:            /**
2835:             * Returns a list of tree paths corresponding to expanded nodes in this
2836:             * viewer's tree, including currently hidden ones that are marked as
2837:             * expanded but are under a collapsed ancestor.
2838:             * <p>
2839:             * This method is typically used when preserving the interesting state of a
2840:             * viewer; <code>setExpandedElements</code> is used during the restore.
2841:             * </p>
2842:             * 
2843:             * @return the array of expanded tree paths
2844:             * @see #setExpandedElements
2845:             * 
2846:             * @since 3.2
2847:             */
2848:            public TreePath[] getExpandedTreePaths() {
2849:                ArrayList items = new ArrayList();
2850:                internalCollectExpandedItems(items, getControl());
2851:                ArrayList result = new ArrayList(items.size());
2852:                for (Iterator it = items.iterator(); it.hasNext();) {
2853:                    Item item = (Item) it.next();
2854:                    TreePath treePath = getTreePathFromItem(item);
2855:                    if (treePath != null) {
2856:                        result.add(treePath);
2857:                    }
2858:                }
2859:                return (TreePath[]) result.toArray(new TreePath[items.size()]);
2860:            }
2861:
2862:            private boolean isTreePathContentProvider() {
2863:                return getContentProvider() instanceof  ITreePathContentProvider;
2864:            }
2865:
2866:            /**
2867:             * Inserts the given element as a new child element of the given parent
2868:             * element at the given position. If this viewer has a sorter, the position
2869:             * is ignored and the element is inserted at the correct position in the
2870:             * sort order.
2871:             * <p>
2872:             * This method should be called (by the content provider) when elements have
2873:             * been added to the model, in order to cause the viewer to accurately
2874:             * reflect the model. This method only affects the viewer, not the model.
2875:             * </p>
2876:             * 
2877:             * @param parentElementOrTreePath
2878:             *            the parent element, or the tree path to the parent
2879:             * @param element
2880:             *            the element
2881:             * @param position
2882:             *            a 0-based position relative to the model, or -1 to indicate
2883:             *            the last position
2884:             * 
2885:             * @since 3.2
2886:             */
2887:            public void insert(Object parentElementOrTreePath, Object element,
2888:                    int position) {
2889:                Assert.isNotNull(parentElementOrTreePath);
2890:                Assert.isNotNull(element);
2891:                if (isBusy())
2892:                    return;
2893:                if (getComparator() != null || hasFilters()) {
2894:                    add(parentElementOrTreePath, new Object[] { element });
2895:                    return;
2896:                }
2897:                Widget[] items;
2898:                if (internalIsInputOrEmptyPath(parentElementOrTreePath)) {
2899:                    items = new Widget[] { getControl() };
2900:                } else {
2901:                    items = internalFindItems(parentElementOrTreePath);
2902:                }
2903:
2904:                for (int i = 0; i < items.length; i++) {
2905:                    Widget widget = items[i];
2906:                    if (widget instanceof  Item) {
2907:                        Item item = (Item) widget;
2908:
2909:                        Item[] childItems = getChildren(item);
2910:                        if (getExpanded(item)
2911:                                || (childItems.length > 0 && childItems[0]
2912:                                        .getData() != null)) {
2913:                            // item has real children, go ahead and add
2914:                            int insertionPosition = position;
2915:                            if (insertionPosition == -1) {
2916:                                insertionPosition = getItemCount(item);
2917:                            }
2918:
2919:                            createTreeItem(item, element, insertionPosition);
2920:                        }
2921:                    } else {
2922:                        int insertionPosition = position;
2923:                        if (insertionPosition == -1) {
2924:                            insertionPosition = getItemCount((Control) widget);
2925:                        }
2926:
2927:                        createTreeItem(widget, element, insertionPosition);
2928:                    }
2929:                }
2930:            }
2931:
2932:            /*
2933:             * (non-Javadoc)
2934:             * 
2935:             * @see org.eclipse.jface.viewers.ColumnViewer#getColumnViewerOwner(int)
2936:             */
2937:            protected Widget getColumnViewerOwner(int columnIndex) {
2938:                // Return null by default
2939:                return null;
2940:            }
2941:
2942:            /**
2943:             * This implementation of {@link #getItemAt(Point)} returns null to ensure
2944:             * API backwards compatibility. Subclasses should override.
2945:             * 
2946:             * @since 3.3
2947:             */
2948:            protected Item getItemAt(Point point) {
2949:                return null;
2950:            }
2951:
2952:            /**
2953:             * This implementation of {@link #createViewerEditor()} returns null to ensure
2954:             * API backwards compatibility. Subclasses should override.
2955:             *
2956:             * @since 3.3
2957:             */
2958:            protected ColumnViewerEditor createViewerEditor() {
2959:                return null;
2960:            }
2961:
2962:            /**
2963:             * Returns the number of columns of this viewer.
2964:             * <p><b>Subclasses should overwrite this method, which has a default
2965:             * implementation (returning 0) for API backwards compatility reasons</b></p>
2966:             *
2967:             * @return the number of columns
2968:             *
2969:             * @since 3.3
2970:             */
2971:            protected int doGetColumnCount() {
2972:                return 0;
2973:            }
2974:
2975:            /**
2976:             * This implementation of buildLabel handles tree paths as well as elements.
2977:             * 
2978:             * @param updateLabel
2979:             *            the ViewerLabel to collect the result in
2980:             * @param elementOrPath
2981:             *            the element or tree path for which a label should be built
2982:             * 
2983:             * @see org.eclipse.jface.viewers.StructuredViewer#buildLabel(org.eclipse.jface.viewers.ViewerLabel,
2984:             *      java.lang.Object)
2985:             */
2986:            protected void buildLabel(ViewerLabel updateLabel,
2987:                    Object elementOrPath) {
2988:                Object element;
2989:                if (elementOrPath instanceof  TreePath) {
2990:                    TreePath path = (TreePath) elementOrPath;
2991:                    IBaseLabelProvider provider = getLabelProvider();
2992:                    if (provider instanceof  ITreePathLabelProvider) {
2993:                        ITreePathLabelProvider pprov = (ITreePathLabelProvider) provider;
2994:                        buildLabel(updateLabel, path, pprov);
2995:                        return;
2996:                    }
2997:                    element = path.getLastSegment();
2998:                } else {
2999:                    element = elementOrPath;
3000:                }
3001:                super .buildLabel(updateLabel, element);
3002:            }
3003:
3004:            /**
3005:             * Returns true if the given object is either the input or an empty tree path.
3006:             *
3007:             * @param elementOrTreePath an element which could either be the viewer's input, or a tree path
3008:             *
3009:             * @return <code>true</code> if the given object is either the input or an empty tree path,
3010:             * <code>false</code> otherwise.
3011:             * @since 3.3
3012:             */
3013:            final protected boolean internalIsInputOrEmptyPath(
3014:                    final Object elementOrTreePath) {
3015:                if (elementOrTreePath.equals(getInput()))
3016:                    return true;
3017:                if (!(elementOrTreePath instanceof  TreePath))
3018:                    return false;
3019:                return ((TreePath) elementOrTreePath).getSegmentCount() == 0;
3020:            }
3021:
3022:            /*
3023:             * Subclasses should implement
3024:             */
3025:            protected ViewerRow getViewerRowFromItem(Widget item) {
3026:                return null;
3027:            }
3028:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.