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);
+                       }
+               }
+       }
+
+}

Reply via email to