Show / Hide Eclipse RCP Editors depending on the current Perspective

Hi,

Here’s a new post about how to customize your Eclipse RCP (Rich Client Platform) application.
Note: I have strongly inspired my solution for this post from from niall kelly’s blog.

Imagine you have several perspectives in your product, usually provided by several plugins, each perspective shows a different view of your application (actually, in Eclipse terms, a perspective is a container for a set of views and editors).
While each perspective will define its own set of views, the editors are shared between perspectives. The simplest example: in Eclipse itself, when you switch between perspectives – for instance from java to debug perspectives, the views will change but the editors will remain the same – you can still see and edit your open java files, for instance.

For my product (The ProActive Studio) I wanted to “stick” an editor with a perspective. Lets say I have 2 perspectives (actually I have more than that): a design perspective, which alow the user to edit workflow diagrams, and a monitoring perspective, which alow the user to see the execution (a graphical representation of the execution) of the workflows. I need editors from thee design perspective to be hidden when the user changes to the monitoring perspective. In the same way, if the monitoring perspective provides some editors, I don’t want them to be visible in the design perspective. My user will either design a workflow or monitor its execution, I don’t want him/her to do both at a time, at least not by default.

Now let’s see how I did this:

1. Implement an Editors Tracker
I need a class which keeps track of all editors and the relationships between the editors and the perspectives. We consider that an editor corresponds to a perspective if that perspective was active when the editor was created. An instance of our class will have to listen to the workbench to know when editors are opened or closed.

public class WorkbenchEditorsTracker implements IPartListener{

	/**
	 * Stores a list of editors corresponding to each perspective
	 */
	private  HashMap<String, ArrayList<IEditorReference>> perspectiveEditors = new HashMap<String, ArrayList<IEditorReference>>();
	
	/**
	 * Stores an active editor for each perspective 
	 */
	private  HashMap<String, IEditorReference> lastActiveEditors = new HashMap<String, IEditorReference>();

	
	@Override
	public void partActivated(IWorkbenchPart part) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void partBroughtToTop(IWorkbenchPart part) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void partClosed(IWorkbenchPart part) {
		 if (part instanceof EditorPart) {
			 //remove the editor from the perspective editors 
             IWorkbenchPage page = part.getSite().getPage();
             IPerspectiveDescriptor activePerspective = page.getPerspective();
             ArrayList<IEditorReference> editors = perspectiveEditors.get(activePerspective.getId());
             if (editors==null)
             {
            	 return;
             }
             Iterator<IEditorReference> iterator = editors.iterator();
	         IEditorReference referenceToRemmove=null;
             while (iterator.hasNext())
	            {
	            	IEditorReference reference = iterator.next();
	            	if (reference.getPart(false) == part)
	            	{
	            		referenceToRemmove = reference;
	            		break;
	            	}
	            }
	            if (referenceToRemmove!=null)
	            	editors.remove(referenceToRemmove);
		 }
	}

	
	@Override
	public void partDeactivated(IWorkbenchPart part) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void partOpened(IWorkbenchPart part) {
        if (part instanceof EditorPart) {
        	EditorPart editor = (EditorPart)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);
            }
        }
    }

	public ArrayList<IEditorReference> getEditorsForPerspective(String activePerspectiveId )
	{
		return perspectiveEditors.get(activePerspectiveId);
	}
	
	public IEditorReference getLastActiveEditor(String activePerspectiveId )
	{
		return lastActiveEditors.get(activePerspectiveId);
	}
	
	public void setLastActiveEditor(String perspectiveID, IEditorReference editor) 
	{
		lastActiveEditors.put(perspectiveID, editor);
		
	}

2. Implement a Perspective Listener, which will listen for perspective changed events and will show or hide the editors accordingly.


public class WorkflowStudioPerspectiveAdapter extends PerspectiveAdapter {

	private WorkbenchEditorsTracker workbenchEditorsTracker;
	
