Sunday, October 4, 2009

Eclipse RCP - How to save view layouts and state?

Introduction:

Saving the state of the application and reopening the application in the same state as previously opened vastly improves user experience. This article explains how to save the layout and state of the views in your application.

Saving Views and Layout:

First of all, you need to enable saving and restoring application state at workbench level. Make sure you override initialize method in your ApplicationWorkbenchAdvisor and add configurer.setSaveAndRestore(true);

@Override
public void initialize(final IWorkbenchConfigurer configurer) {
super.initialize(configurer);
configurer.setSaveAndRestore(true);
}

Adding this automatically saves opens views along with their layouts and makes sure they are reopened appropriately in the same layout. Isn't that amazing? Almost half of our work is done just by adding the above code block to ApplicationWorkbenchAdvisor. The remaining thing is saving the internal view state (i.e saving details of inside the view) .

Saving View State:

Let's say you have a navigator view in your perspective which displays a tree. By adding the above code block, the navigator view would be reopened in the same spot when application reopens again. But, the internals of navigator view would be lost. For example, if the tree had few selections and few nodes opened, they would be lost. Below, I'll explain how to preserve tree selections in your view.

1) Override saveState method (from ViewPart) in your view.

@Override
public void saveState(final IMemento memento) {
IStructuredSelection sel = (IStructuredSelection)this.treeViewer.getSelection();
if (sel.isEmpty()) {
return;
}
memento = memento.createChild("tree-selections");
Iterator iter = sel.iterator();
while (iter.hasNext()) {
String nodeName = iter.next();
memento.createChild("selected-nodes", nodeName);
}
}

IMemento provides way for user to store the application state in XML. User does not have to deal with XML directly and IMemento API takes care of it. When application is closed, if a view is open, it's saveState method is called before it is closed. This way, internal state of the view can be persisted before it is closed.

Restoring View State:

If you want to restore your view state (from the saved memento), you need to override the init method with memento i.e override this method

public void init(IViewSite site, IMemento memento) throws PartInitException {}

instead of

public void init(IViewSite site) throws PartInitException {}

Then, you can read the contents of the memento and restore view's internal state.

// Stores the memento so that it can be used after view is created

@Override
public void init(final IViewSite site, final IMemento memento) throws PartInitException {
init(site);
this.memento = memento;
}

@Override
public void createPartControl(Composite parent) {
// Create view here - For example, create tree viewer here

restoreState();
}

// Method which reads memento and sets selections on the tree
private void restoreState() {
IMemento selectionsMomento = this.memento.getChild("tree-selections");
if (selectionsMomento != null) {
IMemento selectedNodes[] = selectionsMomento.getChildren("selected-nodes");
if (selectedNodes.length > 0) {
ArrayList selections = new ArrayList(selectedNodes.length);
for (int i = 0; i<selectedNodes.length; i++) {
String id = selectedNodes[i].getID();
if (id != null) {
selections.add(id);
}
}

this.treeViewer.setSelection(new StructuredSelection(selections));
}
}
}

The contents of the view is created in createPartControl. Once the contents are created, it's state is set by using the restoreState method, which uses memento to get the internal state of the view last time. Above, we get selected node names from the memento and set tree selection appropriately.

Conclusion:

In this article, we saw how to preserve view layout and it's internal state so that views are reopened in exactly the same way as it was closed last time. In the next one, we'll see how to preserve editor layout and it's state.


11 comments:

StingerAJ said...

Do you know how to save the view's state when the view itself is closed during a session? So that, if the user reopens it during the same session, its layout is restored as it was and not as it was saved in the last memento?

Thx for the post.

Raja said...

Good question. saveState() method is only called when application is closed and not when the view is closed. I don't know of a way to restore the view state within the same session i.e when view is closed and reopened. If you find it, pls. post it here.

Daniele Fanì said...

Hi. I have a little problem, but it's just a bit out of topic.
I can't find a way to reopen a closed view in my rcp. The menu "window" doesn't provide nothing. How can reopen, for example, the 'outline' view once closed?
I posted the question also here
http://www.eclipse.org/forums/index.php?t=msg&goto=653179&S=5eb4239ce8764ed3a4fa3681976eaff0#msg_653179
without answer.
thank you and sorry for the OT

Raja said...

@Daniele - You can reopen a closed view by going to Window->Show Views and opening the desired view from there. Is this what you are looking for?

Daniele Fanì said...

yes...but the problem is that in the window menu, there is not "show view" . Is there a way to add it?
thank youg

Daniele Fanì said...

solved!s

Daniele Fanì said...
This comment has been removed by the author.
prajyod said...

Hi how can i filter perspectives in my rcp application.. i have around 10 perspectives when i open a perspective i should show only 3 perspectives how can u make this.

I used configurer.setShowPerspectiveBar(true); in my ApplicationWorkbenchWindowAdvisor by using this 10 perspectives are shown when i click on openPerspective button ,how can i show only 3 perspective
Thanks in advance

Vasav Shah said...

I am having a view with CheckBoxTreeViewer inside. Now when I am trying to retrieve the selection of the tree using the getSlection() method, it gives me EMPTY_SELECTION.

Please help me to solve the problem . I am using ECLIPSE 3.2.

Sharon said...

This is slightly off your topic but related to restoring the workbench state. I have a perspective with just an editor window (yes, it's an RCP application 3.6). If I close the editor, the perspective remains open....if I close the workbench in this state, and then re-open it, my perspectiveFactory class is not called, and I have no way to determine that the perspective has been re-instated. Do you know of a good way to deal with this? Right now my only thought is to close the perspective if the user closes the editor.

Thanks in advance.

shine said...

It's very useful for me. Thank you.