| /******************************************************************************* |
| * Copyright (c) 2000, 2004 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.jface.action; |
| |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.jface.util.Assert; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.CoolBar; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swt.widgets.ToolBar; |
| |
| /** |
| * A <code>SubMenuManager</code> is used to define a set of contribution |
| * items within a parent manager. Once defined, the visibility of the entire set can |
| * be changed as a unit. |
| * <p> |
| * A client may ask for and make additions to a submenu. The visibility of these items |
| * is also controlled by the visibility of the <code>SubMenuManager</code>. |
| * </p> |
| */ |
| public class SubMenuManager extends SubContributionManager implements |
| IMenuManager { |
| |
| /** |
| * Maps each submenu in the manager to a wrapper. The wrapper is used to |
| * monitor additions and removals. If the visibility of the manager is modified |
| * the visibility of the submenus is also modified. |
| */ |
| private Map mapMenuToWrapper; |
| |
| /** |
| * List of registered menu listeners (element type: <code>IMenuListener</code>). |
| */ |
| private ListenerList menuListeners = new ListenerList(); |
| |
| /** |
| * The menu listener added to the parent. Lazily initialized |
| * in addMenuListener. |
| */ |
| private IMenuListener menuListener; |
| |
| /** |
| * Constructs a new manager. |
| * |
| * @param mgr the parent manager. All contributions made to the |
| * <code>SubMenuManager</code> are forwarded and appear in the |
| * parent manager. |
| */ |
| public SubMenuManager(IMenuManager mgr) { |
| super(mgr); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IMenuManager#addMenuListener(org.eclipse.jface.action.IMenuListener) |
| */ |
| public void addMenuListener(IMenuListener listener) { |
| menuListeners.add(listener); |
| if (menuListener == null) { |
| menuListener = new IMenuListener() { |
| public void menuAboutToShow(IMenuManager manager) { |
| Object[] listeners = menuListeners.getListeners(); |
| for (int i = 0; i < listeners.length; ++i) { |
| ((IMenuListener) listeners[i]) |
| .menuAboutToShow(SubMenuManager.this); |
| } |
| } |
| }; |
| } |
| getParentMenuManager().addMenuListener(menuListener); |
| } |
| |
| /** |
| * The default implementation of this <code>IContributionItem</code> |
| * method does nothing. Subclasses may override. |
| */ |
| public void dispose() { |
| // do nothing |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.SubContributionManager#disposeManager() |
| */ |
| public void disposeManager() { |
| if (menuListener != null) { |
| getParentMenuManager().removeMenuListener(menuListener); |
| menuListener = null; |
| clearListenerList(menuListeners); |
| } |
| // Dispose wrapped menus in addition to removing them. |
| // See bugs 64024 and 73715 for details. |
| // important to dispose menu wrappers before call to super, |
| // otherwise super's call to removeAll will remove them |
| // before they can be disposed |
| if (mapMenuToWrapper != null) { |
| Iterator iter = mapMenuToWrapper.values().iterator(); |
| while (iter.hasNext()) { |
| SubMenuManager wrapper = (SubMenuManager) iter.next(); |
| wrapper.disposeManager(); |
| } |
| mapMenuToWrapper.clear(); |
| mapMenuToWrapper = null; |
| } |
| super.disposeManager(); |
| } |
| |
| /** |
| * Clears all of the listeners in a listener list. TODO Bug 117519 Remove |
| * this method when fixed. |
| * |
| * @param list |
| * The list to be clear; must not be <code>null</code>. |
| */ |
| private final void clearListenerList(final ListenerList list) { |
| final Object[] listeners = list.getListeners(); |
| for (int i = 0; i < listeners.length; i++) { |
| list.remove(listeners[i]); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#fill(org.eclipse.swt.widgets.Composite) |
| */ |
| public void fill(Composite parent) { |
| if (isVisible()) |
| getParentMenuManager().fill(parent); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#fill(org.eclipse.swt.widgets.CoolBar, int) |
| */ |
| public void fill(CoolBar parent, int index) { |
| // do nothing |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#fill(org.eclipse.swt.widgets.Menu, int) |
| */ |
| public void fill(Menu parent, int index) { |
| if (isVisible()) |
| getParentMenuManager().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) { |
| if (isVisible()) |
| getParentMenuManager().fill(parent, index); |
| } |
| |
| /* (non-Javadoc) |
| * Method declared on IContributionManager. |
| * |
| * Returns the item passed to us, not the wrapper. |
| * In the case of menu's not added by this manager, |
| * ensure that we return a wrapper for the menu. |
| */ |
| public IContributionItem find(String id) { |
| IContributionItem item = getParentMenuManager().find(id); |
| if (item instanceof SubContributionItem) |
| // Return the item passed to us, not the wrapper. |
| item = unwrap(item); |
| |
| if (item instanceof IMenuManager) { |
| // if it is a menu manager wrap it before returning |
| IMenuManager menu = (IMenuManager) item; |
| item = getWrapper(menu); |
| } |
| |
| return item; |
| } |
| |
| /** |
| * <p> |
| * The menu returned is wrapped within a <code>SubMenuManager</code> to |
| * monitor additions and removals. If the visibility of this menu is modified |
| * the visibility of the submenus is also modified. |
| * </p> |
| */ |
| public IMenuManager findMenuUsingPath(String path) { |
| IContributionItem item = findUsingPath(path); |
| if (item instanceof IMenuManager) { |
| return (IMenuManager) item; |
| } |
| return null; |
| } |
| |
| /* (non-Javadoc) |
| * Method declared on IMenuManager. |
| * |
| * Returns the item passed to us, not the wrapper. |
| * |
| * We use use the same algorithm as MenuManager.findUsingPath, but unwrap |
| * submenus along so that SubMenuManagers are visible. |
| */ |
| public IContributionItem findUsingPath(String path) { |
| String id = path; |
| String rest = null; |
| int separator = path.indexOf('/'); |
| if (separator != -1) { |
| id = path.substring(0, separator); |
| rest = path.substring(separator + 1); |
| } |
| IContributionItem item = find(id); // unwraps item |
| if (rest != null && item instanceof IMenuManager) { |
| IMenuManager menu = (IMenuManager) item; |
| item = menu.findUsingPath(rest); |
| } |
| return item; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#getId() |
| */ |
| public String getId() { |
| return getParentMenuManager().getId(); |
| } |
| |
| /** |
| * Returns the parent menu manager that this sub-manager contributes to. |
| */ |
| protected final IMenuManager getParentMenuManager() { |
| // Cast is ok because that's the only |
| // thing we accept in the construtor. |
| return (IMenuManager) getParent(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IMenuManager#getRemoveAllWhenShown() |
| */ |
| public boolean getRemoveAllWhenShown() { |
| return false; |
| } |
| |
| /** |
| * Returns the menu wrapper for a menu manager. |
| * <p> |
| * The sub menus within this menu are wrapped within a <code>SubMenuManager</code> to |
| * monitor additions and removals. If the visibility of this menu is modified |
| * the visibility of the sub menus is also modified. |
| * <p> |
| * |
| * @return the menu wrapper |
| */ |
| protected IMenuManager getWrapper(IMenuManager mgr) { |
| if (mapMenuToWrapper == null) { |
| mapMenuToWrapper = new HashMap(4); |
| } |
| SubMenuManager wrapper = (SubMenuManager) mapMenuToWrapper.get(mgr); |
| if (wrapper == null) { |
| wrapper = wrapMenu(mgr); |
| mapMenuToWrapper.put(mgr, wrapper); |
| } |
| return wrapper; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#isDynamic() |
| */ |
| public boolean isDynamic() { |
| return getParentMenuManager().isDynamic(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#isEnabled() |
| */ |
| public boolean isEnabled() { |
| return isVisible() && getParentMenuManager().isEnabled(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#isGroupMarker() |
| */ |
| public boolean isGroupMarker() { |
| return getParentMenuManager().isGroupMarker(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#isSeparator() |
| */ |
| public boolean isSeparator() { |
| return getParentMenuManager().isSeparator(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.SubContributionManager#isVisible() |
| */ |
| public boolean isVisible() { |
| return super.isVisible() && getParentMenuManager().isVisible(); |
| } |
| |
| /** |
| * Remove all contribution items. |
| */ |
| public void removeAll() { |
| super.removeAll(); |
| if (mapMenuToWrapper != null) { |
| Iterator iter = mapMenuToWrapper.values().iterator(); |
| while (iter.hasNext()) { |
| SubMenuManager wrapper = (SubMenuManager) iter.next(); |
| wrapper.removeAll(); |
| } |
| mapMenuToWrapper.clear(); |
| mapMenuToWrapper = null; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IMenuManager#removeMenuListener(org.eclipse.jface.action.IMenuListener) |
| */ |
| public void removeMenuListener(IMenuListener listener) { |
| menuListeners.remove(listener); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#saveWidgetState() |
| */ |
| public void saveWidgetState() { |
| // do nothing |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#setParent(org.eclipse.jface.action.IContributionManager) |
| */ |
| public void setParent(IContributionManager parent) { |
| // do nothing, our "parent manager's" parent |
| // is set when it is added to a manager |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IMenuManager#setRemoveAllWhenShown(boolean) |
| */ |
| public void setRemoveAllWhenShown(boolean removeAll) { |
| Assert.isTrue(false, "Should not be called on submenu manager"); //$NON-NLS-1$ |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.SubContributionManager#setVisible(boolean) |
| */ |
| public void setVisible(boolean visible) { |
| super.setVisible(visible); |
| if (mapMenuToWrapper != null) { |
| Iterator iter = mapMenuToWrapper.values().iterator(); |
| while (iter.hasNext()) { |
| SubMenuManager wrapper = (SubMenuManager) iter.next(); |
| wrapper.setVisible(visible); |
| } |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#update() |
| */ |
| public void update() { |
| // This method is not governed by visibility. The client may |
| // call <code>setVisible</code> and then force an update. At that |
| // point we need to update the parent. |
| getParentMenuManager().update(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionManager#update(boolean) |
| */ |
| public void update(boolean force) { |
| // This method is not governed by visibility. The client may |
| // call <code>setVisible</code> and then force an update. At that |
| // point we need to update the parent. |
| getParentMenuManager().update(force); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IContributionItem#update(java.lang.String) |
| */ |
| public void update(String id) { |
| getParentMenuManager().update(id); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.action.IMenuManager#updateAll(boolean) |
| */ |
| public void updateAll(boolean force) { |
| // This method is not governed by visibility. The client may |
| // call <code>setVisible</code> and then force an update. At that |
| // point we need to update the parent. |
| getParentMenuManager().updateAll(force); |
| } |
| |
| /** |
| * Wraps a menu manager in a sub menu manager, and returns the new wrapper. |
| */ |
| protected SubMenuManager wrapMenu(IMenuManager menu) { |
| SubMenuManager mgr = new SubMenuManager(menu); |
| mgr.setVisible(isVisible()); |
| return mgr; |
| } |
| } |