	public WorkflowStudioPerspectiveAdapter(WorkbenchEditorsTracker workbenchEditorsTracker )
	{
		this.workbenchEditorsTracker = workbenchEditorsTracker;
	}
	
	@Override
	public void perspectiveActivated(IWorkbenchPage page,
			IPerspectiveDescriptor perspectiveDescriptor) {
		super.perspectiveActivated(page, perspectiveDescriptor);
	 // ----------------------------- update editors  --------------------------------
	// ------------------- Only show editors related to the new perspective -------------	
	// 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 = workbenchEditorsTracker.getEditorsForPerspective(perspectiveDescriptor.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 = workbenchEditorsTracker.getLastActiveEditor(perspectiveDescriptor.getId());
            if (lastActiveRef!=null)
            	page.bringToTop(lastActiveRef.getPart(true));
        }
    }

	
	public void perspectiveDeactivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
        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) {
            	workbenchEditorsTracker.setLastActiveEditor(perspective.getId(), editorRefs[0]);
            }
        }
    }
}

3. Susbscribe the listeners to the workbench
In my Workbench Advisor Class (in my case StudioWorkbenchAdvisor), I override the postStartup() method:

	@Override
	public void postStartup()
	{
		IWorkbenchWindow
		workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
		WorkbenchEditorsTracker workkbenchPartListener = new WorkbenchEditorsTracker();
		WorkflowStudioPerspectiveAdapter perspectiveListener = new WorkflowStudioPerspectiveAdapter(workkbenchPartListener);
		IPartService service = (IPartService) workbenchWindow.getService(IPartService.class);
		service.addPartListener(workkbenchPartListener);
		workbenchWindow.addPerspectiveListener(perspectiveListener);
	}

Well, I think this is it …

Advertisements
This entry was posted in Eclipse RCP. Bookmark the permalink.

7 Responses to Show / Hide Eclipse RCP Editors depending on the current Perspective

  1. Sharon says:

    I know you posted this a year ago…but thanks! I used this and Niall’s blog post to help me do something similar. I didn’t want to hide the other editors, just bring the last one used in the perspective up to the top when I re-displayed the perspective.

    I made some minor changes for my purposes. Nothing of real note.

    One thing I noted was that when opening an editor when some of our perspectives received the perspectiveOpened listener notification was too early. The active page was not the one that belonged to our perspective…so when you opened the editor, the partListener would think it belonged to the perspective that you were previously on.

    For example you have perspective A open, with or without an editor. Open perspective B, and it will register a a perspective listener to automatically open the editor when it gets perspectiveOpened. If you just open the editor with the page given in the function header – you will get a partOpened notification for perspective A.

    I intend to blog about this to document it further – I will reference your post when I do, I’ll post a link here when I get it finished for other folks who may need it.

    Thanks again!

    • esalagea says:

      Hi Sharon, I’m glad my post helped you. I’ll be glad if you put a link here to your blog when you finish. I remember I noticed some strange behavior with these editors and perspectives in my application but never had the time to dig into it.

      Cheers,
      emil

      • Sharon says:

        Good to know – I’ll keep an eye out. One thing I did notice was that you never remove the reference in the lastActiveEditor – that may be related to your problem. When closing the part, ensure that the lastActiveEditor for that perspective is removed if it was the editor you are closing.

  2. Pingback: Linking an eclipse editor with the perspective it was opened in « Sharon B. Snyder

  3. Hello

    Good article, it was very useful. However there is something I can’t get, and it is that when you back to a previous perspective the editors layout is not restored. For example, if you move an editor one below the other (no tabs), when you back to that perspective, the layout is lost and the editors are folded in tabs.
    I was trying to fix it but I do not find the way 😦

    Regards
    Arian

  4. Alain Picard says:

    Just a heads up that this no longer works with Mars and others (like Kepler, etc). hideEditor and showEditor are not implemented anymore (https://bugs.eclipse.org/bugs/show_bug.cgi?id=374132 ), neither is perspectiveDeactivated (https://bugs.eclipse.org/bugs/show_bug.cgi?id=408309) which is a shame to break API like this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s