You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by re...@apache.org on 2015/03/26 19:51:52 UTC

[03/51] [partial] incubator-taverna-workbench git commit: all packages are moved to org.apache.taverna.*

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/net/sf/taverna/t2/ui/menu/impl/MenuManagerImpl.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/ui/menu/impl/MenuManagerImpl.java b/taverna-menu-impl/src/main/java/net/sf/taverna/t2/ui/menu/impl/MenuManagerImpl.java
deleted file mode 100644
index 29b8057..0000000
--- a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/ui/menu/impl/MenuManagerImpl.java
+++ /dev/null
@@ -1,880 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2007 The University of Manchester
- *
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- ******************************************************************************/
-package net.sf.taverna.t2.ui.menu.impl;
-
-import static java.lang.Math.min;
-import static javax.help.CSH.setHelpIDString;
-import static javax.swing.Action.NAME;
-import static javax.swing.Action.SHORT_DESCRIPTION;
-import static net.sf.taverna.t2.lang.ui.ShadedLabel.GREEN;
-import static net.sf.taverna.t2.ui.menu.AbstractMenuSection.SECTION_COLOR;
-import static net.sf.taverna.t2.ui.menu.DefaultContextualMenu.DEFAULT_CONTEXT_MENU;
-import static net.sf.taverna.t2.ui.menu.DefaultMenuBar.DEFAULT_MENU_BAR;
-import static net.sf.taverna.t2.ui.menu.DefaultToolBar.DEFAULT_TOOL_BAR;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.lang.ref.WeakReference;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.WeakHashMap;
-
-import javax.swing.AbstractButton;
-import javax.swing.Action;
-import javax.swing.ButtonGroup;
-import javax.swing.JButton;
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JMenuItem;
-import javax.swing.JPopupMenu;
-import javax.swing.JRadioButtonMenuItem;
-import javax.swing.JToggleButton;
-import javax.swing.JToolBar;
-import javax.swing.border.EmptyBorder;
-
-import org.apache.taverna.lang.observer.MultiCaster;
-import org.apache.taverna.lang.observer.Observable;
-import org.apache.taverna.lang.observer.Observer;
-import org.apache.taverna.lang.observer.SwingAwareObserver;
-import net.sf.taverna.t2.lang.ui.ShadedLabel;
-import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
-import net.sf.taverna.t2.ui.menu.AbstractMenuOptionGroup;
-import net.sf.taverna.t2.ui.menu.ContextualMenuComponent;
-import net.sf.taverna.t2.ui.menu.ContextualSelection;
-import net.sf.taverna.t2.ui.menu.DesignOnlyAction;
-import net.sf.taverna.t2.ui.menu.DesignOrResultsAction;
-import net.sf.taverna.t2.ui.menu.MenuComponent;
-import net.sf.taverna.t2.ui.menu.MenuComponent.MenuType;
-import net.sf.taverna.t2.ui.menu.MenuManager;
-import net.sf.taverna.t2.workbench.selection.SelectionManager;
-import net.sf.taverna.t2.workbench.selection.events.PerspectiveSelectionEvent;
-import net.sf.taverna.t2.workbench.selection.events.SelectionManagerEvent;
-
-import org.apache.log4j.Logger;
-
-/**
- * Implementation of {@link MenuManager}.
- *
- * @author Stian Soiland-Reyes
- */
-public class MenuManagerImpl implements MenuManager {
-	private static Logger logger = Logger.getLogger(MenuManagerImpl.class);
-
-	private boolean needsUpdate;
-	/**
-	 * Cache used by {@link #getURIByComponent(Component)}
-	 */
-	private WeakHashMap<Component, URI> componentToUri;
-	/**
-	 * {@link MenuElementComparator} used for sorting menu components from the
-	 * SPI registry.
-	 */
-	private MenuElementComparator menuElementComparator = new MenuElementComparator();
-	/**
-	 * Map of {@link URI} to it's discovered children. Populated by
-	 * {@link #findChildren()}.
-	 */
-	private HashMap<URI, List<MenuComponent>> menuElementTree;
-	/**
-	 * Multicaster to distribute messages to {@link Observer}s of this menu
-	 * manager.
-	 */
-	private MultiCaster<MenuManagerEvent> multiCaster;
-	/**
-	 * Lock for {@link #update()}
-	 */
-	private final Object updateLock = new Object();
-	/**
-	 * True if {@link #doUpdate()} is running, subsequents call to
-	 * {@link #update()} will return immediately.
-	 */
-	private boolean updating;
-	/**
-	 * Cache used by {@link #getComponentByURI(URI)}
-	 */
-	private Map<URI, WeakReference<Component>> uriToComponent;
-	/**
-	 * Map from {@link URI} to defining {@link MenuComponent}. Children are in
-	 * {@link #menuElementTree}.
-	 */
-	private Map<URI, MenuComponent> uriToMenuElement;
-	// Note: Not reset by #resetCollections()
-	private Map<URI, List<WeakReference<Component>>> uriToPublishedComponents = new HashMap<>();
-	private List<MenuComponent> menuComponents = new ArrayList<>();
-
-	/**
-	 * Construct the MenuManagerImpl. Observes the SPI registry and does an
-	 * initial {@link #update()}.
-	 */
-	public MenuManagerImpl() {
-		multiCaster = new MultiCaster<>(this);
-		needsUpdate = true;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public void addMenuItemsWithExpansion(List<JMenuItem> menuItems,
-			JMenu parentMenu, int maxItemsInMenu,
-			ComponentFactory headerItemFactory) {
-		if (menuItems.size() <= maxItemsInMenu) {
-			// Just add them directly
-			for (JMenuItem menuItem : menuItems)
-				parentMenu.add(menuItem);
-			return;
-		}
-		int index = 0;
-		while (index < menuItems.size()) {
-			int toIndex = min(menuItems.size(), index + maxItemsInMenu);
-			if (toIndex == menuItems.size() - 1)
-				// Don't leave a single item left for the last subMenu
-				toIndex--;
-			List<JMenuItem> subList = menuItems.subList(index, toIndex);
-			JMenuItem firstItem = subList.get(0);
-			JMenuItem lastItem = subList.get(subList.size() - 1);
-			JMenu subMenu = new JMenu(firstItem.getText() + " ... "
-					+ lastItem.getText());
-			if (headerItemFactory != null)
-				subMenu.add(headerItemFactory.makeComponent());
-			for (JMenuItem menuItem : subList)
-				subMenu.add(menuItem);
-			parentMenu.add(subMenu);
-			index = toIndex;
-		}
-	}
-
-	@Override
-	public void addObserver(Observer<MenuManagerEvent> observer) {
-		multiCaster.addObserver(observer);
-	}
-
-	@Override
-	public JPopupMenu createContextMenu(Object parent, Object selection,
-			Component relativeToComponent) {
-		ContextualSelection contextualSelection = new ContextualSelection(
-				parent, selection, relativeToComponent);
-		JPopupMenu popupMenu = new JPopupMenu();
-		populateContextMenu(popupMenu, DEFAULT_CONTEXT_MENU,
-				contextualSelection);
-		registerComponent(DEFAULT_CONTEXT_MENU, popupMenu, true);
-		return popupMenu;
-	}
-
-	@Override
-	public JMenuBar createMenuBar() {
-		return createMenuBar(DEFAULT_MENU_BAR);
-	}
-
-	@Override
-	public JMenuBar createMenuBar(URI id) {
-		JMenuBar menuBar = new JMenuBar();
-		if (needsUpdate)
-			update();
-		populateMenuBar(menuBar, id);
-		registerComponent(id, menuBar, true);
-		return menuBar;
-	}
-
-	@Override
-	public JToolBar createToolBar() {
-		return createToolBar(DEFAULT_TOOL_BAR);
-	}
-
-	@Override
-	public JToolBar createToolBar(URI id) {
-		JToolBar toolbar = new JToolBar();
-		if (needsUpdate)
-			update();
-		populateToolBar(toolbar, id);
-		registerComponent(id, toolbar, true);
-		return toolbar;
-	}
-
-	@Override
-	public synchronized Component getComponentByURI(URI id) {
-		WeakReference<Component> componentRef = uriToComponent.get(id);
-		if (componentRef == null)
-			return null;
-		// Might also be null it reference has gone dead
-		return componentRef.get();
-	}
-
-	@Override
-	public List<Observer<MenuManagerEvent>> getObservers() {
-		return multiCaster.getObservers();
-	}
-
-	@Override
-	public synchronized URI getURIByComponent(Component component) {
-		return componentToUri.get(component);
-	}
-
-	@Override
-	public void removeObserver(Observer<MenuManagerEvent> observer) {
-		multiCaster.removeObserver(observer);
-	}
-
-	@Override
-	public void update() {
-		synchronized (updateLock) {
-			if (updating && !needsUpdate)
-				return;
-			updating = true;
-		}
-		try {
-			doUpdate();
-		} finally {
-			synchronized (updateLock) {
-				updating = false;
-				needsUpdate = false;
-			}
-		}
-	}
-
-	public void update(Object service, Map<?, ?> properties) {
-		needsUpdate = true;
-		update();
-	}
-
-	/**
-	 * Add a {@link JMenu} to the list of components as described by the menu
-	 * component. If there are no children, the menu is not added.
-	 *
-	 * @param components
-	 *            List of components where to add the created {@link JMenu}
-	 * @param menuComponent
-	 *            The {@link MenuComponent} definition for this menu
-	 * @param isToolbar
-	 *            True if the list of components is to be added to a toolbar
-	 */
-	private void addMenu(List<Component> components,
-			MenuComponent menuComponent, MenuOptions menuOptions) {
-		URI menuId = menuComponent.getId();
-		if (menuOptions.isToolbar()) {
-			logger.warn("Can't have menu " + menuComponent
-					+ " within toolBar element");
-			return;
-		}
-		MenuOptions childOptions = new MenuOptions(menuOptions);
-		List<Component> subComponents = makeComponents(menuId, childOptions);
-		if (subComponents.isEmpty()) {
-			logger.warn("No sub components found for menu " + menuId);
-			return;
-		}
-
-		JMenu menu = new JMenu(menuComponent.getAction());
-		for (Component menuItem : subComponents)
-			if (menuItem == null)
-				menu.addSeparator();
-			else
-				menu.add(menuItem);
-		registerComponent(menuId, menu);
-		components.add(menu);
-	}
-
-	/**
-	 * Add <code>null</code> to the list of components, meaning that a separator
-	 * is to be created. Subsequent separators are ignored, and if there are no
-	 * components on the list already no separator will be added.
-	 * 
-	 * @param components
-	 *            List of components
-	 */
-	private void addNullSeparator(List<Component> components) {
-		if (components.isEmpty())
-			// Don't start with a separator
-			return;
-		if (components.get(components.size() - 1) == null)
-			// Already a separator in last position
-			return;
-		components.add(null);
-	}
-
-	/**
-	 * Add an {@link AbstractMenuOptionGroup option group} to the list of
-	 * components
-	 *
-	 * @param components
-	 *            List of components where to add the created {@link JMenu}
-	 * @param optionGroupId
-	 *            The {@link URI} identifying the option group
-	 * @param isToolbar
-	 *            True if the option group is to be added to a toolbar
-	 */
-	private void addOptionGroup(List<Component> components, URI optionGroupId,
-			MenuOptions menuOptions) {
-		MenuOptions childOptions = new MenuOptions(menuOptions);
-		childOptions.setOptionGroup(true);
-
-		List<Component> buttons = makeComponents(optionGroupId, childOptions);
-		addNullSeparator(components);
-		if (buttons.isEmpty()) {
-			logger.warn("No sub components found for option group "
-					+ optionGroupId);
-			return;
-		}
-		ButtonGroup buttonGroup = new ButtonGroup();
-
-		for (Component button : buttons) {
-			if (button instanceof AbstractButton)
-				buttonGroup.add((AbstractButton) button);
-			else
-				logger.warn("Component of button group " + optionGroupId
-						+ " is not an AbstractButton: " + button);
-			if (button == null) {
-				logger.warn("Separator found within button group");
-				addNullSeparator(components);
-			} else
-				components.add(button);
-		}
-		addNullSeparator(components);
-	}
-
-	/**
-	 * Add a section to a list of components.
-	 *
-	 * @param components
-	 *            List of components
-	 * @param sectionId
-	 *            The {@link URI} identifying the section
-	 * @param menuOptions
-	 *            {@link MenuOptions options} for creating the menu
-	 */
-	private void addSection(List<Component> components, URI sectionId,
-			MenuOptions menuOptions) {
-		List<Component> childComponents = makeComponents(sectionId, menuOptions);
-
-		MenuComponent sectionDef = uriToMenuElement.get(sectionId);
-		addNullSeparator(components);
-		if (childComponents.isEmpty()) {
-			logger.warn("No sub components found for section " + sectionId);
-			return;
-		}
-		Action sectionAction = sectionDef.getAction();
-		if (sectionAction != null) {
-			String sectionLabel = (String) sectionAction.getValue(NAME);
-			if (sectionLabel != null) {
-				// No separators before the label
-				stripTrailingNullSeparator(components);
-				Color labelColor = (Color) sectionAction.getValue(SECTION_COLOR);
-				if (labelColor == null)
-					labelColor = GREEN;
-				ShadedLabel label = new ShadedLabel(sectionLabel, labelColor);
-				components.add(label);
-			}
-		}
-		for (Component childComponent : childComponents)
-			if (childComponent == null) {
-				logger.warn("Separator found within section " + sectionId);
-				addNullSeparator(components);
-			} else
-				components.add(childComponent);
-		addNullSeparator(components);
-	}
-
-	/**
-	 * Remove the last <code>null</code> separator from the list of components
-	 * if it's present.
-	 *
-	 * @param components
-	 *            List of components
-	 */
-	private void stripTrailingNullSeparator(List<Component> components) {
-		if (!components.isEmpty()) {
-			int lastIndex = components.size() - 1;
-			if (components.get(lastIndex) == null)
-				components.remove(lastIndex);
-		}
-	}
-
-	/**
-	 * Perform the actual update, called by {@link #update()}. Reset all the
-	 * collections, refresh from SPI, modify any previously published components
-	 * and notify any observers.
-	 */
-	protected synchronized void doUpdate() {
-		resetCollections();
-		findChildren();
-		updatePublishedComponents();
-		multiCaster.notify(new UpdatedMenuManagerEvent());
-	}
-
-	/**
-	 * Find all children for all known menu components. Populates
-	 * {@link #uriToMenuElement}.
-	 *
-	 */
-	protected void findChildren() {
-		for (MenuComponent menuElement : menuComponents) {
-			uriToMenuElement.put(menuElement.getId(), menuElement);
-			logger.debug("Found menu element " + menuElement.getId() + " "
-					+ menuElement);
-			if (menuElement.getParentId() == null)
-				continue;
-			List<MenuComponent> siblings = menuElementTree.get(menuElement
-					.getParentId());
-			if (siblings == null) {
-				siblings = new ArrayList<>();
-				synchronized (menuElementTree) {
-					menuElementTree.put(menuElement.getParentId(), siblings);
-				}
-			}
-			siblings.add(menuElement);
-		}
-//		if (uriToMenuElement.isEmpty()) {
-//			logger.error("No menu elements found, check classpath/Raven/SPI");
-//		}
-	}
-
-	/**
-	 * Get the children which have the given URI specified as their parent, or
-	 * an empty list if no children exist.
-	 *
-	 * @param id
-	 *            The {@link URI} of the parent
-	 * @return The {@link List} of {@link MenuComponent} which have the given
-	 *         parent
-	 */
-	protected List<MenuComponent> getChildren(URI id) {
-		List<MenuComponent> children = null;
-		synchronized (menuElementTree) {
-			children = menuElementTree.get(id);
-			if (children != null)
-				children = new ArrayList<>(children);
-		}
-		if (children == null)
-			children = Collections.<MenuComponent> emptyList();
-		else
-			Collections.sort(children, menuElementComparator);
-		return children;
-	}
-
-	/**
-	 * Make the list of Swing {@link Component}s that are the children of the
-	 * given {@link URI}.
-	 *
-	 * @param id
-	 *            The {@link URI} of the parent which children are to be made
-	 * @param menuOptions
-	 *            Options of the created menu, for instance
-	 *            {@link MenuOptions#isToolbar()}.
-	 * @return A {@link List} of {@link Component}s that can be added to a
-	 *         {@link JMenuBar}, {@link JMenu} or {@link JToolBar}.
-	 */
-	protected List<Component> makeComponents(URI id, MenuOptions menuOptions) {
-		List<Component> components = new ArrayList<>();
-		for (MenuComponent childElement : getChildren(id)) {
-			if (childElement instanceof ContextualMenuComponent)
-				((ContextualMenuComponent) childElement)
-						.setContextualSelection(menuOptions
-								.getContextualSelection());
-			/*
-			 * Important - check this AFTER setContextualSelection so the item
-			 * can change it's enabled-state if needed.
-			 */
-			if (!childElement.isEnabled())
-				continue;
-			MenuType type = childElement.getType();
-			Action action = childElement.getAction();
-			URI childId = childElement.getId();
-			if (type.equals(MenuType.action)) {
-				if (action == null) {
-					logger.warn("Skipping invalid action " + childId + " for "
-							+ id);
-					continue;
-				}
-
-				Component actionComponent;
-				if (menuOptions.isOptionGroup()) {
-					if (menuOptions.isToolbar()) {
-						actionComponent = new JToggleButton(action);
-						toolbarizeButton((AbstractButton) actionComponent);
-					} else
-						actionComponent = new JRadioButtonMenuItem(action);
-				} else {
-					if (menuOptions.isToolbar()) {
-						actionComponent = new JButton(action);
-						toolbarizeButton((AbstractButton) actionComponent);
-					} else
-						actionComponent = new JMenuItem(action);
-				}
-				registerComponent(childId, actionComponent);
-				components.add(actionComponent);
-			} else if (type.equals(MenuType.toggle)) {
-				if (action == null) {
-					logger.warn("Skipping invalid toggle " + childId + " for "
-							+ id);
-					continue;
-				}
-				Component toggleComponent;
-				if (menuOptions.isToolbar())
-					toggleComponent = new JToggleButton(action);
-				else
-					toggleComponent = new JCheckBoxMenuItem(action);
-				registerComponent(childId, toggleComponent);
-				components.add(toggleComponent);
-			} else if (type.equals(MenuType.custom)) {
-				Component customComponent = childElement.getCustomComponent();
-				if (customComponent == null) {
-					logger.warn("Skipping null custom component " + childId
-							+ " for " + id);
-					continue;
-				}
-				registerComponent(childId, customComponent);
-				components.add(customComponent);
-			} else if (type.equals(MenuType.optionGroup))
-				addOptionGroup(components, childId, menuOptions);
-			else if (type.equals(MenuType.section))
-				addSection(components, childId, menuOptions);
-			else if (type.equals(MenuType.menu))
-				addMenu(components, childElement, menuOptions);
-			else {
-				logger.warn("Skipping invalid/unknown type " + type + " for "
-						+ id);
-				continue;
-			}
-		}
-		stripTrailingNullSeparator(components);
-		return components;
-	}
-
-	/**
-	 * Fill the specified menu bar with the menu elements that have the given
-	 * URI as their parent.
-	 * <p>
-	 * Existing elements on the menu bar will be removed.
-	 *
-	 * @param menuBar
-	 *            The {@link JMenuBar} to update
-	 * @param id
-	 *            The {@link URI} of the menu bar
-	 */
-	protected void populateMenuBar(JMenuBar menuBar, URI id) {
-		menuBar.removeAll();
-		MenuComponent menuDef = uriToMenuElement.get(id);
-		if (menuDef == null)
-			throw new IllegalArgumentException("Unknown menuBar " + id);
-		if (!menuDef.getType().equals(MenuType.menu))
-			throw new IllegalArgumentException("Element " + id
-					+ " is not a menu, but a " + menuDef.getType());
-		MenuOptions menuOptions = new MenuOptions();
-		for (Component component : makeComponents(id, menuOptions))
-			if (component == null)
-				logger.warn("Ignoring separator in menu bar " + id);
-			else
-				menuBar.add(component);
-	}
-
-	/**
-	 * Fill the specified menu bar with the menu elements that have the given
-	 * URI as their parent.
-	 * <p>
-	 * Existing elements on the menu bar will be removed.
-	 *
-	 * @param popupMenu
-	 *            The {@link JPopupMenu} to update
-	 * @param id
-	 *            The {@link URI} of the menu bar
-	 * @param contextualSelection
-	 *            The current selection for the context menu
-	 */
-	protected void populateContextMenu(JPopupMenu popupMenu, URI id,
-			ContextualSelection contextualSelection) {
-		popupMenu.removeAll();
-		MenuComponent menuDef = uriToMenuElement.get(id);
-		if (menuDef == null)
-			throw new IllegalArgumentException("Unknown menuBar " + id);
-		if (!menuDef.getType().equals(MenuType.menu))
-			throw new IllegalArgumentException("Element " + id
-					+ " is not a menu, but a " + menuDef.getType());
-		MenuOptions menuOptions = new MenuOptions();
-		menuOptions.setContextualSelection(contextualSelection);
-		for (Component component : makeComponents(id, menuOptions))
-			if (component == null)
-				popupMenu.addSeparator();
-			else
-				popupMenu.add(component);
-	}
-
-	/**
-	 * Fill the specified tool bar with the elements that have the given URI as
-	 * their parent.
-	 * <p>
-	 * Existing elements on the tool bar will be removed.
-	 *
-	 * @param toolbar
-	 *            The {@link JToolBar} to update
-	 * @param id
-	 *            The {@link URI} of the tool bar
-	 */
-	protected void populateToolBar(JToolBar toolbar, URI id) {
-		toolbar.removeAll();
-		MenuComponent toolbarDef = uriToMenuElement.get(id);
-		if (toolbarDef == null)
-			throw new IllegalArgumentException("Unknown toolBar " + id);
-		if (!toolbarDef.getType().equals(MenuType.toolBar))
-			throw new IllegalArgumentException("Element " + id
-					+ " is not a toolBar, but a " + toolbarDef.getType());
-		if (toolbarDef.getAction() != null) {
-			String name = (String) toolbarDef.getAction().getValue(Action.NAME);
-			toolbar.setName(name);
-		} else
-			toolbar.setName("");
-		MenuOptions menuOptions = new MenuOptions();
-		menuOptions.setToolbar(true);
-		for (Component component : makeComponents(id, menuOptions)) {
-			if (component == null) {
-				toolbar.addSeparator();
-				continue;
-			}
-			if (component instanceof JButton) {
-				JButton toolbarButton = (JButton) component;
-				toolbarButton.putClientProperty("hideActionText", true);
-			}
-			toolbar.add(component);
-		}
-	}
-
-	/**
-	 * Register a component that has been created. Such a component can be
-	 * resolved through {@link #getComponentByURI(URI)}.
-	 *
-	 * @param id
-	 *            The {@link URI} that defined the component
-	 * @param component
-	 *            The {@link Component} that was created.
-	 */
-	protected synchronized void registerComponent(URI id, Component component) {
-		registerComponent(id, component, false);
-	}
-
-	/**
-	 * Register a component that has been created. Such a component can be
-	 * resolved through {@link #getComponentByURI(URI)}.
-	 *
-	 * @param id
-	 *            The {@link URI} that defined the component
-	 * @param component
-	 *            The {@link Component} that was created.
-	 * @param published
-	 *            <code>true</code> if the component has been published through
-	 *            {@link #createMenuBar()} or similar, and is to be
-	 *            automatically updated by later calls to {@link #update()}.
-	 */
-	protected synchronized void registerComponent(URI id, Component component,
-			boolean published) {
-		uriToComponent.put(id, new WeakReference<>(component));
-		componentToUri.put(component, id);
-		if (published) {
-			List<WeakReference<Component>> publishedComponents = uriToPublishedComponents
-					.get(id);
-			if (publishedComponents == null) {
-				publishedComponents = new ArrayList<>();
-				uriToPublishedComponents.put(id, publishedComponents);
-			}
-			publishedComponents.add(new WeakReference<>(component));
-		}
-		setHelpStringForComponent(component, id);
-	}
-
-	/**
-	 * Reset all collections
-	 *
-	 */
-	protected synchronized void resetCollections() {
-		menuElementTree = new HashMap<>();
-		componentToUri = new WeakHashMap<>();
-		uriToMenuElement = new HashMap<>();
-		uriToComponent = new HashMap<>();
-	}
-
-	/**
-	 * Set javax.help string to identify the component for later references to
-	 * the help document. Note that the component (ie. the
-	 * {@link AbstractMenuAction} must have an ID for an registration to take
-	 * place.
-	 *
-	 * @param component
-	 *            The {@link Component} to set help string for
-	 * @param componentId
-	 *            The {@link URI} to be used as identifier
-	 */
-	protected void setHelpStringForComponent(Component component,
-			URI componentId) {
-		if (componentId != null) {
-			String helpId = componentId.toASCIIString();
-			setHelpIDString(component, helpId);
-		}
-	}
-
-	/**
-	 * Make an {@link AbstractButton} be configured in a "toolbar-like" way, for
-	 * instance showing only the icon.
-	 *
-	 * @param actionButton
-	 *            Button to toolbarise
-	 */
-	protected void toolbarizeButton(AbstractButton actionButton) {
-		Action action = actionButton.getAction();
-		if (action.getValue(SHORT_DESCRIPTION) == null)
-			action.putValue(SHORT_DESCRIPTION, action.getValue(NAME));
-		actionButton.setBorder(new EmptyBorder(0, 2, 0, 2));
-		// actionButton.setHorizontalTextPosition(JButton.CENTER);
-		// actionButton.setVerticalTextPosition(JButton.BOTTOM);
-		if (action.getValue(Action.SMALL_ICON) != null) {
-			// Don't show the text
-			actionButton.putClientProperty("hideActionText", true);
-			// Since hideActionText seems to be broken in Java 5 and/or OS X
-			actionButton.setText(null);
-		}
-	}
-
-	/**
-	 * Update all components that have been published using
-	 * {@link #createMenuBar()} and similar. Content of such components will be
-	 * removed and replaced by fresh components.
-	 */
-	protected void updatePublishedComponents() {
-		for (Entry<URI, List<WeakReference<Component>>> entry : uriToPublishedComponents
-				.entrySet())
-			for (WeakReference<Component> reference : entry.getValue()) {
-				URI id = entry.getKey();
-				Component component = reference.get();
-				if (component == null)
-					continue;
-				if (component instanceof JToolBar)
-					populateToolBar((JToolBar) component, id);
-				else if (component instanceof JMenuBar)
-					populateMenuBar((JMenuBar) component, id);
-				else
-					logger.warn("Could not update published component " + id
-							+ ": " + component.getClass());
-			}
-	}
-
-	public void setMenuComponents(List<MenuComponent> menuComponents) {
-		this.menuComponents = menuComponents;
-	}
-
-	public void setSelectionManager(SelectionManager selectionManager) {
-		selectionManager.addObserver(new SelectionManagerObserver());
-	}
-
-	/**
-	 * {@link Comparator} that can order {@link MenuComponent}s by their
-	 * {@link MenuComponent#getPositionHint()}.
-	 */
-	protected static class MenuElementComparator implements
-			Comparator<MenuComponent> {
-		@Override
-		public int compare(MenuComponent a, MenuComponent b) {
-			return a.getPositionHint() - b.getPositionHint();
-		}
-	}
-
-	/**
-	 * Various options for
-	 * {@link MenuManagerImpl#makeComponents(URI, MenuOptions)} and friends.
-	 *
-	 * @author Stian Soiland-Reyes
-	 */
-	public static class MenuOptions {
-		private boolean isToolbar = false;
-		private boolean isOptionGroup = false;
-		private ContextualSelection contextualSelection = null;
-
-		public ContextualSelection getContextualSelection() {
-			return contextualSelection;
-		}
-
-		public void setContextualSelection(
-				ContextualSelection contextualSelection) {
-			this.contextualSelection = contextualSelection;
-		}
-
-		public MenuOptions(MenuOptions original) {
-			this.isOptionGroup = original.isOptionGroup();
-			this.isToolbar = original.isToolbar();
-			this.contextualSelection = original.getContextualSelection();
-		}
-
-		public MenuOptions() {
-		}
-
-		@Override
-		protected MenuOptions clone() {
-			return new MenuOptions(this);
-		}
-
-		public boolean isToolbar() {
-			return isToolbar;
-		}
-
-		public void setToolbar(boolean isToolbar) {
-			this.isToolbar = isToolbar;
-		}
-
-		public boolean isOptionGroup() {
-			return isOptionGroup;
-		}
-
-		public void setOptionGroup(boolean isOptionGroup) {
-			this.isOptionGroup = isOptionGroup;
-		}
-	}
-
-	private final class SelectionManagerObserver extends
-			SwingAwareObserver<SelectionManagerEvent> {
-		private static final String DESIGN_PERSPECTIVE_ID = "net.sf.taverna.t2.ui.perspectives.design.DesignPerspective";
-		private static final String RESULTS_PERSPECTIVE_ID = "net.sf.taverna.t2.ui.perspectives.results.ResultsPerspective";
-
-		@Override
-		public void notifySwing(Observable<SelectionManagerEvent> sender,
-				SelectionManagerEvent message) {
-			if (!(message instanceof PerspectiveSelectionEvent))
-				return;
-			handlePerspectiveSelect((PerspectiveSelectionEvent) message);
-		}
-
-		private void handlePerspectiveSelect(PerspectiveSelectionEvent event) {
-			String perspectiveID = event.getSelectedPerspective().getID();
-			boolean isDesign = DESIGN_PERSPECTIVE_ID.equals(perspectiveID);
-			boolean isResults = RESULTS_PERSPECTIVE_ID.equals(perspectiveID);
-
-			for (MenuComponent menuComponent : menuComponents)
-				if (!(menuComponent instanceof ContextualMenuComponent)) {
-					Action action = menuComponent.getAction();
-					if (action instanceof DesignOnlyAction)
-						action.setEnabled(isDesign);
-					else if (action instanceof DesignOrResultsAction)
-						action.setEnabled(isDesign || isResults);
-				}
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/AdvancedMenu.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/AdvancedMenu.java b/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/AdvancedMenu.java
deleted file mode 100644
index 9a2f37b..0000000
--- a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/AdvancedMenu.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2007 The University of Manchester   
- * 
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- * 
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *    
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *    
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- ******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.impl.menu;
-
-import static java.awt.event.KeyEvent.VK_A;
-import static javax.swing.Action.MNEMONIC_KEY;
-import static net.sf.taverna.t2.ui.menu.DefaultMenuBar.DEFAULT_MENU_BAR;
-
-import java.net.URI;
-
-import net.sf.taverna.t2.ui.menu.AbstractMenu;
-
-public class AdvancedMenu extends AbstractMenu {
-	public static final URI ADVANCED_URI = URI
-			.create("http://taverna.sf.net/2008/t2workbench/menu#advanced");
-
-	public AdvancedMenu() {
-		super(DEFAULT_MENU_BAR, 1000, ADVANCED_URI, makeAction());
-	}
-
-	public static DummyAction makeAction() {
-		DummyAction action = new DummyAction("Advanced");
-		action.putValue(MNEMONIC_KEY, Integer.valueOf(VK_A));
-		return action;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/EditMenu.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/EditMenu.java b/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/EditMenu.java
deleted file mode 100644
index a15237c..0000000
--- a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/EditMenu.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2007 The University of Manchester   
- * 
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- * 
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *    
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *    
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- ******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.impl.menu;
-
-import static java.awt.event.KeyEvent.VK_E;
-import static javax.swing.Action.MNEMONIC_KEY;
-import static net.sf.taverna.t2.ui.menu.DefaultMenuBar.DEFAULT_MENU_BAR;
-
-import java.net.URI;
-
-import net.sf.taverna.t2.ui.menu.AbstractMenu;
-
-public class EditMenu extends AbstractMenu {
-	public EditMenu() {
-		super(DEFAULT_MENU_BAR, 20, URI
-				.create("http://taverna.sf.net/2008/t2workbench/menu#edit"),
-				makeAction());
-	}
-
-	public static DummyAction makeAction() {
-		DummyAction action = new DummyAction("Edit");
-		action.putValue(MNEMONIC_KEY, Integer.valueOf(VK_E));
-		return action;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/FeedbackMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/FeedbackMenuAction.java b/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/FeedbackMenuAction.java
deleted file mode 100644
index 6b6eb7c..0000000
--- a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/FeedbackMenuAction.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2007 The University of Manchester   
- * 
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- * 
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *    
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *    
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- ******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.impl.menu;
-
-import static java.awt.Desktop.getDesktop;
-import static net.sf.taverna.t2.workbench.ui.impl.menu.HelpMenu.HELP_URI;
-
-import java.awt.event.ActionEvent;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-
-import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
-
-import org.apache.log4j.Logger;
-
-/**
- * MenuItem for feedback
- * 
- * @author alanrw
- */
-public class FeedbackMenuAction extends AbstractMenuAction {
-	private static Logger logger = Logger.getLogger(FeedbackMenuAction.class);
-
-	private static String FEEDBACK_URL = "http://www.taverna.org.uk/about/contact-us/feedback/";
-
-	public FeedbackMenuAction() {
-		super(HELP_URI, 20);
-	}
-
-	@Override
-	protected Action createAction() {
-		return new FeedbackAction();
-	}
-
-	@SuppressWarnings("serial")
-	private final class FeedbackAction extends AbstractAction {
-		private FeedbackAction() {
-			super("Contact us");
-		}
-
-		@Override
-		public void actionPerformed(ActionEvent e) {
-			try {
-				getDesktop().browse(new URI(FEEDBACK_URL));
-			} catch (IOException e1) {
-				logger.error("Unable to open URL", e1);
-			} catch (URISyntaxException e1) {
-				logger.error("Invalid URL syntax", e1);
-			}
-		}
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/FileMenu.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/FileMenu.java b/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/FileMenu.java
deleted file mode 100644
index 61f963b..0000000
--- a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/FileMenu.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2007 The University of Manchester   
- * 
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- * 
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *    
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *    
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- ******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.impl.menu;
-
-import static java.awt.event.KeyEvent.VK_F;
-import static javax.swing.Action.MNEMONIC_KEY;
-import static net.sf.taverna.t2.ui.menu.DefaultMenuBar.DEFAULT_MENU_BAR;
-
-import java.net.URI;
-
-import net.sf.taverna.t2.ui.menu.AbstractMenu;
-
-/**
- * File menu
- * 
- * @author Stian Soiland-Reyes
- */
-public class FileMenu extends AbstractMenu {
-	public FileMenu() {
-		super(DEFAULT_MENU_BAR, 10, URI
-				.create("http://taverna.sf.net/2008/t2workbench/menu#file"),
-				makeAction());
-	}
-
-	public static DummyAction makeAction() {
-		DummyAction action = new DummyAction("File");
-		action.putValue(MNEMONIC_KEY, Integer.valueOf(VK_F));
-		return action;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/HelpMenu.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/HelpMenu.java b/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/HelpMenu.java
deleted file mode 100644
index c4169cc..0000000
--- a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/HelpMenu.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2007 The University of Manchester   
- * 
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- * 
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *    
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *    
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- ******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.impl.menu;
-
-import static java.awt.event.KeyEvent.VK_H;
-import static javax.swing.Action.MNEMONIC_KEY;
-import static net.sf.taverna.t2.ui.menu.DefaultMenuBar.DEFAULT_MENU_BAR;
-
-import java.net.URI;
-
-import net.sf.taverna.t2.ui.menu.AbstractMenu;
-
-public class HelpMenu extends AbstractMenu {
-	public static final URI HELP_URI = URI
-			.create("http://taverna.sf.net/2008/t2workbench/menu#help");
-
-	public HelpMenu() {
-		super(DEFAULT_MENU_BAR, 1024, HELP_URI, makeAction());
-	}
-
-	public static DummyAction makeAction() {
-		DummyAction action = new DummyAction("Help");
-		action.putValue(MNEMONIC_KEY, Integer.valueOf(VK_H));
-		return action;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/OnlineHelpMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/OnlineHelpMenuAction.java b/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/OnlineHelpMenuAction.java
deleted file mode 100644
index d091c8e..0000000
--- a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/OnlineHelpMenuAction.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2007 The University of Manchester   
- * 
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- * 
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *    
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *    
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- ******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.impl.menu;
-
-import static java.awt.event.KeyEvent.VK_F1;
-import static javax.swing.KeyStroke.getKeyStroke;
-import static net.sf.taverna.t2.workbench.helper.Helper.displayDefaultHelp;
-import static net.sf.taverna.t2.workbench.ui.impl.menu.HelpMenu.HELP_URI;
-
-import java.awt.AWTEvent;
-import java.awt.event.ActionEvent;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-
-import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
-
-/**
- * MenuItem for help
- * 
- * @author alanrw
- */
-public class OnlineHelpMenuAction extends AbstractMenuAction {
-	public OnlineHelpMenuAction() {
-		super(HELP_URI, 10);
-	}
-
-	@Override
-	protected Action createAction() {
-		return new OnlineHelpAction();
-	}
-
-	@SuppressWarnings("serial")
-	private final class OnlineHelpAction extends AbstractAction {
-		private OnlineHelpAction() {
-			super("Online help");
-			putValue(ACCELERATOR_KEY, getKeyStroke(VK_F1, 0));
-
-		}
-
-		/**
-		 * When selected, use the Helper to display the default help.
-		 */
-		@Override
-		public void actionPerformed(ActionEvent e) {
-			displayDefaultHelp((AWTEvent) e);
-			// TODO change helper to bean?
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/ShowLogsAndDataMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/ShowLogsAndDataMenuAction.java b/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/ShowLogsAndDataMenuAction.java
deleted file mode 100644
index 308d51d..0000000
--- a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/ShowLogsAndDataMenuAction.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package net.sf.taverna.t2.workbench.ui.impl.menu;
-
-import static java.lang.Runtime.getRuntime;
-import static javax.swing.JOptionPane.INFORMATION_MESSAGE;
-import static javax.swing.JOptionPane.showInputDialog;
-import static net.sf.taverna.t2.workbench.MainWindow.getMainWindow;
-import static net.sf.taverna.t2.workbench.ui.impl.menu.AdvancedMenu.ADVANCED_URI;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-
-import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
-
-import org.apache.log4j.Logger;
-
-import uk.org.taverna.configuration.app.ApplicationConfiguration;
-
-public class ShowLogsAndDataMenuAction extends AbstractMenuAction {
-	private static final String OPEN = "open";
-	private static final String EXPLORER = "explorer";
-	// TODO Consider using xdg-open instead of gnome-open
-	private static final String GNOME_OPEN = "gnome-open";
-	private static final String WINDOWS = "Windows";
-	private static final String MAC_OS_X = "Mac OS X";
-
-	private ApplicationConfiguration applicationConfiguration;
-
-	public ShowLogsAndDataMenuAction() {
-		super(ADVANCED_URI, 200);
-	}
-
-	private static Logger logger = Logger.getLogger(ShowLogsAndDataMenuAction.class);
-
-	@Override
-	protected Action createAction() {
-		return new AbstractAction("Show logs and data folder") {
-			private static final long serialVersionUID = 1L;
-
-			@Override
-			public void actionPerformed(ActionEvent e) {
-				File logsAndDataDir = applicationConfiguration.getApplicationHomeDir();
-				showDirectory(logsAndDataDir, "Taverna logs and data folder");
-			}
-		};
-	}
-
-	public static void showDirectory(File dir, String title) {
-		String path = dir.getAbsolutePath();
-		String os = System.getProperty("os.name");
-		String cmd;
-		boolean isWindows = false;
-		if (os.equals(MAC_OS_X))
-			cmd = OPEN;
-		else if (os.startsWith(WINDOWS)) {
-			cmd = EXPLORER;
-			isWindows = true;
-		} else
-			// Assume Unix - best option is gnome-open
-			cmd = GNOME_OPEN;
-
-		String[] cmdArray = new String[2];
-		cmdArray[0] = cmd;
-		cmdArray[1] = path;
-		try {
-			Process exec = getRuntime().exec(cmdArray);
-			Thread.sleep(300);
-			exec.getErrorStream().close();
-			exec.getInputStream().close();
-			exec.getOutputStream().close();
-			exec.waitFor();
-			if (exec.exitValue() == 0 || isWindows && exec.exitValue() == 1)
-				// explorer.exe thinks 1 means success
-				return;
-			logger.warn("Exit value from " + cmd + " " + path + ": " + exec.exitValue());
-		} catch (Exception ex) {
-			logger.warn("Could not call " + cmd + " " + path, ex);
-		}
-		// Fall-back - just show a dialogue with the path
-		showInputDialog(getMainWindow(), "Copy path from below:", title,
-				INFORMATION_MESSAGE, null, null, path);
-	}
-
-	public void setApplicationConfiguration(ApplicationConfiguration applicationConfiguration) {
-		this.applicationConfiguration = applicationConfiguration;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/ViewShowMenuSection.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/ViewShowMenuSection.java b/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/ViewShowMenuSection.java
deleted file mode 100644
index 2df05e5..0000000
--- a/taverna-menu-impl/src/main/java/net/sf/taverna/t2/workbench/ui/impl/menu/ViewShowMenuSection.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2007 The University of Manchester   
- * 
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- * 
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *    
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *    
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- ******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.impl.menu;
-
-import java.net.URI;
-
-import net.sf.taverna.t2.ui.menu.AbstractMenuSection;
-
-/**
- * @author Alex Nenadic
- * @author Alan R Williams
- */
-public class ViewShowMenuSection extends AbstractMenuSection {
-	public static final URI DIAGRAM_MENU = URI
-			.create("http://taverna.sf.net/2008/t2workbench/menu#diagram");
-	public static final URI VIEW_SHOW_MENU_SECTION = URI
-			.create("http://taverna.sf.net/2008/t2workbench/menu#viewShowMenuSection");
-
-	public ViewShowMenuSection() {
-		super(DIAGRAM_MENU, 10, VIEW_SHOW_MENU_SECTION);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/org/apache/taverna/ui/menu/impl/MenuManagerImpl.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/org/apache/taverna/ui/menu/impl/MenuManagerImpl.java b/taverna-menu-impl/src/main/java/org/apache/taverna/ui/menu/impl/MenuManagerImpl.java
new file mode 100644
index 0000000..826114e
--- /dev/null
+++ b/taverna-menu-impl/src/main/java/org/apache/taverna/ui/menu/impl/MenuManagerImpl.java
@@ -0,0 +1,879 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.ui.menu.impl;
+
+import static java.lang.Math.min;
+import static javax.help.CSH.setHelpIDString;
+import static javax.swing.Action.NAME;
+import static javax.swing.Action.SHORT_DESCRIPTION;
+import static org.apache.taverna.lang.ui.ShadedLabel.GREEN;
+import static org.apache.taverna.ui.menu.AbstractMenuSection.SECTION_COLOR;
+import static org.apache.taverna.ui.menu.DefaultContextualMenu.DEFAULT_CONTEXT_MENU;
+import static org.apache.taverna.ui.menu.DefaultMenuBar.DEFAULT_MENU_BAR;
+import static org.apache.taverna.ui.menu.DefaultToolBar.DEFAULT_TOOL_BAR;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.lang.ref.WeakReference;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.WeakHashMap;
+
+import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+import javax.swing.border.EmptyBorder;
+
+import org.apache.taverna.lang.observer.MultiCaster;
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+import org.apache.taverna.lang.observer.SwingAwareObserver;
+import org.apache.taverna.lang.ui.ShadedLabel;
+import org.apache.taverna.ui.menu.AbstractMenuAction;
+import org.apache.taverna.ui.menu.AbstractMenuOptionGroup;
+import org.apache.taverna.ui.menu.ContextualMenuComponent;
+import org.apache.taverna.ui.menu.ContextualSelection;
+import org.apache.taverna.ui.menu.DesignOnlyAction;
+import org.apache.taverna.ui.menu.DesignOrResultsAction;
+import org.apache.taverna.ui.menu.MenuComponent;
+import org.apache.taverna.ui.menu.MenuComponent.MenuType;
+import org.apache.taverna.ui.menu.MenuManager;
+import org.apache.taverna.workbench.selection.SelectionManager;
+import org.apache.taverna.workbench.selection.events.PerspectiveSelectionEvent;
+import org.apache.taverna.workbench.selection.events.SelectionManagerEvent;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Implementation of {@link MenuManager}.
+ *
+ * @author Stian Soiland-Reyes
+ */
+public class MenuManagerImpl implements MenuManager {
+	private static Logger logger = Logger.getLogger(MenuManagerImpl.class);
+
+	private boolean needsUpdate;
+	/**
+	 * Cache used by {@link #getURIByComponent(Component)}
+	 */
+	private WeakHashMap<Component, URI> componentToUri;
+	/**
+	 * {@link MenuElementComparator} used for sorting menu components from the
+	 * SPI registry.
+	 */
+	private MenuElementComparator menuElementComparator = new MenuElementComparator();
+	/**
+	 * Map of {@link URI} to it's discovered children. Populated by
+	 * {@link #findChildren()}.
+	 */
+	private HashMap<URI, List<MenuComponent>> menuElementTree;
+	/**
+	 * Multicaster to distribute messages to {@link Observer}s of this menu
+	 * manager.
+	 */
+	private MultiCaster<MenuManagerEvent> multiCaster;
+	/**
+	 * Lock for {@link #update()}
+	 */
+	private final Object updateLock = new Object();
+	/**
+	 * True if {@link #doUpdate()} is running, subsequents call to
+	 * {@link #update()} will return immediately.
+	 */
+	private boolean updating;
+	/**
+	 * Cache used by {@link #getComponentByURI(URI)}
+	 */
+	private Map<URI, WeakReference<Component>> uriToComponent;
+	/**
+	 * Map from {@link URI} to defining {@link MenuComponent}. Children are in
+	 * {@link #menuElementTree}.
+	 */
+	private Map<URI, MenuComponent> uriToMenuElement;
+	// Note: Not reset by #resetCollections()
+	private Map<URI, List<WeakReference<Component>>> uriToPublishedComponents = new HashMap<>();
+	private List<MenuComponent> menuComponents = new ArrayList<>();
+
+	/**
+	 * Construct the MenuManagerImpl. Observes the SPI registry and does an
+	 * initial {@link #update()}.
+	 */
+	public MenuManagerImpl() {
+		multiCaster = new MultiCaster<>(this);
+		needsUpdate = true;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void addMenuItemsWithExpansion(List<JMenuItem> menuItems,
+			JMenu parentMenu, int maxItemsInMenu,
+			ComponentFactory headerItemFactory) {
+		if (menuItems.size() <= maxItemsInMenu) {
+			// Just add them directly
+			for (JMenuItem menuItem : menuItems)
+				parentMenu.add(menuItem);
+			return;
+		}
+		int index = 0;
+		while (index < menuItems.size()) {
+			int toIndex = min(menuItems.size(), index + maxItemsInMenu);
+			if (toIndex == menuItems.size() - 1)
+				// Don't leave a single item left for the last subMenu
+				toIndex--;
+			List<JMenuItem> subList = menuItems.subList(index, toIndex);
+			JMenuItem firstItem = subList.get(0);
+			JMenuItem lastItem = subList.get(subList.size() - 1);
+			JMenu subMenu = new JMenu(firstItem.getText() + " ... "
+					+ lastItem.getText());
+			if (headerItemFactory != null)
+				subMenu.add(headerItemFactory.makeComponent());
+			for (JMenuItem menuItem : subList)
+				subMenu.add(menuItem);
+			parentMenu.add(subMenu);
+			index = toIndex;
+		}
+	}
+
+	@Override
+	public void addObserver(Observer<MenuManagerEvent> observer) {
+		multiCaster.addObserver(observer);
+	}
+
+	@Override
+	public JPopupMenu createContextMenu(Object parent, Object selection,
+			Component relativeToComponent) {
+		ContextualSelection contextualSelection = new ContextualSelection(
+				parent, selection, relativeToComponent);
+		JPopupMenu popupMenu = new JPopupMenu();
+		populateContextMenu(popupMenu, DEFAULT_CONTEXT_MENU,
+				contextualSelection);
+		registerComponent(DEFAULT_CONTEXT_MENU, popupMenu, true);
+		return popupMenu;
+	}
+
+	@Override
+	public JMenuBar createMenuBar() {
+		return createMenuBar(DEFAULT_MENU_BAR);
+	}
+
+	@Override
+	public JMenuBar createMenuBar(URI id) {
+		JMenuBar menuBar = new JMenuBar();
+		if (needsUpdate)
+			update();
+		populateMenuBar(menuBar, id);
+		registerComponent(id, menuBar, true);
+		return menuBar;
+	}
+
+	@Override
+	public JToolBar createToolBar() {
+		return createToolBar(DEFAULT_TOOL_BAR);
+	}
+
+	@Override
+	public JToolBar createToolBar(URI id) {
+		JToolBar toolbar = new JToolBar();
+		if (needsUpdate)
+			update();
+		populateToolBar(toolbar, id);
+		registerComponent(id, toolbar, true);
+		return toolbar;
+	}
+
+	@Override
+	public synchronized Component getComponentByURI(URI id) {
+		WeakReference<Component> componentRef = uriToComponent.get(id);
+		if (componentRef == null)
+			return null;
+		// Might also be null it reference has gone dead
+		return componentRef.get();
+	}
+
+	@Override
+	public List<Observer<MenuManagerEvent>> getObservers() {
+		return multiCaster.getObservers();
+	}
+
+	@Override
+	public synchronized URI getURIByComponent(Component component) {
+		return componentToUri.get(component);
+	}
+
+	@Override
+	public void removeObserver(Observer<MenuManagerEvent> observer) {
+		multiCaster.removeObserver(observer);
+	}
+
+	@Override
+	public void update() {
+		synchronized (updateLock) {
+			if (updating && !needsUpdate)
+				return;
+			updating = true;
+		}
+		try {
+			doUpdate();
+		} finally {
+			synchronized (updateLock) {
+				updating = false;
+				needsUpdate = false;
+			}
+		}
+	}
+
+	public void update(Object service, Map<?, ?> properties) {
+		needsUpdate = true;
+		update();
+	}
+
+	/**
+	 * Add a {@link JMenu} to the list of components as described by the menu
+	 * component. If there are no children, the menu is not added.
+	 *
+	 * @param components
+	 *            List of components where to add the created {@link JMenu}
+	 * @param menuComponent
+	 *            The {@link MenuComponent} definition for this menu
+	 * @param isToolbar
+	 *            True if the list of components is to be added to a toolbar
+	 */
+	private void addMenu(List<Component> components,
+			MenuComponent menuComponent, MenuOptions menuOptions) {
+		URI menuId = menuComponent.getId();
+		if (menuOptions.isToolbar()) {
+			logger.warn("Can't have menu " + menuComponent
+					+ " within toolBar element");
+			return;
+		}
+		MenuOptions childOptions = new MenuOptions(menuOptions);
+		List<Component> subComponents = makeComponents(menuId, childOptions);
+		if (subComponents.isEmpty()) {
+			logger.warn("No sub components found for menu " + menuId);
+			return;
+		}
+
+		JMenu menu = new JMenu(menuComponent.getAction());
+		for (Component menuItem : subComponents)
+			if (menuItem == null)
+				menu.addSeparator();
+			else
+				menu.add(menuItem);
+		registerComponent(menuId, menu);
+		components.add(menu);
+	}
+
+	/**
+	 * Add <code>null</code> to the list of components, meaning that a separator
+	 * is to be created. Subsequent separators are ignored, and if there are no
+	 * components on the list already no separator will be added.
+	 * 
+	 * @param components
+	 *            List of components
+	 */
+	private void addNullSeparator(List<Component> components) {
+		if (components.isEmpty())
+			// Don't start with a separator
+			return;
+		if (components.get(components.size() - 1) == null)
+			// Already a separator in last position
+			return;
+		components.add(null);
+	}
+
+	/**
+	 * Add an {@link AbstractMenuOptionGroup option group} to the list of
+	 * components
+	 *
+	 * @param components
+	 *            List of components where to add the created {@link JMenu}
+	 * @param optionGroupId
+	 *            The {@link URI} identifying the option group
+	 * @param isToolbar
+	 *            True if the option group is to be added to a toolbar
+	 */
+	private void addOptionGroup(List<Component> components, URI optionGroupId,
+			MenuOptions menuOptions) {
+		MenuOptions childOptions = new MenuOptions(menuOptions);
+		childOptions.setOptionGroup(true);
+
+		List<Component> buttons = makeComponents(optionGroupId, childOptions);
+		addNullSeparator(components);
+		if (buttons.isEmpty()) {
+			logger.warn("No sub components found for option group "
+					+ optionGroupId);
+			return;
+		}
+		ButtonGroup buttonGroup = new ButtonGroup();
+
+		for (Component button : buttons) {
+			if (button instanceof AbstractButton)
+				buttonGroup.add((AbstractButton) button);
+			else
+				logger.warn("Component of button group " + optionGroupId
+						+ " is not an AbstractButton: " + button);
+			if (button == null) {
+				logger.warn("Separator found within button group");
+				addNullSeparator(components);
+			} else
+				components.add(button);
+		}
+		addNullSeparator(components);
+	}
+
+	/**
+	 * Add a section to a list of components.
+	 *
+	 * @param components
+	 *            List of components
+	 * @param sectionId
+	 *            The {@link URI} identifying the section
+	 * @param menuOptions
+	 *            {@link MenuOptions options} for creating the menu
+	 */
+	private void addSection(List<Component> components, URI sectionId,
+			MenuOptions menuOptions) {
+		List<Component> childComponents = makeComponents(sectionId, menuOptions);
+
+		MenuComponent sectionDef = uriToMenuElement.get(sectionId);
+		addNullSeparator(components);
+		if (childComponents.isEmpty()) {
+			logger.warn("No sub components found for section " + sectionId);
+			return;
+		}
+		Action sectionAction = sectionDef.getAction();
+		if (sectionAction != null) {
+			String sectionLabel = (String) sectionAction.getValue(NAME);
+			if (sectionLabel != null) {
+				// No separators before the label
+				stripTrailingNullSeparator(components);
+				Color labelColor = (Color) sectionAction.getValue(SECTION_COLOR);
+				if (labelColor == null)
+					labelColor = GREEN;
+				ShadedLabel label = new ShadedLabel(sectionLabel, labelColor);
+				components.add(label);
+			}
+		}
+		for (Component childComponent : childComponents)
+			if (childComponent == null) {
+				logger.warn("Separator found within section " + sectionId);
+				addNullSeparator(components);
+			} else
+				components.add(childComponent);
+		addNullSeparator(components);
+	}
+
+	/**
+	 * Remove the last <code>null</code> separator from the list of components
+	 * if it's present.
+	 *
+	 * @param components
+	 *            List of components
+	 */
+	private void stripTrailingNullSeparator(List<Component> components) {
+		if (!components.isEmpty()) {
+			int lastIndex = components.size() - 1;
+			if (components.get(lastIndex) == null)
+				components.remove(lastIndex);
+		}
+	}
+
+	/**
+	 * Perform the actual update, called by {@link #update()}. Reset all the
+	 * collections, refresh from SPI, modify any previously published components
+	 * and notify any observers.
+	 */
+	protected synchronized void doUpdate() {
+		resetCollections();
+		findChildren();
+		updatePublishedComponents();
+		multiCaster.notify(new UpdatedMenuManagerEvent());
+	}
+
+	/**
+	 * Find all children for all known menu components. Populates
+	 * {@link #uriToMenuElement}.
+	 *
+	 */
+	protected void findChildren() {
+		for (MenuComponent menuElement : menuComponents) {
+			uriToMenuElement.put(menuElement.getId(), menuElement);
+			logger.debug("Found menu element " + menuElement.getId() + " "
+					+ menuElement);
+			if (menuElement.getParentId() == null)
+				continue;
+			List<MenuComponent> siblings = menuElementTree.get(menuElement
+					.getParentId());
+			if (siblings == null) {
+				siblings = new ArrayList<>();
+				synchronized (menuElementTree) {
+					menuElementTree.put(menuElement.getParentId(), siblings);
+				}
+			}
+			siblings.add(menuElement);
+		}
+//		if (uriToMenuElement.isEmpty()) {
+//			logger.error("No menu elements found, check classpath/Raven/SPI");
+//		}
+	}
+
+	/**
+	 * Get the children which have the given URI specified as their parent, or
+	 * an empty list if no children exist.
+	 *
+	 * @param id
+	 *            The {@link URI} of the parent
+	 * @return The {@link List} of {@link MenuComponent} which have the given
+	 *         parent
+	 */
+	protected List<MenuComponent> getChildren(URI id) {
+		List<MenuComponent> children = null;
+		synchronized (menuElementTree) {
+			children = menuElementTree.get(id);
+			if (children != null)
+				children = new ArrayList<>(children);
+		}
+		if (children == null)
+			children = Collections.<MenuComponent> emptyList();
+		else
+			Collections.sort(children, menuElementComparator);
+		return children;
+	}
+
+	/**
+	 * Make the list of Swing {@link Component}s that are the children of the
+	 * given {@link URI}.
+	 *
+	 * @param id
+	 *            The {@link URI} of the parent which children are to be made
+	 * @param menuOptions
+	 *            Options of the created menu, for instance
+	 *            {@link MenuOptions#isToolbar()}.
+	 * @return A {@link List} of {@link Component}s that can be added to a
+	 *         {@link JMenuBar}, {@link JMenu} or {@link JToolBar}.
+	 */
+	protected List<Component> makeComponents(URI id, MenuOptions menuOptions) {
+		List<Component> components = new ArrayList<>();
+		for (MenuComponent childElement : getChildren(id)) {
+			if (childElement instanceof ContextualMenuComponent)
+				((ContextualMenuComponent) childElement)
+						.setContextualSelection(menuOptions
+								.getContextualSelection());
+			/*
+			 * Important - check this AFTER setContextualSelection so the item
+			 * can change it's enabled-state if needed.
+			 */
+			if (!childElement.isEnabled())
+				continue;
+			MenuType type = childElement.getType();
+			Action action = childElement.getAction();
+			URI childId = childElement.getId();
+			if (type.equals(MenuType.action)) {
+				if (action == null) {
+					logger.warn("Skipping invalid action " + childId + " for "
+							+ id);
+					continue;
+				}
+
+				Component actionComponent;
+				if (menuOptions.isOptionGroup()) {
+					if (menuOptions.isToolbar()) {
+						actionComponent = new JToggleButton(action);
+						toolbarizeButton((AbstractButton) actionComponent);
+					} else
+						actionComponent = new JRadioButtonMenuItem(action);
+				} else {
+					if (menuOptions.isToolbar()) {
+						actionComponent = new JButton(action);
+						toolbarizeButton((AbstractButton) actionComponent);
+					} else
+						actionComponent = new JMenuItem(action);
+				}
+				registerComponent(childId, actionComponent);
+				components.add(actionComponent);
+			} else if (type.equals(MenuType.toggle)) {
+				if (action == null) {
+					logger.warn("Skipping invalid toggle " + childId + " for "
+							+ id);
+					continue;
+				}
+				Component toggleComponent;
+				if (menuOptions.isToolbar())
+					toggleComponent = new JToggleButton(action);
+				else
+					toggleComponent = new JCheckBoxMenuItem(action);
+				registerComponent(childId, toggleComponent);
+				components.add(toggleComponent);
+			} else if (type.equals(MenuType.custom)) {
+				Component customComponent = childElement.getCustomComponent();
+				if (customComponent == null) {
+					logger.warn("Skipping null custom component " + childId
+							+ " for " + id);
+					continue;
+				}
+				registerComponent(childId, customComponent);
+				components.add(customComponent);
+			} else if (type.equals(MenuType.optionGroup))
+				addOptionGroup(components, childId, menuOptions);
+			else if (type.equals(MenuType.section))
+				addSection(components, childId, menuOptions);
+			else if (type.equals(MenuType.menu))
+				addMenu(components, childElement, menuOptions);
+			else {
+				logger.warn("Skipping invalid/unknown type " + type + " for "
+						+ id);
+				continue;
+			}
+		}
+		stripTrailingNullSeparator(components);
+		return components;
+	}
+
+	/**
+	 * Fill the specified menu bar with the menu elements that have the given
+	 * URI as their parent.
+	 * <p>
+	 * Existing elements on the menu bar will be removed.
+	 *
+	 * @param menuBar
+	 *            The {@link JMenuBar} to update
+	 * @param id
+	 *            The {@link URI} of the menu bar
+	 */
+	protected void populateMenuBar(JMenuBar menuBar, URI id) {
+		menuBar.removeAll();
+		MenuComponent menuDef = uriToMenuElement.get(id);
+		if (menuDef == null)
+			throw new IllegalArgumentException("Unknown menuBar " + id);
+		if (!menuDef.getType().equals(MenuType.menu))
+			throw new IllegalArgumentException("Element " + id
+					+ " is not a menu, but a " + menuDef.getType());
+		MenuOptions menuOptions = new MenuOptions();
+		for (Component component : makeComponents(id, menuOptions))
+			if (component == null)
+				logger.warn("Ignoring separator in menu bar " + id);
+			else
+				menuBar.add(component);
+	}
+
+	/**
+	 * Fill the specified menu bar with the menu elements that have the given
+	 * URI as their parent.
+	 * <p>
+	 * Existing elements on the menu bar will be removed.
+	 *
+	 * @param popupMenu
+	 *            The {@link JPopupMenu} to update
+	 * @param id
+	 *            The {@link URI} of the menu bar
+	 * @param contextualSelection
+	 *            The current selection for the context menu
+	 */
+	protected void populateContextMenu(JPopupMenu popupMenu, URI id,
+			ContextualSelection contextualSelection) {
+		popupMenu.removeAll();
+		MenuComponent menuDef = uriToMenuElement.get(id);
+		if (menuDef == null)
+			throw new IllegalArgumentException("Unknown menuBar " + id);
+		if (!menuDef.getType().equals(MenuType.menu))
+			throw new IllegalArgumentException("Element " + id
+					+ " is not a menu, but a " + menuDef.getType());
+		MenuOptions menuOptions = new MenuOptions();
+		menuOptions.setContextualSelection(contextualSelection);
+		for (Component component : makeComponents(id, menuOptions))
+			if (component == null)
+				popupMenu.addSeparator();
+			else
+				popupMenu.add(component);
+	}
+
+	/**
+	 * Fill the specified tool bar with the elements that have the given URI as
+	 * their parent.
+	 * <p>
+	 * Existing elements on the tool bar will be removed.
+	 *
+	 * @param toolbar
+	 *            The {@link JToolBar} to update
+	 * @param id
+	 *            The {@link URI} of the tool bar
+	 */
+	protected void populateToolBar(JToolBar toolbar, URI id) {
+		toolbar.removeAll();
+		MenuComponent toolbarDef = uriToMenuElement.get(id);
+		if (toolbarDef == null)
+			throw new IllegalArgumentException("Unknown toolBar " + id);
+		if (!toolbarDef.getType().equals(MenuType.toolBar))
+			throw new IllegalArgumentException("Element " + id
+					+ " is not a toolBar, but a " + toolbarDef.getType());
+		if (toolbarDef.getAction() != null) {
+			String name = (String) toolbarDef.getAction().getValue(Action.NAME);
+			toolbar.setName(name);
+		} else
+			toolbar.setName("");
+		MenuOptions menuOptions = new MenuOptions();
+		menuOptions.setToolbar(true);
+		for (Component component : makeComponents(id, menuOptions)) {
+			if (component == null) {
+				toolbar.addSeparator();
+				continue;
+			}
+			if (component instanceof JButton) {
+				JButton toolbarButton = (JButton) component;
+				toolbarButton.putClientProperty("hideActionText", true);
+			}
+			toolbar.add(component);
+		}
+	}
+
+	/**
+	 * Register a component that has been created. Such a component can be
+	 * resolved through {@link #getComponentByURI(URI)}.
+	 *
+	 * @param id
+	 *            The {@link URI} that defined the component
+	 * @param component
+	 *            The {@link Component} that was created.
+	 */
+	protected synchronized void registerComponent(URI id, Component component) {
+		registerComponent(id, component, false);
+	}
+
+	/**
+	 * Register a component that has been created. Such a component can be
+	 * resolved through {@link #getComponentByURI(URI)}.
+	 *
+	 * @param id
+	 *            The {@link URI} that defined the component
+	 * @param component
+	 *            The {@link Component} that was created.
+	 * @param published
+	 *            <code>true</code> if the component has been published through
+	 *            {@link #createMenuBar()} or similar, and is to be
+	 *            automatically updated by later calls to {@link #update()}.
+	 */
+	protected synchronized void registerComponent(URI id, Component component,
+			boolean published) {
+		uriToComponent.put(id, new WeakReference<>(component));
+		componentToUri.put(component, id);
+		if (published) {
+			List<WeakReference<Component>> publishedComponents = uriToPublishedComponents
+					.get(id);
+			if (publishedComponents == null) {
+				publishedComponents = new ArrayList<>();
+				uriToPublishedComponents.put(id, publishedComponents);
+			}
+			publishedComponents.add(new WeakReference<>(component));
+		}
+		setHelpStringForComponent(component, id);
+	}
+
+	/**
+	 * Reset all collections
+	 *
+	 */
+	protected synchronized void resetCollections() {
+		menuElementTree = new HashMap<>();
+		componentToUri = new WeakHashMap<>();
+		uriToMenuElement = new HashMap<>();
+		uriToComponent = new HashMap<>();
+	}
+
+	/**
+	 * Set javax.help string to identify the component for later references to
+	 * the help document. Note that the component (ie. the
+	 * {@link AbstractMenuAction} must have an ID for an registration to take
+	 * place.
+	 *
+	 * @param component
+	 *            The {@link Component} to set help string for
+	 * @param componentId
+	 *            The {@link URI} to be used as identifier
+	 */
+	protected void setHelpStringForComponent(Component component,
+			URI componentId) {
+		if (componentId != null) {
+			String helpId = componentId.toASCIIString();
+			setHelpIDString(component, helpId);
+		}
+	}
+
+	/**
+	 * Make an {@link AbstractButton} be configured in a "toolbar-like" way, for
+	 * instance showing only the icon.
+	 *
+	 * @param actionButton
+	 *            Button to toolbarise
+	 */
+	protected void toolbarizeButton(AbstractButton actionButton) {
+		Action action = actionButton.getAction();
+		if (action.getValue(SHORT_DESCRIPTION) == null)
+			action.putValue(SHORT_DESCRIPTION, action.getValue(NAME));
+		actionButton.setBorder(new EmptyBorder(0, 2, 0, 2));
+		// actionButton.setHorizontalTextPosition(JButton.CENTER);
+		// actionButton.setVerticalTextPosition(JButton.BOTTOM);
+		if (action.getValue(Action.SMALL_ICON) != null) {
+			// Don't show the text
+			actionButton.putClientProperty("hideActionText", true);
+			// Since hideActionText seems to be broken in Java 5 and/or OS X
+			actionButton.setText(null);
+		}
+	}
+
+	/**
+	 * Update all components that have been published using
+	 * {@link #createMenuBar()} and similar. Content of such components will be
+	 * removed and replaced by fresh components.
+	 */
+	protected void updatePublishedComponents() {
+		for (Entry<URI, List<WeakReference<Component>>> entry : uriToPublishedComponents
+				.entrySet())
+			for (WeakReference<Component> reference : entry.getValue()) {
+				URI id = entry.getKey();
+				Component component = reference.get();
+				if (component == null)
+					continue;
+				if (component instanceof JToolBar)
+					populateToolBar((JToolBar) component, id);
+				else if (component instanceof JMenuBar)
+					populateMenuBar((JMenuBar) component, id);
+				else
+					logger.warn("Could not update published component " + id
+							+ ": " + component.getClass());
+			}
+	}
+
+	public void setMenuComponents(List<MenuComponent> menuComponents) {
+		this.menuComponents = menuComponents;
+	}
+
+	public void setSelectionManager(SelectionManager selectionManager) {
+		selectionManager.addObserver(new SelectionManagerObserver());
+	}
+
+	/**
+	 * {@link Comparator} that can order {@link MenuComponent}s by their
+	 * {@link MenuComponent#getPositionHint()}.
+	 */
+	protected static class MenuElementComparator implements
+			Comparator<MenuComponent> {
+		@Override
+		public int compare(MenuComponent a, MenuComponent b) {
+			return a.getPositionHint() - b.getPositionHint();
+		}
+	}
+
+	/**
+	 * Various options for
+	 * {@link MenuManagerImpl#makeComponents(URI, MenuOptions)} and friends.
+	 *
+	 * @author Stian Soiland-Reyes
+	 */
+	public static class MenuOptions {
+		private boolean isToolbar = false;
+		private boolean isOptionGroup = false;
+		private ContextualSelection contextualSelection = null;
+
+		public ContextualSelection getContextualSelection() {
+			return contextualSelection;
+		}
+
+		public void setContextualSelection(
+				ContextualSelection contextualSelection) {
+			this.contextualSelection = contextualSelection;
+		}
+
+		public MenuOptions(MenuOptions original) {
+			this.isOptionGroup = original.isOptionGroup();
+			this.isToolbar = original.isToolbar();
+			this.contextualSelection = original.getContextualSelection();
+		}
+
+		public MenuOptions() {
+		}
+
+		@Override
+		protected MenuOptions clone() {
+			return new MenuOptions(this);
+		}
+
+		public boolean isToolbar() {
+			return isToolbar;
+		}
+
+		public void setToolbar(boolean isToolbar) {
+			this.isToolbar = isToolbar;
+		}
+
+		public boolean isOptionGroup() {
+			return isOptionGroup;
+		}
+
+		public void setOptionGroup(boolean isOptionGroup) {
+			this.isOptionGroup = isOptionGroup;
+		}
+	}
+
+	private final class SelectionManagerObserver extends
+			SwingAwareObserver<SelectionManagerEvent> {
+		private static final String DESIGN_PERSPECTIVE_ID = "net.sf.taverna.t2.ui.perspectives.design.DesignPerspective";
+		private static final String RESULTS_PERSPECTIVE_ID = "net.sf.taverna.t2.ui.perspectives.results.ResultsPerspective";
+
+		@Override
+		public void notifySwing(Observable<SelectionManagerEvent> sender,
+				SelectionManagerEvent message) {
+			if (!(message instanceof PerspectiveSelectionEvent))
+				return;
+			handlePerspectiveSelect((PerspectiveSelectionEvent) message);
+		}
+
+		private void handlePerspectiveSelect(PerspectiveSelectionEvent event) {
+			String perspectiveID = event.getSelectedPerspective().getID();
+			boolean isDesign = DESIGN_PERSPECTIVE_ID.equals(perspectiveID);
+			boolean isResults = RESULTS_PERSPECTIVE_ID.equals(perspectiveID);
+
+			for (MenuComponent menuComponent : menuComponents)
+				if (!(menuComponent instanceof ContextualMenuComponent)) {
+					Action action = menuComponent.getAction();
+					if (action instanceof DesignOnlyAction)
+						action.setEnabled(isDesign);
+					else if (action instanceof DesignOrResultsAction)
+						action.setEnabled(isDesign || isResults);
+				}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/org/apache/taverna/workbench/ui/impl/menu/AdvancedMenu.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/org/apache/taverna/workbench/ui/impl/menu/AdvancedMenu.java b/taverna-menu-impl/src/main/java/org/apache/taverna/workbench/ui/impl/menu/AdvancedMenu.java
new file mode 100644
index 0000000..50c57e0
--- /dev/null
+++ b/taverna-menu-impl/src/main/java/org/apache/taverna/workbench/ui/impl/menu/AdvancedMenu.java
@@ -0,0 +1,43 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.impl.menu;
+
+import static java.awt.event.KeyEvent.VK_A;
+import static javax.swing.Action.MNEMONIC_KEY;
+import static org.apache.taverna.ui.menu.DefaultMenuBar.DEFAULT_MENU_BAR;
+
+import java.net.URI;
+
+import org.apache.taverna.ui.menu.AbstractMenu;
+
+public class AdvancedMenu extends AbstractMenu {
+	public static final URI ADVANCED_URI = URI
+			.create("http://taverna.sf.net/2008/t2workbench/menu#advanced");
+
+	public AdvancedMenu() {
+		super(DEFAULT_MENU_BAR, 1000, ADVANCED_URI, makeAction());
+	}
+
+	public static DummyAction makeAction() {
+		DummyAction action = new DummyAction("Advanced");
+		action.putValue(MNEMONIC_KEY, Integer.valueOf(VK_A));
+		return action;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/org/apache/taverna/workbench/ui/impl/menu/EditMenu.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/org/apache/taverna/workbench/ui/impl/menu/EditMenu.java b/taverna-menu-impl/src/main/java/org/apache/taverna/workbench/ui/impl/menu/EditMenu.java
new file mode 100644
index 0000000..4d63107
--- /dev/null
+++ b/taverna-menu-impl/src/main/java/org/apache/taverna/workbench/ui/impl/menu/EditMenu.java
@@ -0,0 +1,42 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.impl.menu;
+
+import static java.awt.event.KeyEvent.VK_E;
+import static javax.swing.Action.MNEMONIC_KEY;
+import static org.apache.taverna.ui.menu.DefaultMenuBar.DEFAULT_MENU_BAR;
+
+import java.net.URI;
+
+import org.apache.taverna.ui.menu.AbstractMenu;
+
+public class EditMenu extends AbstractMenu {
+	public EditMenu() {
+		super(DEFAULT_MENU_BAR, 20, URI
+				.create("http://taverna.sf.net/2008/t2workbench/menu#edit"),
+				makeAction());
+	}
+
+	public static DummyAction makeAction() {
+		DummyAction action = new DummyAction("Edit");
+		action.putValue(MNEMONIC_KEY, Integer.valueOf(VK_E));
+		return action;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-impl/src/main/java/org/apache/taverna/workbench/ui/impl/menu/FeedbackMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-menu-impl/src/main/java/org/apache/taverna/workbench/ui/impl/menu/FeedbackMenuAction.java b/taverna-menu-impl/src/main/java/org/apache/taverna/workbench/ui/impl/menu/FeedbackMenuAction.java
new file mode 100644
index 0000000..3cb6b7d
--- /dev/null
+++ b/taverna-menu-impl/src/main/java/org/apache/taverna/workbench/ui/impl/menu/FeedbackMenuAction.java
@@ -0,0 +1,74 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.impl.menu;
+
+import static java.awt.Desktop.getDesktop;
+import static org.apache.taverna.workbench.ui.impl.menu.HelpMenu.HELP_URI;
+
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import org.apache.taverna.ui.menu.AbstractMenuAction;
+
+import org.apache.log4j.Logger;
+
+/**
+ * MenuItem for feedback
+ * 
+ * @author alanrw
+ */
+public class FeedbackMenuAction extends AbstractMenuAction {
+	private static Logger logger = Logger.getLogger(FeedbackMenuAction.class);
+
+	private static String FEEDBACK_URL = "http://www.taverna.org.uk/about/contact-us/feedback/";
+
+	public FeedbackMenuAction() {
+		super(HELP_URI, 20);
+	}
+
+	@Override
+	protected Action createAction() {
+		return new FeedbackAction();
+	}
+
+	@SuppressWarnings("serial")
+	private final class FeedbackAction extends AbstractAction {
+		private FeedbackAction() {
+			super("Contact us");
+		}
+
+		@Override
+		public void actionPerformed(ActionEvent e) {
+			try {
+				getDesktop().browse(new URI(FEEDBACK_URL));
+			} catch (IOException e1) {
+				logger.error("Unable to open URL", e1);
+			} catch (URISyntaxException e1) {
+				logger.error("Invalid URL syntax", e1);
+			}
+		}
+	}
+
+}