Saturday, September 13, 2008

Add pulldown actions to Eclipse View's Toolbars

The actions added to the org.eclipse.ui.actionSets extension point (which allows contribution to the Wokbench Window's toolbars) allow the pulldown style. However the actions added to the org.eclipse.ui.viewActions extension point do not allow the pulldown style. IMHO this is a annoying limitation. It may be that the original reason for this limitation was to avoid confusion with the drop down menu in the View toolbars. However the visual of a pulldown action down action is different enough that it is not confusing. Besides the pull down actions are used in View toolbars of many Eclipse provided Views e.g. Open Console action on the as Console view's toolbar. So how are such actions created? Well such actions are programatically created during the View's createPartControl() invocation. However that is not always the case. You may want to contribute a pulldown action to a View created elsewhere. In this entry I show you how to do exactly that programatically.

The basic idea behind this is to watch for opening of the view that you are interested in and programatically add the pulldown style action when the view is opened. Just put the following code in your plug-in's Activator. One thing to keep in mind is that your plug-in may get activated some time after the View that you are contributing a pull down action to - was already created. To handle that we process all the exiting windows that are already present when our code activates. We monitor the opening of the views in the Workbench windows by adding the IPartListener to the Window's PartService. What happens if the user creates more Workbench windows and then openes the View of interest in that Workbench window. Well, we monitor creation of new Workbench windows by adding the IWindowListener to the Workbench. We keep track of the fact that the action was added to the View's toolbar in a WeakHashMap (keyed by the IViewPart) so that we add the action only once. This is because the addActions() is called from multiple places in the following code. One more thing...the action you add must use SWT.AS_DROP_DOWN_MENU style and also implement the IMenuCreator intreface. That's it. Here is the code:
private static WeakHashMap actionsAddedToView = new WeakHashMap();
private static void addActions(IViewPart viewPart)
{
Boolean added = actionsAddedToView.get(viewPart);
if (added == null) {
// The actions were not added yet
final IToolBarManager toolBarManager = viewPart.getViewSite().getActionBars().getToolBarManager();

// SomePulldownAction extends Action implements IMenuCreator
// public SomePulldownAction() {
// super("Some Action...", IAction.AS_DROP_DOWN_MENU);
// }
// Also implement the getMenu() action.
// public Menu getMenu(Control parent) {
// create menu
// add menu items
// return the menu
// }
SomePulldownAction someDownloadAction = new SomePulldownAction();
someDownloadAction.init(viewPart);
toolBarManager.insertAfter("id-of-an-exiting-action-on-views-toolbar", someDownloadAction); //$NON-NLS-1$

// Add more actions
// ...
// ...
// ...

toolBarManager.update(true);
actionsAddedToView.put(viewPart, Boolean.TRUE);
}
}

// Listner for monitoring the view opening
private static final IPartListener partListener = new PartListenerAdapter()
{
@Override
public void partOpened(IWorkbenchPart part)
{
if (part instanceof IViewPart)
{
IViewPart viewPart = (IViewPart) part;
if ("-id-of-the-view-to-which-you-want-to-add-the-pulldown-action".equals(viewPart.getSite().getId()))
{
addActions(viewPart);
}
}
}

@Override
public void partClosed(IWorkbenchPart part)
{
if (part instanceof IViewPart)
{
IViewPart viewPart = (IViewPart) part;
if ("-id-of-the-view-to-which-you-want-to-add-the-pulldown-action".equals(viewPart.getSite().getId()))
{
// forget the view's actions added state
actionsAddedToView.remove(viewPart);
}
}
}
};

private static void processWindow(IWorkbenchWindow window)
{
IWorkbenchPage[] pages = window.getPages();
for (IWorkbenchPage workbenchPage : pages)
{
IViewPart viewPart = workbenchPage.findView("-id-of-the-view-to-which-you-want-to-add-the-pulldown-action");
if viewPart != null && viewPart.getSite() != null)
{
addActions(viewPart);
break;
}
}

// Monitor furture view creation in case the view
// is closed and reopened
window.getPartService().addPartListener(partListener);
}

static {
// Add pulldown action to the view that may be already present in
// exiting Workbench windows.
IWorkbenchWindow[] workbenchWindows = PlatformUI.getWorkbench().getWorkbenchWindows();
for (IWorkbenchWindow workbenchWindow : workbenchWindows)
{
processWindow(workbenchWindow);
}

// Monitor future Workbench windows
PlatformUI.getWorkbench().addWindowListener(new IWindowListener()
{
public void windowActivated(IWorkbenchWindow window) {}
public void windowClosed(IWorkbenchWindow window) {}
public void windowDeactivated(IWorkbenchWindow window) {}
public void windowOpened(IWorkbenchWindow window)
{
processWindow(window);
}
});
}

No comments: