In this post I’ll demonstrate a solution I used to keep track of Eclipse editors and hide/restore them on switching between perspectives.

Eclipse RCP currently only allows you to have one editor area that is shared between all perspectives. Certain use cases may require having a separate collection of editors associated to different perspectives. For example in an email client you may like to have one perspective with all your email editors and another perspective that only displays editors for appointments.

According to Eclipse Bug 11001 there are plans to address this in Eclipse e4, and in the meantime features have been added in Eclipse 3.5 to enable you to hide and subsequently restore an editor.

The two methods that have been added to org.eclipse.ui.IWorkbenchPage are:

public void hideEditor(IEditorReference ref);
public void showEditor(IEditorReference ref);

According to the API, a hidden editor becomes a non-participating editor that will not be visible in the editor area, but will continue to participate in the save lifecycle. So all we need to do is to keep track of the editor references that are to be hidden, and those to be shown on switching perspectives.

All of the changes necessary for this can be confined to your application’s WorkbenchWindowAdvisor class. To keep track of the editor references I added two HashMap’s; one for storing the editor references for each perspective, and one for maintaining a reference to the last active editor within the editor area for each perspective. The last active editor reference is needed so that we can tell the workbench page which editor to send to the top.

	private HashMap<String, ArrayList<IEditorReference>> perspectiveEditors = new HashMap<String, ArrayList<IEditorReference>>();
	private HashMap<String, IEditorReference> lastActiveEditors = new HashMap<String, IEditorReference>();

To keep track of the editors that belong to each perspective I add an IPartListener to the IPartService from within the preWindowOpen() method. When a FormEditor part is opened, the active perspective is retrieved and the perspectiveEditors HashMap updated with the perspective id and editor reference.

    	IPartService service = (IPartService) configurer.getWindow().getService(IPartService.class);
    	service.addPartListener(new IPartListener() {

			public void partActivated(IWorkbenchPart part) {
			}

			public void partBroughtToTop(IWorkbenchPart part) {
			}

			public void partClosed(IWorkbenchPart part) {
			}

			public void partDeactivated(IWorkbenchPart part) {
			}

			public void partOpened(IWorkbenchPart part) {
				if (part instanceof FormEditor) {
					FormEditor editor = (FormEditor)part;
					IWorkbenchPage page = part.getSite().getPage();
					IEditorInput editorInput = editor.getEditorInput();
					IPerspectiveDescriptor activePerspective = page.getPerspective();

					ArrayList<IEditorReference> editors = perspectiveEditors.get(activePerspective.getId());
					if (editors == null)
						editors = new ArrayList<IEditorReference>();

					// 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);
					}
				}
			}
    	});

A perspective listener is also added so that when a perspective is deactivated, the currently active editor if any is stored as the last active editor. When a perspective is activated the listener hides all participating editors, re-shows the editors associated with this perspective, and sends the last active editor to the top of the editor area.

		configurer.getWindow().addPerspectiveListener(new PerspectiveAdapter() {
            public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
				updateTitle();

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

				// Show the editors associated with this perspective
				ArrayList<IEditorReference> editorRefs = perspectiveEditors.get(perspective.getId());
				if (editorRefs != null) {
					for (Iterator<IEditorReference> it = editorRefs.iterator(); it.hasNext(); ) {
						IEditorReference editorInput = it.next();
						page.showEditor(editorInput);
					}

					// Send the last active editor to the top
					IEditorReference lastActiveRef = lastActiveEditors.get(perspective.getId());
					page.bringToTop(lastActiveRef.getPart(true));
				}
			}

            public void perspectiveSavedAs(IWorkbenchPage page, IPerspectiveDescriptor oldPerspective, IPerspectiveDescriptor newPerspective) {
				updateTitle();
			}

            public void perspectiveDeactivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
				updateTitle();
				IEditorPart activeEditor = page.getActiveEditor();
				if (activeEditor != null) {

					// Find the editor reference that relates to this editor input
					IEditorReference[] editorRefs = page.findEditors(activeEditor.getEditorInput(), null, IWorkbenchPage.MATCH_INPUT);
					if (editorRefs.length > 0) {
						lastActiveEditors.put(perspective.getId(), editorRefs[0]);
					}
				}
			}
		});

And that’s all that’s required to switch between perspectives and maintain separate editors! I’ve uploaded the complete source for a sample application WorkbenchWindowAdvisor class that you can download here:
ApplicationWorkbenchWindowAdvisor.java

About

Welcome to my personal website and blog which I hope to keep updated with various tips and tricks relating to various interests of mine including software development, technical analysis of the stock market, and juggling. The views expressed on this site are my own and do not necessarily reflect the views of Oracle.More info about me..

Categories

Archives

  • Ingo: Thank you very much for this article. I needed such a solution since a long time, unfortunately I mi [...]
  • emil: Thanks for this post. It was very useful. [...]
  • Jay: You saved my ass with this article, thank you :-) [...]