Bug 77071 [Navigator] [Viewers] Navigator update loses additions
Build: I20041019 I am working on support for lazily populating the workspace in cases where the user has a slow file system (such as remote network share). When a project is created, a background job is started to do a refreshLocal to pull in contents from the file system. In the meantime, the user can continue to browse the project as it arrives. While testing, I discovered the TreeViewer update algorithm doesn't function properly when it receives notification to add an item it already nows about. Here is what happens: 1) Project is created. WorkbenchContentProvider receives delta for added project. 2) Background refresh is started 3) User expands new project. At this point the refresh is partially complete, but the navigator has not yet received a delta for it. When the content provider asks for the children of the project, it gets a list of the folders that have already been discovered. Say the project "P" contains single folder "f" at this point. The folder "f" is shown in the navigator. At this point the children of "f" have not yet been discovered, so no "plus box" is added for the "f" tree item. (hasChildren returns false at this point). 4) The refresh completes, and WorkbenchContentProvider receives a delta for all of the refresh resources. This delta looks like: /P [*] (changed project) /P/f [+] (added folder) /P/f/a.txt (added file) We see that "f" does indeed have a child. WorkbenchContentProvider just does a single TreeViewer.add() call for /P/f, and doesn't bother calling add for the child /P/f/a.txt. In AbstractTreeViewer.createAddedElement(Widget, Object) we see that it tests to ensure it is not adding something that already exists: for (int i = 0; i < items.length; i++) { if (items[i].getData().equals(element)) return; } This correctly short-circuits the addition. However, it means the /P/f tree item is never updated, so it remains without a "plus box" even though it now has children. The navigator view has to be closed and reopened to get the new items to appear correctly. Possible fix: when the TreeViewer addition code discovers it is being told to add an element that already exists, it could instead just update the element: private void createAddedElement(Widget widget, Object element) { if (equals(element, widget.getData())) return; Item[] items = getChildren(widget); for (int i = 0; i < items.length; i++) { if (items[i].getData().equals(element)) { update(element, null); return; } } int index = indexForElement(widget, element); createTreeItem(widget, element, index); } This is currently difficult to reproduce naturally, but quite easy to reproduce on a slow drive (I simulate this by adding a 1ms sleep to CoreFileSystemLibrary.getStat).
bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/AbstractTreeViewer.java
*         if collapsed
     */
    public boolean getExpandedState(Object element) {
        Assert.isNotNull(element);
        Widget item = findItem(element);
        if (item instanceof Item)
            return getExpanded((Item) item);
        return false;
    }
    /**
     * Returns the number of child items of the given SWT control.
     * 
     * @param control
     *           the control
     * @return the number of children
     */
    protected abstract int getItemCount(Control control);
    /**
     * Returns the number of child items of the given SWT item.
     * 
     * @param item
     *           the item
     * @return the number of children
     */
    protected abstract int getItemCount(Item item);
    /**
     * Returns the child items of the given SWT item.
     * 
     * @param item
     *           the item