Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to properly hide editors, when switching between perspectives in eclipse rcp application

DZone's Guide to

How to properly hide editors, when switching between perspectives in eclipse rcp application

· Java Zone
Free Resource

Get the Edge with a Professional Java IDE. 30-day free trial.

Long story short... In Eclipse RCP application it is not possible to hide editors, which are currently opened, when switching between perspectives. "Not possible" means, that it is not built in functionality (as for views), so it is needed to hack in order to make it working (hacking is always good, right?). Unfortunately, it brings some troubles and therefore more hacks. But still, if you need it, it should be done.

 So, there is already a pretty good blog post about hiding editors: http://www.niallkelly.com/?p=1 . Unfortunately, if you make your editors to be persisted into memento, and then restored, when application is restarted, you will find an empty perspective. I spent some time, debugging the process, how editors are restored, but the answer was simple:
 
perspectiveActivated() {
...

 // Hide all the editors
IEditorReference[] editors = page.getEditorReferences();
for (int i = 0; i < editors.length; i++) {
   page.hideEditor(editors[i]);
}

..
}

 This code snippet the cruel job. Apparently, we don't want it to work like that and will try to improve it. In order to restore an editor from the memento we need to create an EditorInput object. We could use this object afterwards to check, if this editor is restored from memento or not (we still like hacks, right?:S), if so, we will not hide it:

// Hide all editors
final IEditorReference[] editorReferences = workbenchPage.getEditorReferences();
for (final IEditorReference editorReference : editorReferences) {
    try {
        final IEditorInput editorInput = editorReference.getEditorInput();
        if (editorInput instanceof AbstractBEEditorInput) {
            final AbstractBEEditorInput abstractBEEditorInput = (AbstractBEEditorInput) editorReference.getEditorInput();
            if (!abstractBEEditorInput.isRestoredInput()) {
                workbenchPage.hideEditor(editorReference);
            } else {
                abstractBEEditorInput.setRestoredInput(false);
            }
        }
    } catch (final PartInitException e) {
        // log
    }
}
 For sure, this not seem to be the most elegant solution, but still it can be used.

 Another problem was in this code snippet:
  // Find the editor reference that relates to this editor input
 IEditorReference[] editorRefs = page.findEditors(editorInput, null, IWorkbenchPage.MATCH_INPUT);
 
if (editorRefs.length > 0) {
   editors.add(editorRefs[0]);
   perspectiveEditors.put(activePerspective.getId(), editors);
}
Sometimes it can not find editors by input (for me the reason was in overrided "equals" method in AbstractBEEditorInput object, which didn't work as excpected to match input).That is why I had to fix partOpened method to always find all opened editors:

public void partOpened(final IWorkbenchPart workbenchPart) {
    if (workbenchPart instanceof EditorPart) {
        final EditorPart editorPart = (EditorPart) workbenchPart;
        final IWorkbenchPage workbenchPage = editorPart.getSite().getPage();

        final IPerspectiveDescriptor activePerspective = workbenchPage.getPerspective();
        allEditorReferences = perspectiveIdToEditorReferencesMap.get(activePerspective.getId());
        if (allEditorReferences == null) {
            allEditorReferences = new CopyOnWriteArrayList<IEditorReference>();
            perspectiveIdToEditorReferencesMap.put(activePerspective.getId(), allEditorReferences);
        }

        // store editors, which are opened in current perspective
        allEditorReferences.addAll(Arrays.asList(workbenchPage.getEditorReferences()));
         }
}
The trick here is to have maps and lists from concurrent package. It is needed to avoid ConcurrentModificationException, which can occur, when application is restarted and you immediately switch perspective. I have fixed it in the following way:
 

private List<IEditorReference> allEditorReferences = new CopyOnWriteArrayList<IEditorReference>();
private final Map<String, List<IEditorReference>> perspectiveIdToEditorReferencesMap = new ConcurrentHashMap<String, List<IEditorReference>>();
private final HashMap<String, IEditorReference> perspectiveIdToLastActiveEditorMap = new HashMap<String, IEditorReference>();

...


synchronized (perspectiveIdToEditorReferencesMap) {

                allEditorReferences = perspectiveIdToEditorReferencesMap.get(perspectiveId);
                if (allEditorReferences != null) {
                    synchronized (allEditorReferences) {
                        for (final IEditorReference editorReference : allEditorReferences) {
                            final IEditorInput editorInput = editorReference.getEditorInput();
                            workbenchPage.showEditor(editorReference);
                        }
                    }
                }



I hope that it will help someone. Any ideas/comments are very welcome.

Cheers,


AlexG 

Get the Java IDE that understands code & makes developing enjoyable. Level up your code with IntelliJ IDEA. Download the free trial.

Topics:

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}