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

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

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 

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

Topics:

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

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

{{ parent.tldr }}

{{ parent.urlSource.name }}