Bug 173571 - [Viewers] TreeViewer.updateHasChildren() does not work if item is already expanded
Summary: [Viewers] TreeViewer.updateHasChildren() does not work if item is already exp...
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.3   Edit
Hardware: PC Windows XP
: P3 major (vote)
Target Milestone: 3.3 M6   Edit
Assignee: Boris Bokowski CLA
QA Contact:
URL:
Whiteboard:
Keywords: contributed, greatbug
Depends on:
Blocks:
 
Reported: 2007-02-08 19:28 EST by Pawel Piech CLA
Modified: 2007-06-05 16:36 EDT (History)
3 users (show)

See Also:


Attachments
Patch to request children count update if node is expanded upon setHasChildren(). (775 bytes, patch)
2007-02-08 19:30 EST, Pawel Piech CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Pawel Piech CLA 2007-02-08 19:28:24 EST
When the ILazyTreePathContentProvider.updateElement() is called, the content provider needs to call TreeViewer.replace() and TreeViewer.setChildCount() to refresh the element's state.  However, if the old element at the same index was previously expanded, the setHasChildren() has no effect.
This is because a test in TreeViewer.setHasChildren() causes the update to be inored if the item is already expanded.  Adding a call to update the child count for the node seems to fix the problem (patch to be attached).

Use sample below to reproduce the problem:
1) Expand the first item.
2) Press the "Change Order" button.
3) Expand second item.
4) Press the "Change Order" button again.
Problem: The '+' disappears from the second item.

public class TestJFace {

    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display, SWT.SHELL_TRIM);
        shell.setLayout(new GridLayout());
        GridData data = new GridData(GridData.FILL_BOTH);
        shell.setLayoutData(data);

        Font font = new Font(display, "Courier", 10, SWT.NORMAL);

        final TreeViewer treeViewer = new TreeViewer(shell, SWT.VIRTUAL | SWT.BORDER);
        treeViewer.getControl().setLayoutData(data);
        
        final ContentProvider contentProvider = new ContentProvider(treeViewer);
        treeViewer.setContentProvider(contentProvider);
        treeViewer.setInput(new Object());
        
        Button button = new Button(shell, SWT.NONE);
        button.setText("Change Order");
        button.addSelectionListener(new SelectionListener() {

            public void widgetDefaultSelected(SelectionEvent e) {}

            public void widgetSelected(SelectionEvent e) {
                fgParentFirst = !fgParentFirst;
                treeViewer.refresh();
            }
        });

        shell.open();

        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        font.dispose();
    }

    public static boolean fgParentFirst = true;
    
    public static class ContentProvider implements ILazyTreePathContentProvider {
        TreeViewer fViewer;
        
        ContentProvider(TreeViewer viewer) {
            fViewer = viewer;
        }
        
        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        }
                
        public void updateHasChildren(TreePath path) {
            if (path.getSegmentCount() == 0) {
                fViewer.setHasChildren(path, true);
            } else if (path.getSegmentCount() == 1) {
                if ("Parent".equals(path.getSegment(0))) {
                    fViewer.setHasChildren(path, true);
                } else {
                    fViewer.setHasChildren(path, false);
                }
            } else {
                fViewer.setHasChildren(path, false);
            }
        }

        public void updateChildCount(TreePath path, int currentChildCount) {
            if (path.getSegmentCount() == 0) {
                fViewer.setChildCount(path, 2);
            } else if (path.getSegmentCount() == 1) {
                if ("Parent".equals(path.getSegment(0))) {
                    fViewer.setChildCount(path, 1);
                } else {
                    fViewer.setChildCount(path, 0);
                }
            } else {
                fViewer.setChildCount(path, 0);
            }
        }

        public void updateElement(TreePath path, int index) {
            Object object = null;
            if (path.getSegmentCount() == 0) {
                if (index == 0) {
                    object = fgParentFirst ? "Parent" : "Non-Parent";
                } else if (index == 1) {
                    object = fgParentFirst ? "Non-Parent" : "Parent";
                }
                
            } else if (path.getSegmentCount() == 1) {
                if ("Parent".equals(path.getSegment(0))) {
                    object = "Child";
                } 
            } 
            
            if (object != null) {
                fViewer.replace(path, index, object);
                updateHasChildren(path.createChildPath(object));
            }                
        }


        public TreePath[] getParents(Object element) {
            return new TreePath[0];
        }

        public void dispose() {}

    }
}
Comment 1 Pawel Piech CLA 2007-02-08 19:30:36 EST
Created attachment 58621 [details]
Patch to request children count update if node is expanded upon setHasChildren().
Comment 2 Darin Wright CLA 2007-02-12 15:59:43 EST
*** Bug 173898 has been marked as a duplicate of this bug. ***
Comment 3 Darin Wright CLA 2007-02-12 16:00:30 EST
Marking as major, as this impacts the usability of the variables view.
Comment 4 Boris Bokowski CLA 2007-03-16 16:00:22 EDT
Released >20070316.  Thanks for the patch, and sorry for not releasing this earlier.
Comment 5 Tod Creasey CLA 2007-03-23 08:57:39 EDT
Verified in I20070322-1800 - thanks for the excellent test case
Comment 6 Pawel Piech CLA 2007-03-23 10:26:40 EDT
thanks :-)