| /****************************************************************************** |
| * Copyright (c) 2002, 2008 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| ****************************************************************************/ |
| |
| package org.eclipse.gmf.runtime.common.ui.action; |
| |
| import org.eclipse.gmf.runtime.common.core.util.Log; |
| import org.eclipse.gmf.runtime.common.ui.internal.CommonUIPlugin; |
| import org.eclipse.gmf.runtime.common.ui.internal.CommonUIStatusCodes; |
| import org.eclipse.jface.action.AbstractGroupMarker; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.ActionContributionItem; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.action.IContributionItem; |
| import org.eclipse.jface.action.IContributionManager; |
| import org.eclipse.jface.action.IMenuCreator; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.action.SubContributionItem; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swt.widgets.MenuItem; |
| import org.eclipse.swt.widgets.ToolBar; |
| import org.eclipse.ui.actions.LabelRetargetAction; |
| |
| /** |
| * An implementation of an <code>IMenuManager</code> that inherits its |
| * UI (text + icon + hints) from a given action. |
| * |
| * When filled in a toolbar, the menu is rendered as a tool item |
| * with two parts: a button, whose icon comes from the supplied |
| * action handler, and a drop-down menu arrow. |
| * When the arrow is pressed, the drop-down menu is shown. When the |
| * button is pressed, the associated action is executed. The manager can have |
| * an optional style to retarget the last executed action. In this |
| * case the tool item UI reflects the last executed sub-action from the menu. |
| * |
| * When filled in a menu, this menu shows up as a normal cascading menu with |
| * its GUI inherited from the supplied action. |
| * |
| * @author melaasar |
| */ |
| public class ActionMenuManager extends MenuManager { |
| |
| /** |
| * An action that provides a menu and fills it from the contribution |
| * items of the enclosing menu manager. It also retargets to the |
| * manager's supplied action handler. |
| */ |
| public class MenuCreatorAction |
| extends LabelRetargetAction |
| implements IMenuCreator { |
| // the menu widget |
| private Menu menu; |
| |
| // menu item selection listener: listens to selection events |
| private Listener menuItemListener = new Listener() { |
| public void handleEvent(Event event) { |
| if (SWT.Selection == event.type |
| && !event.widget.isDisposed()) { |
| ActionContributionItem item = |
| (ActionContributionItem) event.widget.getData(); |
| if (retargetLastAction) { |
| setActionHandler(item.getAction()); |
| setDefaultAction(item.getAction()); |
| } |
| subActionSelected(item.getAction()); |
| } |
| } |
| }; |
| |
| /** |
| * Creates a new menu creator action |
| * |
| * @param actionHandler the action handler |
| */ |
| public MenuCreatorAction(IAction actionHandler) { |
| super(actionHandler.getId(), actionHandler.getText()); |
| setEnabled(false); // initially untill a menu item is added |
| setActionHandler(actionHandler); |
| setMenuCreator(this); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IMenuCreator#getMenu(org.eclipse.swt.widgets.Control) |
| */ |
| public Menu getMenu(Control parent) { |
| if (menu != null) |
| menu.dispose(); |
| |
| menu = new Menu(parent); |
| return createMenu(menu); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IMenuCreator#getMenu(org.eclipse.swt.widgets.Menu) |
| */ |
| public Menu getMenu(Menu parent) { |
| if (menu != null) |
| menu.dispose(); |
| menu = new Menu(parent); |
| return createMenu(menu); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.actions.ActionFactory.IWorkbenchAction#dispose() |
| */ |
| public void dispose() { |
| if (menu != null) { |
| menu.dispose(); |
| menu = null; |
| } |
| super.dispose(); |
| ActionMenuManager.this.dispose(); |
| } |
| |
| /** |
| * Create the drop-down/pop-up menu. |
| * |
| * @param mnu <code>Menu</code> for which to create the drop-down/pop-up menu |
| * @return <code>Menu</code> the drop-down/pop-up menu |
| */ |
| protected Menu createMenu(Menu mnu) { |
| IContributionItem[] items = getRealItems(); |
| IContributionItem lastGroupMarker = null; |
| for (int i = 0; i < items.length; i++) { |
| IContributionItem item = items[i]; |
| if (item instanceof AbstractGroupMarker) { |
| if (i == 0 |
| || i == items.length - 1 |
| || items[i + 1] instanceof AbstractGroupMarker |
| || mnu.getItemCount() < 1 |
| || !item.isVisible()) { |
| continue; |
| } else { |
| // Do not add last group marker until we know that there |
| // will be items following it. |
| lastGroupMarker = item; |
| } |
| } else { |
| if (!item.isVisible()) { |
| continue; |
| } |
| try { |
| if (lastGroupMarker != null) { |
| lastGroupMarker.fill(menu, -1); |
| lastGroupMarker = null; |
| } |
| item.fill(menu, -1); |
| } catch (Exception e) { |
| Log.info(CommonUIPlugin.getDefault(), CommonUIStatusCodes.GENERAL_UI_FAILURE, "The contribution item (" + item.getId() + ") failed to fill within the menu"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| } |
| MenuItem menuItems[] = mnu.getItems(); |
| for (int i = 0; i < menuItems.length; i++) { |
| if (menuItems[i].getStyle() == SWT.SEPARATOR) |
| continue; |
| menuItems[i].addListener(SWT.Selection, menuItemListener); |
| } |
| return mnu; |
| } |
| |
| /** |
| * Ignores the action handler's "enable" event since "enablement" |
| * is determined by the sub-action(s) enablement state |
| * |
| */ |
| protected void propagateChange(PropertyChangeEvent event) { |
| if (!event.getProperty().equals(Action.ENABLED)) |
| super.propagateChange(event); |
| } |
| |
| /** |
| * Ignores the action handler's "enable" event since "enablement" |
| * is determined by the sub-action(s) |
| * |
| */ |
| protected void setActionHandler(IAction handler) { |
| boolean enabled = MenuCreatorAction.this.isEnabled(); |
| super.setActionHandler(handler); |
| MenuCreatorAction.this.setEnabled(enabled); |
| } |
| |
| /** |
| * Only run the action handler if it is enabled |
| * |
| */ |
| public void run() { |
| if (getActionHandler() != null && getActionHandler().isEnabled()) |
| super.run(); |
| else if (getDefaultAction().isEnabled()) { |
| setActionHandler(getDefaultAction()); |
| super.run(); |
| } |
| } |
| |
| /** |
| * Only run the action handler if it is enabled |
| * |
| */ |
| public void runWithEvent(Event event) { |
| if (getActionHandler() != null && getActionHandler().isEnabled()) |
| super.runWithEvent(event); |
| else if (getDefaultAction().isEnabled()) { |
| setActionHandler(getDefaultAction()); |
| super.runWithEvent(event); |
| } |
| } |
| |
| } |
| |
| /** the associated menu action */ |
| protected final MenuCreatorAction action; |
| |
| /** the associated menu action */ |
| protected IAction defaultAction = null; |
| |
| /** the delege action contribution item */ |
| private final ActionContributionItem actionContributionItem; |
| |
| /** an option to retarget the last action */ |
| private boolean retargetLastAction; |
| |
| /** |
| * Creates a new instance of <code>ActionMenuManager</code> with |
| * a given action handler. The manager does not retarget the last |
| * selected action from the menu |
| * |
| * @param id The menu manager id |
| * @param actionHandler the menu associated action handler |
| */ |
| public ActionMenuManager(String id, IAction actionHandler) { |
| this(id, actionHandler, false); |
| } |
| |
| /** |
| * Creates a new instance of <code>ActionMenuManager</code> with |
| * a given action handler and an option to retarget the last |
| * executed menu action. |
| * |
| * @param id The menu manager id |
| * @param actionHandler the menu associated action handler |
| * @param retargetLastAction whether to retarget the last action or not |
| */ |
| public ActionMenuManager( |
| String id, |
| IAction actionHandler, |
| boolean retargetLastAction) { |
| super(actionHandler.getText(), id); |
| assert null != actionHandler; |
| action = new MenuCreatorAction(actionHandler); |
| defaultAction = actionHandler; |
| actionContributionItem = new ActionContributionItem(action); |
| this.retargetLastAction = retargetLastAction; |
| } |
| |
| /** |
| * Returns whether the option to retarget last action was requested |
| * |
| * @return <code>true</code> if retargetLastAction is enabled, <code>false</code> otherwise |
| */ |
| protected boolean isRetargetLastAction() { |
| return retargetLastAction; |
| } |
| |
| /** |
| * Handle subaction selection |
| * |
| * @param subActionHandler The selected sub action handler |
| */ |
| protected void subActionSelected(IAction subActionHandler) { |
| /* method not implemented */ |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#fill(org.eclipse.swt.widgets.Composite) |
| */ |
| public void fill(Composite parent) { |
| // this is only relevant in toolbars |
| retargetLastAction = false; |
| actionContributionItem.fill(parent); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#fill(org.eclipse.swt.widgets.Menu, int) |
| */ |
| public void fill(Menu parent, int index) { |
| // this is only relevant in toolbars |
| retargetLastAction = false; |
| actionContributionItem.fill(parent, index); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#fill(org.eclipse.swt.widgets.ToolBar, int) |
| */ |
| public void fill(ToolBar parent, int index) { |
| actionContributionItem.fill(parent, index); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#dispose() |
| */ |
| public void dispose() { |
| actionContributionItem.dispose(); |
| super.dispose(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#isEnabled() |
| */ |
| public boolean isEnabled() { |
| return actionContributionItem.isEnabled(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionManager#isDirty() |
| */ |
| public boolean isDirty() { |
| return actionContributionItem.isDirty(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#isDynamic() |
| */ |
| public boolean isDynamic() { |
| return actionContributionItem.isDynamic(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#isGroupMarker() |
| */ |
| public boolean isGroupMarker() { |
| return actionContributionItem.isGroupMarker(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#isSeparator() |
| */ |
| public boolean isSeparator() { |
| return actionContributionItem.isSeparator(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#isVisible() |
| */ |
| public boolean isVisible() { |
| IContributionItem[] items = getRealItems(); |
| for (int i = 0; i < items.length; i++) { |
| IContributionItem item = items[i]; |
| if (!(item instanceof AbstractGroupMarker) && item.isVisible()) { |
| return actionContributionItem.isVisible(); |
| } |
| } |
| return false; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#setParent(org.eclipse.jface.action.IContributionManager) |
| */ |
| public void setParent(IContributionManager parent) { |
| actionContributionItem.setParent(parent); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#setVisible(boolean) |
| */ |
| public void setVisible(boolean visible) { |
| actionContributionItem.setVisible(visible); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#update() |
| */ |
| public void update() { |
| actionContributionItem.update(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#update(java.lang.String) |
| */ |
| public void update(String id) { |
| actionContributionItem.update(id); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IMenuManager#updateAll(boolean) |
| */ |
| public void updateAll(boolean force) { |
| update(force); |
| |
| IContributionItem[] items = getRealItems(); |
| for (int i = 0; i < items.length; ++i) { |
| IContributionItem ci = items[i]; |
| if (ci instanceof IMenuManager) { |
| IMenuManager mm = (IMenuManager) ci; |
| if (mm.isVisible()) { |
| mm.updateAll(force); |
| } |
| } |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionManager#update(boolean) |
| */ |
| public void update(boolean force) { |
| update(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.ContributionManager#itemAdded(org.eclipse.jface.action.IContributionItem) |
| */ |
| protected void itemAdded(IContributionItem item) { |
| super.itemAdded(item); |
| if (item instanceof SubContributionItem) |
| item = ((SubContributionItem) item).getInnerItem(); |
| if (!item.isGroupMarker()) |
| action.setEnabled(true); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.ContributionManager#itemRemoved(org.eclipse.jface.action.IContributionItem) |
| */ |
| protected void itemRemoved(IContributionItem item) { |
| super.itemRemoved(item); |
| if (item instanceof SubContributionItem) |
| item = ((SubContributionItem) item).getInnerItem(); |
| if (!item.isGroupMarker()) { |
| action.setEnabled(false); |
| IContributionItem[] items = getItems(); |
| for (int i = 0; i < items.length; i++) |
| if (!items[i].isGroupMarker()){ |
| action.setEnabled(true); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Returns the contribution items of this manager. If an item |
| * is wrapper in a SubContributionItem instance it extracts the |
| * real item instance |
| * |
| * @return An array of real items of this contribution manager |
| */ |
| protected IContributionItem[] getRealItems() { |
| IContributionItem[] items = getItems(); |
| IContributionItem[] realItems = new IContributionItem[items.length]; |
| for (int i = 0; i < items.length; i++) { |
| if (items[i] instanceof SubContributionItem) { |
| realItems[i] = ((SubContributionItem) items[i]).getInnerItem(); |
| } else { |
| realItems[i] = items[i]; |
| } |
| } |
| return realItems; |
| } |
| |
| |
| public IAction getDefaultAction() { |
| return defaultAction; |
| } |
| |
| |
| protected void setDefaultAction(IAction defaultAction) { |
| this.defaultAction = defaultAction; |
| } |
| |
| } |