Saving TreeViewer state before setInput()
Asked Answered
H

2

10

I'm trying to save JFace TreeViewer expansion state to refresh it after calling setInput() method. I tried getExpandedElements, setExpandedElements, getExpandedTreePaths, setExpandedTreePaths methods of TreeViewer but it doesn't work.

Object[] expandedElements = viewer.getExpandedElements();
TreePath[] expandedTreePaths = viewer.getExpandedTreePaths();
viewer.setInput();
viewer.setExpandedElements(expandedElements);
viewer.setExpandedTreePaths(expandedTreePaths);
Halford answered 16/10, 2009 at 7:7 Comment(0)
D
9

You need to make sure that your TreeViewer's content provider provides objects that have their hashCode and equals methods properly defined. AbstractTreeViewer needs to be able to compare the old and new objects to determine their expansion state. If hashCode and equals aren't provided, it's a simple reference check, which won't work if you've recreated your contents.

Dupree answered 16/10, 2009 at 20:9 Comment(1)
This works, but what was not obvious for me: the code of the question is still needed, together with the good hashCode/equals implementation.Commentate
G
3

As mentioned in this thread, take a look at the late ResourceNavigator, from the org.eclipse.ui.views.navigator package.
("late" because that class is no longer used directly, see the Eclipse Wiki).

alt text (as seen in the eclipse Java Model)

It uses a TreeViewer, and saves the expanded elements and selected elements, among other state.
The model elements are IResource objects, which are persisted using the IPersistableElement/IElementFactory mechanism.
The IPersistableElement adapter is registered against IResource in class WorkbenchAdapter, but this could instead be obtained by the model element implementing IPersistableElement directly.
The corresponding IElementFactory is declared in an elementFactory extension in org.eclipse.ui.ide's plugin.xml.

The restored resources know how to get their own children (and parent), via the tree's content provider, so not all elements of the tree need to be persisted.

A similar approach could be used for saving the viewer's input resource.
For ResourceNavigator, there's a level of indirection here through its FrameList's current frame, but if you step through it in the debugger, you'll see that it's essentially doing the same thing.


Small extract (but the rest of the code save also many other things, including selection)

if (frameList.getCurrentIndex() > 0) {
    //save frame, it's not the "home"/workspace frame
    TreeFrame currentFrame = (TreeFrame) frameList.getCurrentFrame();
    IMemento frameMemento = memento.createChild(TAG_CURRENT_FRAME);
    currentFrame.saveState(frameMemento);
} else {
    //save visible expanded elements
    Object JavaDoc expandedElements[] = viewer.getVisibleExpandedElements();
    if (expandedElements.length > 0) {
        IMemento expandedMem = memento.createChild(TAG_EXPANDED);
        for (int i = 0; i < expandedElements.length; i++) {
            if (expandedElements[i] instanceof IResource) {
                IMemento elementMem = expandedMem
                        .createChild(TAG_ELEMENT);
                elementMem.putString(TAG_PATH,
                        ((IResource) expandedElements[i]).getFullPath()
                                .toString());
            }
        }
    }
    [...]
 }
Gynandromorph answered 16/10, 2009 at 12:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.