Thursday, March 1, 2007

Show View Shortcuts

Show View Shortcuts:
In Eclipse, you can click the 'Window->Show View' menu, and you see a bunch of views available for quick showing within the current perspective.

Where I started:
From my research in how to get the 'Window->Show View' menu, I knew that org.eclipse.ui.internal.ShowViewMenu was used by the IContributionItem created by the VIEWS_SHORTLIST ContributionFactory in the org.eclipse.ui.workbench plug-in. Thus, my search began there.

Inside the ShowViewMenu#fillMenu(IMenuManager) method, the Menu is populated with view ids retrieved from the active org.eclipse.ui.IWorkbenchPage. Tracing references to this method should aid us. Unfortunately, ShowViewMenu#fillMenu(IMenuManager) is the only reference. Thus, we must dig into the implementation class, org.eclipse.ui.internal.WorkbenchPage.

org.eclipse.ui.internal.WorkbenchPage#getShowViewShortcuts() retrieves its data from the active org.eclipse.ui.internal.Perspective with the org.eclipse.ui.internal.Perspective#getShowViewShortcuts() method. Inside this method, we see a java.util.ArrayList of view ids stored internally. Searching for references within the class turns up the org.eclipse.ui.internal.Perspective#loadPredefinedPesp(PerspectiveDescriptor) method. It sets the view ids based on the value given by the org.eclipse.ui.internal.PageLayout#getShowViewShortcuts() method. This method maintains its own java.util.ArrayList of view ids. Searching for its references, we find we can add view ids with the org.eclipse.ui.internal.PageLayout#addShowViewShortcut(String) method. Encouragingly, this method is also part of the org.eclipse.ui.IPageLayout public API.

Now, we have the method to call to add a view to the top-level "Show View" menu. We just need to find where it is used. Searching for references to org.eclipse.ui.IPageLayout#addShowViewShortcut(String) yields the org.eclipse.ui.internal.ide.ResourcePerspective#defineActions(IPageLayout) method in the org.eclipse.ui.ide plug-in. Again, this method is not part of the public API, but it is only used inside the org.eclipse.ui.internal.ide.ResourcePerspective#createInitialLayout(IPageLayout) method. This method implements the org.eclipse.ui.IPerspectiveFactory#createInitialLayout(IPageLayout) method, and provides a good example for how to exercise the public API.

Most Likely Public API:
To define which views should be available as shortcuts under the 'Show View' Menu, add the view ids with the org.eclipse.ui.IPageLayout#addShowViewShortcut(String) method on the org.eclipse.ui.IPageLayout that is passed to the org.eclipse.ui.IPerspectiveFactory#createInitialLayout(IPageLayout) method. The IPerspectiveFactory is responsible for defining the layout of your perspective.

Show View

Show View:
In the IDE, you can use the 'Window->Show View' menu to open any view available. Additionally, there are some views that have shortcuts, and they appear to change with the selected perspective.

Where I Started:
I guessed that putting a breakpoint in a view that shows up in the default perspective would lead me to the IAction that represented the 'Window->Show View' menu.

My target platform is Eclipse 3.2.1, and I debugged the org.eclipse.sdk.ide product with the following required plug-ins (select these plug-ins and then click the 'Add Required Plug-ins' button):
org.eclipse.sdk
org.eclipse.ui.ide

This starts up a minimal Eclipse IDE with only the Resource perspective. I placed a breakpoint in the org.eclipse.ui.views.markers.internal.BookmarkView#createPartControl(Composite) method
and clicked 'Window->Show View->Bookmarks' menu item.

This lead to the following call stack:
BookmarkView.createPartControl(Composite) line: 96
ViewReference.createPartHelper() line: 332
ViewReference.createPart() line: 197
ViewReference(WorkbenchPartReference).getPart(boolean) line: 566
Perspective.showView(String, String) line: 1675
WorkbenchPage.busyShowView(String, String, int) line: 987
WorkbenchPage.access$13(WorkbenchPage, String, String, int) line: 968
WorkbenchPage$13.run() line: 3514
BusyIndicator.showWhile(Display, Runnable) line: 67
WorkbenchPage.showView(String, String, int) line: 3511
WorkbenchPage.showView(String) line: 3487
ShowViewAction.run() line: 76
ShowViewAction(Action).runWithEvent(Event) line: 499
...

org.eclipse.ui.internal.ShowViewAction was a likely candidate, so I opened that it and searched for references, which returned only org.eclipse.ui.internal.ShowViewMenu#getAction(String). Since I'm looking for a public API, and any package with 'internal' in the name is not for public use, I kept searching, this time for references to ShowViewMenu. This seach returned org.eclipse.ui.actions.ContributionItemFactory#VIEWS_SHORTLIST. This is a public API, and is probably the API I want to use to get an IContributionItem for my 'Show View' menu item.

As an aside, you may have noticed that the ContributionItemFactory isn't dealing with IActions. IMenuManagers really need IContributionItems to be added to them, not IActions. The IMenuManager is in fact an IContributionManager, which is an interface for anything that manages IContributionItems, including the ICoolBarManager, IStatusLineManager, and IToolBarManager. The IContributionManager#add(IAction) method is really just a convenience method that wraps the IAction in an IContributionItem.

So, now I had a public API for my 'Show View' menu item, but I didn't know the best way to use it. So, I did a search for references to ContributionItemFactory#VIEWS_SHORTLIST, and found org.eclipse.internal.ide.WorkbenchActionBuilder. On line 670 in the addPerspectiveActions(MenuManager) method, the 'Show View' IContributionItem, IContributionItem returned from ContributionItemFactory#VIEWS_SHORTLIST, is added to a new MenuManager, which is added to the IDE's 'Window' MenuManager.

I didn't understand why the IContributionItem needed to be in its own IMenuManager, since it seemed like the best option is just to add it to the 'Window' MenuManager directly. To experiment, I did just that. In my ActionBarAdvisor (the class responsible for adding IActions to the IWorkbenchWindow), I added the
'Show View' IContributionItem to my 'Window' MenuManager, and I only saw a separator and 'Other...' menu items. So, the 'Show View' IContributionItem is really only responsible for populating the sub-menu beneath an already existing 'Show View' menu.

Another result of my experiment was that the 'Show View' submenu only had the separator and 'Other...' menu items. It didn't have any of my application's views. If I clicked the 'Other...' menu item, I received the same dialog I'm used to in the IDE that showed all views broken into categories. All my views were there, so how'd Eclipse do that? We'll save that for the next (hopefully shorter) post.

Most Likely Public API:
Googling "Eclipse 'show view'" turned up the following nothing of interest other than an eclipse news post asking the same question I did. Hopefully, that person finds this blog.

Thus, my guess is that if you want the 'Show View' menu inside your RCP application, create a MenuManager for it and add to that MenuManager the IContributionItem returned by ContributionItemFactory#VIEWS_SHORTLIST#create(IWorkbenchWindow),
which exists in the org.eclipse.ui.workbench plug-in. Then, add your MenuManager to any existing MenuManager, usually one you created in ActionBarAdvisor#fillMenuBar(IMenuManager).

Intro

I'm an Eclipse RCP developer, and am constantly searching the eclipse source code for the best way to implement featues on an Eclipse RCP application. Usually, I find a similar feature in the Eclipse IDE; set a few breakpoints in the Eclipse source; and follow the code until a decipher the public API.

This blog will be a record of my findings. I'm going to try the following format:

Feature:
The behavior in the Eclipse IDE I want to emulate.

Where I started:
The Eclipse IDE source files and line numbers I started with. At the end of this section, I'll detail where Eclipse does the real work.

Most Likely Public API:
The API available to implement the feature, and the plug-ins in which it is located. Additionally, I'll post some links to real documentation if I can find it.