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

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

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/AbstractMenuSection.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/AbstractMenuSection.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/AbstractMenuSection.java
new file mode 100644
index 0000000..9966d0f
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/AbstractMenuSection.java
@@ -0,0 +1,112 @@
+/*
+* 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;
+
+import java.awt.Color;
+import java.net.URI;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+/**
+ * A {@link MenuComponent} of the type {@link MenuType#section}.
+ * <p>
+ * Subclass to create an SPI implementation for the {@link MenuManager} of a
+ * section. A section is a part of a {@linkplain AbstractMenu menu} or
+ * {@linkplain AbstractToolBar toolbar} that group together
+ * {@linkplain AbstractMenuAction actions} or {@linkplain AbstractMenuToggle
+ * toggles}, and separates them from siblings using separators if needed.
+ * <p>
+ * Menu components are linked together using URIs, avoiding the need for compile
+ * time dependencies between SPI implementations. To add actions to a section,
+ * use the {@link URI} identifying this section as their parent id.
+ * <p>
+ * <strong>Note:</strong> To avoid conflicts with other plugins, use a unique
+ * URI root that is related to the Java package name, for instance
+ * <code>http://cs.university.ac.uk/myplugin/2008/menu</code>, and use hash
+ * identifiers for each menu item, for instance
+ * <code>http://cs.university.ac.uk/myplugin/2008/menu#run</code> for a "Run"
+ * item. Use flat URI namespaces, don't base a child's URI on the parent's URI,
+ * as this might make it difficult to relocate the parent menu.
+ * <p>
+ * You need to list the {@linkplain Class#getName() fully qualified class name}
+ * (for example <code>com.example.t2plugin.menu.MyMenu</code>) of the section
+ * implementation in the SPI description resource file
+ * <code>/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent</code> so
+ * that it can be discovered by the {@link MenuManager}. This requirement also
+ * applies to parent menu components (except {@link DefaultToolBar} and
+ * {@link DefaultMenuBar}, but ensure they are only listed once.
+ * 
+ * @author Stian Soiland-Reyes
+ */
+public abstract class AbstractMenuSection extends AbstractMenuItem {
+	public static final String SECTION_COLOR = "sectionColor";
+
+	/**
+	 * Construct a menu section.
+	 * 
+	 * @param parentId
+	 *            The {@link URI} of the parent menu component. The parent
+	 *            should be of type {@link MenuType#menu} or
+	 *            {@link MenuType#toolBar}.
+	 * @param positionHint
+	 *            The position hint to determine the position of this section
+	 *            among its siblings in the parent menu. For extensibility, use
+	 *            BASIC style numbering such as 10, 20, etc. (Note that position
+	 *            hints are local to each parent, so each section have their own
+	 *            position hint scheme for their children.)
+	 * @param id
+	 *            The {@link URI} to identify this menu section. Use this as the
+	 *            parent ID for menu components to appear in this section.
+	 */
+	public AbstractMenuSection(URI parentId, int positionHint, URI id) {
+		super(MenuType.section, parentId, id);
+		this.positionHint = positionHint;
+	}
+
+	@Override
+	public synchronized Action getAction() {
+		if (action == null)
+			action = createAction();
+		return action;
+	}
+
+	/**
+	 * (Optionally) Create the {@link Action} that labels this section.
+	 * <p>
+	 * The actual action will be ignored, but the label and/or icon will be used
+	 * as a section header in the menu. If the property {@link #SECTION_COLOR}
+	 * has been defined in the action, that {@link Color} will be used to make
+	 * the section background.
+	 * <p>
+	 * The default implementation of this method returns <code>null</code>,
+	 * meaning that no section header will be created - instead a simple line
+	 * will separate this section from the items above (if needed).
+	 * <p>
+	 * Implementations might use {@link AbstractAction} as a superclass for menu
+	 * actions.
+	 * 
+	 * @return A configured {@link Action} that should at least have a label or
+	 *         icon.
+	 */
+	protected Action createAction() {
+		return null;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/AbstractMenuToggle.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/AbstractMenuToggle.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/AbstractMenuToggle.java
new file mode 100644
index 0000000..70c47f5
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/AbstractMenuToggle.java
@@ -0,0 +1,131 @@
+/*
+* 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;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.URI;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+/**
+ * A {@link MenuComponent} of the type {@link MenuType#toggle}.
+ * <p>
+ * Subclass to create an SPI implementation for the {@link MenuManager} of an
+ * toggle action. A toggle is a menu item that can be turned on/off and are
+ * typically represented with a check box when they are enabled.
+ * <p>
+ * This action can have as an parent a {@linkplain AbstractMenu menu} or
+ * {@linkplain AbstractToolBar toolbar}, or grouped within a
+ * {@linkplain AbstractMenuSection section} or
+ * {@linkplain AbstractMenuOptionGroup option group}.
+ * <p>
+ * To define the {@link Action}, implement {@link #createAction()}. The action
+ * should provide both the label/icon (representation) and
+ * {@link ActionListener#actionPerformed(ActionEvent)}.
+ * <p>
+ * You need to list the {@linkplain Class#getName() fully qualified class name}
+ * (for example <code>com.example.t2plugin.menu.MyMenuAction</code>) of the menu
+ * action implementation in the SPI description resource file
+ * <code>/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent</code> so
+ * that it can be discovered by the {@link MenuManager}. This requirement also
+ * applies to parent menu components (except {@link DefaultToolBar} and
+ * {@link DefaultMenuBar}, but ensure they are only listed once.
+ * 
+ * @author Stian Soiland-Reyes
+ */
+public abstract class AbstractMenuToggle extends AbstractMenuItem {
+	/**
+	 * Construct a toggle action to appear within the specified menu component.
+	 * 
+	 * @param parentId
+	 *            The {@link URI} of the parent menu component. The component
+	 *            should be a {@linkplain MenuType#isParentType() parent type}
+	 *            and must have been registered separately as an SPI.
+	 * @param positionHint
+	 *            The position hint to determine the position of this toggle
+	 *            action among its siblings in the parent menu, section or
+	 *            toolbar. For extensibility, use BASIC style numbering such as
+	 *            10, 20, etc. (Note that position hints are local to each
+	 *            parent, so each {@linkplain AbstractMenuSection section} have
+	 *            their own position hint scheme.)
+	 */
+	public AbstractMenuToggle(URI parentId, int positionHint) {
+		this(parentId, null, positionHint);
+	}
+
+	/**
+	 * Construct a toggle action to appear within the specified menu component.
+	 * 
+	 * @param parentId
+	 *            The {@link URI} of the parent menu component. The component
+	 *            should be a {@link MenuType#isParentType() parent type} and
+	 *            must have been registered separately as an SPI.
+	 * @param id
+	 *            The {@link URI} to identify this toggle action. Although no
+	 *            components can have an action as their parent, this URI can be
+	 *            used to retrieve the realisation of this component using
+	 *            {@link MenuManager#getComponentByURI(URI)}. This ID might also
+	 *            be registered as a help identifier with the help system.
+	 * @param positionHint
+	 *            The position hint to determine the position of this action
+	 *            among its siblings in the parent menu, section or toolbar. For
+	 *            extensibility, use BASIC style numbering such as 10, 20, etc.
+	 *            (Note that position hints are local to each parent, so each
+	 *            {@linkplain AbstractMenuSection section} have their own
+	 *            position hint scheme.)
+	 */
+	public AbstractMenuToggle(URI parentId, URI id, int positionHint) {
+		super(MenuType.toggle, parentId, id);
+		this.positionHint = positionHint;
+	}
+
+	/**
+	 * Call {@link #createAction()} on first call, after that return cached
+	 * action.
+	 * 
+	 * @see #createAction()
+	 * 
+	 *      {@inheritDoc}
+	 */
+	@Override
+	public synchronized Action getAction() {
+		if (action == null)
+			action = createAction();
+		return action;
+	}
+
+	/**
+	 * Create the {@link Action} that labels this toggle action, in addition to
+	 * performing the desired action on
+	 * {@link ActionListener#actionPerformed(ActionEvent)}.
+	 * <p>
+	 * Implementations might use {@link AbstractAction} as a superclass for menu
+	 * actions. It is recommended to make the action a top level class so that
+	 * it can be used both within an {@link AbstractMenuAction} of a menu bar
+	 * and within an {@link AbstractMenuAction} of a tool bar.
+	 * </p>
+	 * 
+	 * @return A configured {@link Action} that should at least have a label or
+	 *         icon.
+	 */
+	protected abstract Action createAction();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/AbstractToolBar.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/AbstractToolBar.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/AbstractToolBar.java
new file mode 100644
index 0000000..c3fe045
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/AbstractToolBar.java
@@ -0,0 +1,73 @@
+/*
+* 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;
+
+import java.net.URI;
+
+/**
+ * A {@link MenuComponent} of the type {@link MenuType#toolBar}.
+ * <p>
+ * Subclass to create an SPI implementation for the {@link MenuManager} of a
+ * toolbar. A toolbar can contain {@linkplain AbstractMenuAction actions},
+ * {@linkplain AbstractMenuToggle toggles} or {@linkplain AbstractMenuCustom
+ * custom components}, or any of the above grouped in a
+ * {@linkplain AbstractMenuSection section} or an
+ * {@linkplain AbstractMenuOptionGroup option group}.
+ * <p>
+ * The {@link DefaultToolBar default toolbar} can be used as a parent for items
+ * that are to be returned in the toolbar {@link MenuManager#createToolBar()},
+ * while toolbars from other instances of AbstractToolBar can be created using
+ * {@link MenuManager#createToolBar(URI)} specifying the URI of the toolbar's
+ * identifier.
+ * <p>
+ * Menu components are linked together using URIs, avoiding the need for compile
+ * time dependencies between SPI implementations. To add components to a
+ * toolbar, use the {@link URI} identifying this toolbar as their parent id.
+ * <p>
+ * <strong>Note:</strong> To avoid conflicts with other plugins, use a unique
+ * URI root that is related to the Java package name, for instance
+ * <code>http://cs.university.ac.uk/myplugin/2008/menu</code>, and use hash
+ * identifiers for each menu item, for instance
+ * <code>http://cs.university.ac.uk/myplugin/2008/menu#run</code> for a "Run"
+ * item. Use flat URI namespaces, don't base a child's URI on the parent's URI,
+ * as this might make it difficult to relocate the parent menu.
+ * <p>
+ * You need to list the {@linkplain Class#getName() fully qualified class name}
+ * (for example <code>com.example.t2plugin.menu.MyMenu</code>) of the toolbar
+ * implementation in the SPI description resource file
+ * <code>/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent</code> so
+ * that it can be discovered by the {@link MenuManager}. This requirement also
+ * applies to parent menu components (except {@link DefaultToolBar} and
+ * {@link DefaultMenuBar}, but ensure they are only listed once.
+ * 
+ * @author Stian Soiland-Reyes
+ */
+public abstract class AbstractToolBar extends AbstractMenuItem {
+	/**
+	 * Construct a toolbar with the given {@link URI} as identifier.
+	 * 
+	 * @param id
+	 *            The {@link URI} to identify this toolbar. Use this as the
+	 *            parent ID for menu components to appear in this toolbar.
+	 */
+	public AbstractToolBar(URI id) {
+		super(MenuType.toolBar, null, id);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/ContextualMenuComponent.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/ContextualMenuComponent.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/ContextualMenuComponent.java
new file mode 100644
index 0000000..ec729cf
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/ContextualMenuComponent.java
@@ -0,0 +1,54 @@
+/*
+* 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;
+
+import java.awt.Component;
+
+/**
+ * A contextual menu component.
+ * <p>
+ * A {@link MenuComponent} that also implements ContextualMenuComponent, when
+ * included in a menu tree rooted in the {@link DefaultContextualMenu} and
+ * retrieved using
+ * {@link MenuManager#createContextMenu(Object, Object, Component)}, will be
+ * {@linkplain #setContextualSelection(ContextualSelection) informed} before
+ * calls to {@link #isEnabled()} or {@link #getAction()}.
+ * <p>
+ * In this way the contextual menu item can be visible for only certain
+ * selections, and its action can be bound to the current selection.
+ * <p>
+ * Contextual menu components can be grouped by {@linkplain AbstractMenuSection
+ * sections} and {@linkplain AbstractMenu sub-menus}, or directly have the
+ * {@link DefaultContextualMenu} as the parent.
+ * 
+ * @see ContextualSelection
+ * @see DefaultContextualMenu
+ * @author Stian Soiland-Reyes
+ */
+public interface ContextualMenuComponent extends MenuComponent {
+	/**
+	 * Set the contextual selection, or <code>null</code> if there is no current
+	 * selection (if the menu item was not included in a contextual menu).
+	 * 
+	 * @param contextualSelection
+	 *            The contextual selection
+	 */
+	void setContextualSelection(ContextualSelection contextualSelection);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/ContextualSelection.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/ContextualSelection.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/ContextualSelection.java
new file mode 100644
index 0000000..19ef657
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/ContextualSelection.java
@@ -0,0 +1,67 @@
+/*
+* 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;
+
+import java.awt.Component;
+
+import javax.swing.JPopupMenu;
+
+import org.apache.taverna.scufl2.api.core.Workflow;
+
+/**
+ * A contextual selection as passed to a {@link ContextualMenuComponent}.
+ * 
+ * @author Stian Soiland-Reyes
+ */
+public class ContextualSelection {
+	private final Object parent;
+	private final Object selection;
+	private final Component relativeToComponent;
+
+	public ContextualSelection(Object parent, Object selection,
+			Component relativeToComponent) {
+		this.parent = parent;
+		this.selection = selection;
+		this.relativeToComponent = relativeToComponent;
+	}
+
+	/**
+	 * The parent object of the selected object, for instance a {@link Workflow}.
+	 */
+	public Object getParent() {
+		return parent;
+	}
+
+	/**
+	 * The selected object which actions in the contextual menu relate to, for
+	 * instance a Processor.
+	 */
+	public Object getSelection() {
+		return selection;
+	}
+
+	/**
+	 * A UI component which the returned {@link JPopupMenu} (and it's actions)
+	 * is to be relative to, for instance as a parent of pop-up dialogues.
+	 */
+	public Component getRelativeToComponent() {
+		return relativeToComponent;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DefaultContextualMenu.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DefaultContextualMenu.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DefaultContextualMenu.java
new file mode 100644
index 0000000..57e1f53
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DefaultContextualMenu.java
@@ -0,0 +1,52 @@
+/*
+* 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;
+
+import java.net.URI;
+
+/**
+ * The default contextual menu, created using
+ * {@link MenuManager#createContextMenu(Object, Object, java.awt.Component)()}.
+ * <p>
+ * Items that are part of a contextual menu should also implement
+ * {@link ContextualMenuComponent}, the menu manager will then be able to tell
+ * the items what is the current selection for the contextual menu, so that the
+ * items can update their {@link MenuComponent#isEnabled()} (only visible for
+ * some selections) and {@link MenuComponent#getAction()} (the action needs the
+ * selected object).
+ * 
+ * @author Stian Soiland-Reyes
+ */
+public class DefaultContextualMenu extends AbstractMenu {
+	/**
+	 * The URI of a menu item representing the default menu bar. Menu items who
+	 * has this URI as their {@link #getParentId()} will be shown in the top
+	 * menu of the main application window.
+	 */
+	public static final URI DEFAULT_CONTEXT_MENU = URI
+			.create("http://taverna.sf.net/2008/t2workbench/menu#defaultContextMenu");
+
+	/**
+	 * Construct the default menu bar
+	 */
+	public DefaultContextualMenu() {
+		super(DEFAULT_CONTEXT_MENU);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DefaultMenuBar.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DefaultMenuBar.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DefaultMenuBar.java
new file mode 100644
index 0000000..2ddef45
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DefaultMenuBar.java
@@ -0,0 +1,49 @@
+/*
+* 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;
+
+import java.net.URI;
+
+/**
+ * The default {@link AbstractMenu menu bar} that appears in the main
+ * application window, created using {@link MenuManager#createMenuBar()}.
+ * Alternative menu bars can be created using
+ * {@link MenuManager#createMenuBar(URI)} - referring to the URI of another
+ * instance of {@link AbstractMenu}.
+ * 
+ * @author Stian Soiland-Reyes
+ */
+public class DefaultMenuBar extends AbstractMenu {
+	/**
+	 * The URI of a menu item representing the default menu bar. Menu items who
+	 * has this URI as their {@link #getParentId()} will be shown in the top
+	 * menu of the main application window.
+	 */
+	public static final URI DEFAULT_MENU_BAR = URI
+			.create("http://taverna.sf.net/2008/t2workbench/menu#defaultMenuBar");
+
+	/**
+	 * Construct the default menu bar
+	 * 
+	 */
+	public DefaultMenuBar() {
+		super(DEFAULT_MENU_BAR);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DefaultToolBar.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DefaultToolBar.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DefaultToolBar.java
new file mode 100644
index 0000000..7aab590
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DefaultToolBar.java
@@ -0,0 +1,50 @@
+/*
+* 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;
+
+import java.net.URI;
+
+/**
+ * The default tool bar that will be shown by the main application window. Use
+ * {@link #DEFAULT_TOOL_BAR} as the {@link #getParentId()} for items that should
+ * appear in this toolbar. This toolbar can be created using
+ * {@link MenuManager#createToolBar()}
+ * <p>
+ * Separate toolbars can be made by subclassing {@link AbstractToolBar} and
+ * created by using {@link MenuManager#createToolBar(URI)}.
+ * 
+ * @author Stian Soiland-Reyes
+ */
+public class DefaultToolBar extends AbstractToolBar {
+	/**
+	 * The URI of a tool bar item representing the default tool bar. Items who
+	 * has this URI as their {@link #getParentId()} will be shown in the default
+	 * toolbar of the main application window.
+	 */
+	public static final URI DEFAULT_TOOL_BAR = URI
+			.create("http://taverna.sf.net/2008/t2workbench/menu#defaultToolBar");
+
+	/**
+	 * Construct the default toolbar.
+	 */
+	public DefaultToolBar() {
+		super(DEFAULT_TOOL_BAR);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DesignOnlyAction.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DesignOnlyAction.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DesignOnlyAction.java
new file mode 100644
index 0000000..8614e64
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DesignOnlyAction.java
@@ -0,0 +1,31 @@
+/*
+* 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;
+
+/**
+ * Marker interface for actions that are valid only when the design perspective
+ * is selected.
+ * 
+ * @author alanrw
+ * @author David Withers
+ */
+public interface DesignOnlyAction {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DesignOrResultsAction.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DesignOrResultsAction.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DesignOrResultsAction.java
new file mode 100644
index 0000000..a922b46
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/DesignOrResultsAction.java
@@ -0,0 +1,31 @@
+/*
+* 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;
+
+/**
+ * Marker interface for actions that are valid the design or result perspectives
+ * are selected.
+ * 
+ * @author alanrw
+ * @author David Withers
+ */
+public interface DesignOrResultsAction {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/MenuComponent.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/MenuComponent.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/MenuComponent.java
new file mode 100644
index 0000000..4ac1d7d
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/MenuComponent.java
@@ -0,0 +1,276 @@
+/*
+* 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;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.URI;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.swing.Action;
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JMenu;
+import javax.swing.JToolBar;
+import javax.swing.MenuElement;
+
+/**
+ * A menu component, including sub menus, toolbars, and menu items.
+ * <p>
+ * This is an {@link net.sf.taverna.t2.spi.SPIRegistry SPI}, and implementations
+ * should list their fully qualified classnames in
+ * <tt>META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent</tt> to be
+ * discovered by the {@link MenuManager}.
+ * 
+ * @author Stian Soiland-Reyes
+ * @author David Withers
+ */
+public interface MenuComponent {
+	/**
+	 * The {@link Action} describing this menu item, used for creating the UI
+	 * representation of this item.
+	 * <p>
+	 * As a minimum the action should contain a name, and optionally an icon, a
+	 * description and a keyboard shortcut. For {@linkplain MenuType#action
+	 * actions} and {@linkplain MenuType#toggle toggles} the {@link Action}'s
+	 * {@link ActionListener#actionPerformed(ActionEvent)} method is called when
+	 * the item is clicked/selected.
+	 * <p>
+	 * This action is ignored and should be <code>null</code> for items of type
+	 * {@link MenuType#optionGroup} and {@link MenuType#custom}. The action is
+	 * optional for {@linkplain MenuType#toolBar toolbars} and
+	 * {@linkplain MenuType#section sections}, where the action's name would be
+	 * used as a label.
+	 * 
+	 * @return The {@link Action} describing this menu item, or
+	 *         <code>null</code> if the {@link #getType()} is
+	 *         {@link MenuType#section}, {@link MenuType#optionGroup} or
+	 *         {@link MenuType#custom}.
+	 */
+	public Action getAction();
+
+	/**
+	 * Get a custom {@link Component} to be inserted into the parent
+	 * menu/toolbar.
+	 * <p>
+	 * Used instead of creating menu elements from the {@link #getAction()} if
+	 * the {@link #getType()} is {@link MenuType#custom}. This can be used to
+	 * include dynamic menus.
+	 * <p>
+	 * This value is ignored and should be <code>null</code> for all other types
+	 * except {@link MenuType#custom}.
+	 * 
+	 * @return A {@link Component} to be inserted into the parent menu/toolbar.
+	 */
+	public Component getCustomComponent();
+
+	/**
+	 * The {@link URI} to identify this menu item.
+	 * <p>
+	 * This identifier can be used with other menu item's {@link #getParentId()}
+	 * if this item has a {@link #getType()} of {@link MenuType#menu},
+	 * {@link MenuType#toolBar}, {@link MenuType#section} or
+	 * {@link MenuType#optionGroup}.
+	 * <p>
+	 * Leaf menu items of {@link #getType()} {@link MenuType#toggle},
+	 * {@link MenuType#custom} and {@link MenuType#action} don't need an
+	 * identifier as they can't have children, and may return <code>null</code>
+	 * instead. However, a valid identifier might be used to look up the
+	 * MenuItem with {@link MenuManager#getComponentByURI(URI)}
+	 * <p>
+	 * <strong>Note:</strong> To avoid conflicts with other plugins, use a
+	 * unique URI root that is related to the Java package name, for instance
+	 * <code>http://cs.university.ac.uk/myplugin/2008/menu</code>, and use hash
+	 * identifiers for each menu item, for instance
+	 * <code>http://cs.university.ac.uk/myplugin/2008/menu#run</code> for a
+	 * "Run" item. Use flat URI namespaces, don't base a child's URI on the
+	 * parent's URI, as this might make it difficult to relocate the parent
+	 * menu.
+	 * 
+	 * @return The {@link URI} to identify this menu item.
+	 */
+	public URI getId();
+
+	/**
+	 * The {@link URI} of the parent menu item, as returned by the parent's
+	 * {@link #getId()}.
+	 * <p>
+	 * If this is the {@link DefaultMenuBar#DEFAULT_MENU_BAR}, then this menu
+	 * item will be one of the top level menus of the main application window,
+	 * like "File" or "Edit", and must have {@link #getType()}
+	 * {@link MenuType#menu}.
+	 * <p>
+	 * This value should be <code>null</code> if this item is of
+	 * {@link #getType()} {@link MenuType#toolBar}, and could be
+	 * <code>null</code> if this is an independent root menu of type
+	 * {@link MenuType#menu} (to be used outside the main window).
+	 * <p>
+	 * <strong>Note:</strong> To avoid compile time and runtime dependency on
+	 * the parent menu item, always construct this URI directly using
+	 * {@link URI#create(String)}.
+	 * 
+	 * @return The {@link URI} of the parent menu item.
+	 */
+	public URI getParentId();
+
+	/**
+	 * A hint on how to position this item below the parent.
+	 * <p>
+	 * Menu items within the same parent menu/group/toolBar are ordered
+	 * according to this position hint. If several items have the same position
+	 * hint, their internal order is undefined, although generally it will be
+	 * the order in which they were loaded.
+	 * <p>
+	 * <strong>Tip:</strong> Number the position hints in BASIC style, such as
+	 * 10, 20, etc. so that plugins can use position hint such as 19 or 21 to be
+	 * immediately before or after your item.
+	 * 
+	 * @return A position hint
+	 */
+	public int getPositionHint();
+
+	/**
+	 * The {@link MenuType type} of menu item.
+	 * <p>
+	 * In the simple case of a "File -> New" menu structure, the "File" menu
+	 * item has a type of {@link MenuType#menu}, while the "New" has a type of
+	 * {@link MenuType#action}.
+	 * <p>
+	 * The menu item can only have children (i.e., items with
+	 * {@link #getParentId()} equalling to this item's {@link #getId()}) if the
+	 * type is not a leaf type, i.e., not {@link MenuType#toggle} or
+	 * {@link MenuType#action}.
+	 * 
+	 * @return A {@link MenuType} to specify the role of this menu item.
+	 */
+	public MenuType getType();
+
+	/**
+	 * True if this menu component is to be included in the menu/toolbar.
+	 * 
+	 * @return True is this menu component is to be included
+	 */
+	public boolean isEnabled();
+
+	/**
+	 * The type of menu item, such as {@link #action}, {@link #menu} or
+	 * {@link #toolBar}.
+	 * <p>
+	 * Some types are {@linkplain #isParentType() parent types} - that means
+	 * URIs to menu components of that type can be used as a
+	 * {@linkplain MenuComponent#getParentId() parent id}.
+	 * 
+	 * @author Stian Soiland-Reyes
+	 * 
+	 */
+	public static enum MenuType {
+		/**
+		 * A normal {@link Action} as part of a {@link #menu}, {@link #toolBar},
+		 * {@link #section} or {@link #optionGroup}. Such menu items are leaf
+		 * nodes, which no {@link MenuComponent}s can have this as it's
+		 * {@link MenuComponent#getParentId()}. The action's
+		 * {@link ActionListener#actionPerformed(ActionEvent)} will be called
+		 * when choosing/clicking the menu item from the menu or toolBar.
+		 */
+		action,
+		/**
+		 * Provide a customised {@link MenuElement} from
+		 * {@link MenuComponent#getCustomComponent()} that is to be used instead
+		 * of creating an element from {@link MenuComponent#getAction()}.
+		 */
+		custom,
+		/**
+		 * A group containing mutually exclusive choices (as {@link #action}s),
+		 * to be grouped in a {@link ButtonGroup}, separated using
+		 * {@link JMenu#addSeparator()} or {@link JToolBar#addSeparator()} when
+		 * needed. The {@link MenuComponent#getAction()} is ignored and should
+		 * be <code>null</code>.
+		 */
+		optionGroup,
+		/**
+		 * A section of menu items within {@link #menu} or {@link #toolBar}.
+		 * Sections are separated using {@link JMenu#addSeparator()} or
+		 * {@link JToolBar#addSeparator()} when needed. The
+		 * {@link MenuComponent#getAction()} is ignored and should be
+		 * <code>null</code>.
+		 */
+		section,
+		/**
+		 * A (sub)menu that contain other menu items, including deeper
+		 * {@link #menu}s. The {@link Action} from
+		 * {@link MenuComponent#getAction()} is used to find the name, icon,
+		 * etc., for the sub-menu, while its
+		 * {@link ActionListener#actionPerformed(ActionEvent)} method is
+		 * ignored. The {@link DefaultMenuBar} is the default top level menu,
+		 * although others can be created with <code>null</code> as their
+		 * parent.
+		 */
+		menu,
+		/**
+		 * A boolean toggle action, the action will be shown as a
+		 * {@link JCheckBox} on a menu or toolBar. Such menu items are leaf
+		 * nodes, which no {@link MenuComponent}s can have this as it's
+		 * {@link MenuComponent#getParentId()}. The action's
+		 * {@link ActionListener#actionPerformed(ActionEvent)} will be called
+		 * when toggling the action.
+		 */
+		toggle,
+		/**
+		 * A toolBar containing {@link #optionGroup}s, {@link #toggle}s or
+		 * {@link #action}s. The toolBar can be shown as a {@link JToolBar}. The
+		 * {@link MenuComponent#getAction()} and
+		 * {@link MenuComponent#getParentId()} are ignored and should be
+		 * <code>null</code>.
+		 */
+		toolBar;
+
+		private static final Set<MenuType> parentTypes = defineParentTypes();
+
+		/**
+		 * True if the menu type is a parent type such as {@link #optionGroup},
+		 * {@link #section}, {@link #menu} or {@link #toolBar}. If the type of a
+		 * menu component is a a parent type it can (should) have children,
+		 * i.e., the children has a {@link MenuComponent#getParentId()} that
+		 * equals the parent's {@link MenuComponent#getId()}.
+		 * 
+		 * @return True if the menu type is a parent type.
+		 */
+		public boolean isParentType() {
+			return parentTypes.contains(this);
+		}
+
+		/**
+		 * Create the set of {@link MenuType}s that {@link #isParentType()}
+		 * would return <code>true</code> for.
+		 * 
+		 * @return A {@link Set} of {@link MenuType}s.
+		 */
+		private static Set<MenuType> defineParentTypes() {
+			HashSet<MenuType> types = new HashSet<>();
+			types.add(optionGroup);
+			types.add(section);
+			types.add(menu);
+			types.add(toolBar);
+			return types;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/MenuManager.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/MenuManager.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/MenuManager.java
new file mode 100644
index 0000000..7195164
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/MenuManager.java
@@ -0,0 +1,338 @@
+/*
+* 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;
+
+import java.awt.Component;
+import java.lang.ref.WeakReference;
+import java.net.URI;
+import java.util.List;
+
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.JToolBar;
+
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+import org.apache.taverna.ui.menu.MenuComponent.MenuType;
+import org.apache.taverna.ui.menu.MenuManager.MenuManagerEvent;
+
+/**
+ * Create {@link JMenuBar}s and {@link JToolBar}s based on SPI instances of
+ * {@link MenuComponent}.
+ * <p>
+ * Elements of menus are discovered automatically using an {@link SPIRegistry}.
+ * The elements specify their internal relationship through
+ * {@link MenuComponent#getParentId()} and
+ * {@link MenuComponent#getPositionHint()}. {@link MenuComponent#getType()}
+ * specifies how the component is to be rendered or grouped.
+ * <p>
+ * The menu manager is {@link Observable}, you can
+ * {@linkplain #addObserver(Observer) add an observer} to be notified when the
+ * menus have changed, i.e. when {@link #update()} has been called, for instance
+ * when the {@link SPIRegistry} (which the menu manager observes) has been
+ * updated due to a plugin installation.
+ * <p>
+ * {@link #createMenuBar()} creates the default menu bar, ie. the menu bar
+ * containing all the items with {@link DefaultMenuBar#DEFAULT_MENU_BAR} as
+ * their parent. Alternate menu bars can be created using
+ * {@link #createMenuBar(URI)}.
+ * <p>
+ * Similary {@link #createToolBar()} creates the default tool bar, containing
+ * the items that has {@link DefaultToolBar#DEFAULT_TOOL_BAR} as their parent.
+ * Alternate toolbars can be created using {@link #createToolBar(URI)}.
+ * <p>
+ * The menu manager keeps weak references to the created (published) menu bars
+ * and tool bars, and will attempt to update them when {@link #update()} is
+ * called.
+ * <p>
+ * See the package level documentation for more information about how to specify
+ * menu elements.
+ * 
+ * @author Stian Soiland-Reyes
+ */
+public interface MenuManager extends Observable<MenuManagerEvent> {
+	/**
+	 * Add the items from the list of menu items to the parent menu with
+	 * expansion sub-menus if needed.
+	 * <p>
+	 * If the list contains more than <tt>maxItemsInMenu</tt> items, a series of
+	 * sub-menus will be created and added to the parentMenu instead, each
+	 * containing a maximum of <tt>maxItemsInMenu</tt> items. (Note that if
+	 * menuItems contains more than <tt>maxItemsInMenu*maxItemsInMenu</tt>
+	 * items, there might be more than <tt>maxItemsInMenu</tt> sub-menus added
+	 * to the parent).
+	 * <p>
+	 * The sub-menus are titled according to the {@link JMenuItem#getText()} of
+	 * the first and last menu item it contains - assuming that they are already
+	 * sorted.
+	 * <p>
+	 * The optional {@link ComponentFactory} headerItemFactory, if not
+	 * <code>null</code>, will be invoked to create a header item that will be
+	 * inserted on top of the sub-menus. This item does not count towards
+	 * <tt>maxItemsInMenu</tt>.
+	 * <p>
+	 * Note that this is a utility method that does not mandate the use of the
+	 * {@link MenuManager} structure for the menu.
+	 * 
+	 * @param menuItems
+	 *            {@link JMenuItem}s to be inserted
+	 * @param parentMenu
+	 *            Menu to insert items to
+	 * @param maxItemsInMenu
+	 *            Maximum number of items in parent menu or created sub-menus
+	 * @param headerItemFactory
+	 *            If not <code>null</code>, a {@link ComponentFactory} to create
+	 *            a header item to insert at top of created sub-menus
+	 */
+	abstract void addMenuItemsWithExpansion(List<JMenuItem> menuItems,
+			JMenu parentMenu, int maxItemsInMenu,
+			ComponentFactory headerItemFactory);
+
+	/**
+	 * Create a contextual menu for a selected object.
+	 * <p>
+	 * Items for the contextual menues are discovered in a similar to fashion as
+	 * with {@link #createMenuBar()}, but using {@link DefaultContextualMenu} as
+	 * the root.
+	 * <p>
+	 * Additionally, items implementing {@link ContextualMenuComponent} will be
+	 * {@linkplain ContextualMenuComponent#setContextualSelection(Object, Object, Component)
+	 * informed} about what is the current selection, as passed to this method.
+	 * <p>
+	 * Thus, the items can choose if they want to be
+	 * {@link MenuComponent#isEnabled() visible} or not for a given selection,
+	 * and return an action that is bound it to the selection.
+	 * 
+	 * @param parent
+	 *            The parent object of the selected object, for instance a
+	 *            {@link Workflow}.
+	 * @param selection
+	 *            The selected object which actions in the contextual menu
+	 *            relate to, for instance a {@link Processor}
+	 * @param relativeToComponent
+	 *            A UI component which the returned {@link JPopupMenu} (and it's
+	 *            actions) is to be relative to, for instance as a parent of
+	 *            pop-up dialogues.
+	 * @return An empty or populated {@link JPopupMenu} depending on the
+	 *         selected objects.
+	 */
+	abstract JPopupMenu createContextMenu(Object parent, Object selection,
+			Component relativeToComponent);
+
+	/**
+	 * Create the {@link JMenuBar} containing menu elements defining
+	 * {@link DefaultMenuBar#DEFAULT_MENU_BAR} as their
+	 * {@linkplain MenuComponent#getParentId() parent}.
+	 * <p>
+	 * A {@linkplain WeakReference weak reference} is kept in the menu manager
+	 * to update the menubar if {@link #update()} is called (manually or
+	 * automatically when the SPI is updated).
+	 * 
+	 * @return A {@link JMenuBar} populated with the items belonging to the
+	 *         default menu bar
+	 */
+	abstract JMenuBar createMenuBar();
+
+	/**
+	 * Create the {@link JMenuBar} containing menu elements defining the given
+	 * <code>id</code> as their {@linkplain MenuComponent#getParentId() parent}.
+	 * <p>
+	 * Note that the parent itself also needs to exist as a registered SPI
+	 * instance og {@link MenuComponent#getType()} equal to
+	 * {@link MenuType#menu}, for instance by subclassing {@link AbstractMenu}.
+	 * <p>
+	 * A {@linkplain WeakReference weak reference} is kept in the menu manager
+	 * to update the menubar if {@link #update()} is called (manually or
+	 * automatically when the SPI is updated).
+	 * 
+	 * @param id
+	 *            The {@link URI} identifying the menu bar
+	 * @return A {@link JMenuBar} populated with the items belonging to the
+	 *         given parent id.
+	 */
+	abstract JMenuBar createMenuBar(URI id);
+
+	/**
+	 * Create the {@link JToolBar} containing elements defining
+	 * {@link DefaultToolBar#DEFAULT_TOOL_BAR} as their
+	 * {@linkplain MenuComponent#getParentId() parent}.
+	 * <p>
+	 * A {@linkplain WeakReference weak reference} is kept in the menu manager
+	 * to update the toolbar if {@link #update()} is called (manually or
+	 * automatically when the SPI is updated).
+	 * 
+	 * @return A {@link JToolBar} populated with the items belonging to the
+	 *         default tool bar
+	 */
+	abstract JToolBar createToolBar();
+
+	/**
+	 * Create the {@link JToolBar} containing menu elements defining the given
+	 * <code>id</code> as their {@linkplain MenuComponent#getParentId() parent}.
+	 * <p>
+	 * Note that the parent itself also needs to exist as a registered SPI
+	 * instance of {@link MenuComponent#getType()} equal to
+	 * {@link MenuType#toolBar}, for instance by subclassing
+	 * {@link AbstractToolBar}.
+	 * <p>
+	 * A {@linkplain WeakReference weak reference} is kept in the menu manager
+	 * to update the toolbar if {@link #update()} is called (manually or
+	 * automatically when the SPI is updated).
+	 * 
+	 * @param id
+	 *            The {@link URI} identifying the tool bar
+	 * @return A {@link JToolBar} populated with the items belonging to the
+	 *         given parent id.
+	 */
+	abstract JToolBar createToolBar(URI id);
+
+	/**
+	 * Get a menu item identified by the given URI.
+	 * <p>
+	 * Return the UI {@link Component} last created for a {@link MenuComponent},
+	 * through {@link #createMenuBar()}, {@link #createMenuBar(URI)},
+	 * {@link #createToolBar()} or {@link #createToolBar(URI)}.
+	 * <p>
+	 * For instance, if {@link #createMenuBar()} created a menu bar containing a
+	 * "File" menu with {@link MenuComponent#getId() getId()} ==
+	 * <code>http://example.com/menu#file</code>, calling:
+	 * 
+	 * <pre>
+	 * Component fileMenu = getComponentByURI(URI
+	 * 		.create(&quot;http://example.com/menu#file&quot;));
+	 * </pre>
+	 * 
+	 * would return the {@link JMenu} last created for "File". Note that "last
+	 * created" could mean both the last call to {@link #createMenuBar()} and
+	 * last call to {@link #update()} - which could have happened because the
+	 * SPI registry was updated. To be notified when
+	 * {@link #getComponentByURI(URI)} might return a new Component because the
+	 * menues have been reconstructed, {@linkplain #addObserver(Observer) add an
+	 * observer} to the MenuManager.
+	 * <p>
+	 * If the URI is unknown, has not yet been rendered as a {@link Component},
+	 * or the Component is no longer in use outside the menu manager's
+	 * {@linkplain WeakReference weak references}, <code>null</code> is returned
+	 * instead.
+	 * 
+	 * @see #getURIByComponent(Component)
+	 * @param id
+	 *            {@link URI} of menu item as returned by
+	 *            {@link MenuComponent#getId()}
+	 * @return {@link Component} as previously generated by
+	 *         {@link #createMenuBar()}/{@link #createToolBar()}, or
+	 *         <code>null</code> if the URI is unknown, or if the
+	 *         {@link Component} no longer exists.
+	 */
+	public abstract Component getComponentByURI(URI id);
+
+	/**
+	 * Get the URI of the {@link MenuComponent} this menu/toolbar
+	 * {@link Component} was created from.
+	 * <p>
+	 * If the component was created by the MenuManager, through
+	 * {@link #createMenuBar()}, {@link #createMenuBar(URI)},
+	 * {@link #createToolBar()} or {@link #createToolBar(URI)}, the URI
+	 * identifying the defining {@link MenuComponent} is returned. This will be
+	 * the same URI as returned by {@link MenuComponent#getId()}.
+	 * <p>
+	 * Note that if {@link #update()} has been invoked, the {@link MenuManager}
+	 * might have rebuilt the menu structure and replaced the components since
+	 * the given <code>component</code> was created. The newest
+	 * {@link Component} for the given URI can be retrieved using
+	 * {@link #getComponentByURI(URI)}.
+	 * <p>
+	 * If the component is unknown, <code>null</code> is returned instead.
+	 * 
+	 * @see #getComponentByURI(URI)
+	 * @param component
+	 *            {@link Component} that was previously created by the
+	 *            {@link MenuManager}
+	 * @return {@link URI} identifying the menu component, as returned by
+	 *         {@link MenuComponent#getId()}, or <code>null</code> if the
+	 *         component is unknown.
+	 */
+	abstract URI getURIByComponent(Component component);
+
+	/**
+	 * Update and rebuild the menu structure.
+	 * <p>
+	 * Rebuild menu structure as defined by the {@link MenuComponent}s retrieved
+	 * from the MenuComponent {@link SPIRegistry}.
+	 * <p>
+	 * Rebuilds previously published menubars and toolbars created with
+	 * {@link #createMenuBar()}, {@link #createMenuBar(URI)},
+	 * {@link #createToolBar()} and {@link #createToolBar(URI)}. Note that the
+	 * rebuild will do a removeAll() on the menubar/toolbar, so all components
+	 * will be reconstructed. You can use {@link #getComponentByURI(URI)} to
+	 * look up individual components within the menu and toolbars.
+	 * <p>
+	 * Note that the menu manager is observing the {@link SPIRegistry}, so if a
+	 * plugin gets installed and the SPI registry is updated, this update method
+	 * will be called by the SPI registry observer.
+	 * <p>
+	 * If there are several concurrent calls to {@link #update()}, the calls
+	 * from the other thread will return immediately, while the first thread to
+	 * get the synchronization lock on the menu manager will do the actual
+	 * update. If you want to ensure that {@link #update()} does not return
+	 * before the update has been performed fully, synchronize on the menu
+	 * manager:
+	 * 
+	 * <pre>
+	 * MenuManager menuManager = MenuManager.getInstance();
+	 * synchronized (menuManager) {
+	 * 	menuManager.update();
+	 * }
+	 * doSomethingAfterUpdateFinished();
+	 * </pre>
+	 */
+	abstract void update();
+
+	/**
+	 * Abstract class for events sent to {@linkplain Observer observers} of the
+	 * menu manager.
+	 * 
+	 * @see UpdatedMenuManagerEvent
+	 * @author Stian Soiland-Reyes
+	 */
+	static abstract class MenuManagerEvent {
+	}
+
+	/**
+	 * Event sent to observers registered by
+	 * {@link MenuManager#addObserver(Observer)} when the menus have been
+	 * updated, i.e. when {@link MenuManager#update()} has been called.
+	 */
+	static class UpdatedMenuManagerEvent extends MenuManagerEvent {
+	}
+
+	/**
+	 * A factory for making {@link Component}s, in particular for making headers
+	 * (like {@link JLabel}s) for
+	 * {@link MenuManager#addMenuItemsWithExpansion(List, JMenu, int, ComponentFactory)}
+	 */
+	interface ComponentFactory {
+		public Component makeComponent();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/package-info.java b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/package-info.java
new file mode 100644
index 0000000..f2b39a8
--- /dev/null
+++ b/taverna-menu-api/src/main/java/org/apache/taverna/ui/menu/package-info.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * 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
+ ******************************************************************************/
+/**
+ * An {@link net.sf.taverna.t2.spi.SPIRegistry SPI} based system for creating
+ * {@link javax.swing.JMenuBar menues} and {@link javax.swing.JToolBar toolbars}.
+ * <p>
+ * Each element of a menu and/or toolbar is created by making an SPI
+ * implementation class of {@link net.sf.taverna.t2.ui.menu.MenuComponent} and listing the fully qualified
+ * class name in the SPI description resource file
+ * <code>/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent</code>
+ * </p>
+ * <p>
+ * The {@link net.sf.taverna.t2.ui.menu.MenuManager} discovers all menu components using an SPI registry,
+ * and builds the {@link javax.swing.JMenuBar menu bar} using
+ * {@link net.sf.taverna.t2.ui.menu.MenuManager#createMenuBar()} or the
+ * {@link javax.swing.JToolBar toolbar} using
+ * {@link net.sf.taverna.t2.ui.menu.MenuManager#createToolBar()}.
+ * </p>
+ * <p>
+ * This allows plugins to provide actions (menu items) and submenues that can be
+ * inserted at any points in the generated menu. All parts of the menues are
+ * described through a parent/child relationship using
+ * {@link net.sf.taverna.t2.ui.menu.MenuComponent#getId()} and {@link net.sf.taverna.t2.ui.menu.MenuComponent#getParentId()}. The
+ * components are identified using {@link java.net.URI}s to avoid compile time
+ * dependencies, so a plugin can for instance add something to the existing
+ * "Edit" menu without depending on the actual implementation of the
+ * {@link net.sf.taverna.t2.ui.menu.MenuComponent} describing "Edit", as long as it refers to the same
+ * URI. The use of URIs instead of pure strings is to encourage the use of
+ * unique identifiers, for instance plugins should use an URI base that is
+ * derived from their package name to avoid collision with other plugins.
+ * </p>
+ * <p>
+ * A set of abstract classes, with a common parent {@link net.sf.taverna.t2.ui.menu.AbstractMenuItem},
+ * make it more convenient to create simple SPI implementations. Two default top
+ * level implementations {@link net.sf.taverna.t2.ui.menu.DefaultMenuBar} and {@link net.sf.taverna.t2.ui.menu.DefaultToolBar} can
+ * be used as parents for items that are to be included in
+ * {@link net.sf.taverna.t2.ui.menu.MenuManager#createMenuBar()} and {@link net.sf.taverna.t2.ui.menu.MenuManager#createToolBar()},
+ * but it's possible to have other parents - such menu trees would have to be
+ * created by providing the URI of the top level parent to
+ * {@link net.sf.taverna.t2.ui.menu.MenuManager#createMenuBar(URI)} or
+ * {@link net.sf.taverna.t2.ui.menu.MenuManager#createToolBar(URI)}.
+ * </p> 
+ * <p>
+ * In the simplest form a menu structure can be built by subclassing
+ * {@link net.sf.taverna.t2.ui.menu.AbstractMenu} and {@link net.sf.taverna.t2.ui.menu.AbstractMenuAction}, but more complex menus
+ * can be built by including submenus (AbstractMenu with an AbstractMenu as a
+ * parent), grouping similar actions in a {@link net.sf.taverna.t2.ui.menu.AbstractMenuSection section},
+ * or making {@link net.sf.taverna.t2.ui.menu.AbstractMenuToggle toggle actions} and
+ * {@link net.sf.taverna.t2.ui.menu.AbstractMenuOptionGroup option groups}. You can add arbitrary "real"
+ * {@link javax.swing.JMenuBar} / {@link javax.swing.JToolBar} compatible items
+ * (such as {@link javax.swing.JMenu}s, {@link javax.swing.JMenuItem}s and
+ * {@link javax.swing.JButton}s) using
+ * {@link net.sf.taverna.t2.ui.menu.AbstractMenuCustom custom menu items}.
+ * </p>
+ * 
+ * <p>
+ * Example showing how <code>File-&gt;Open</code> could be implemented using
+ * two SPI implementations net.sf.taverna.t2.ui.perspectives.hello.FileMenu and
+ * net.sf.taverna.t2.ui.perspectives.hello.FileOpenAction:
+ * </p>
+ * 
+ * <pre>
+ * package net.sf.taverna.t2.ui.perspectives.hello;
+ * 
+ * import java.net.URI;
+ * 
+ * import net.sf.taverna.t2.ui.menu.AbstractMenu;
+ * import net.sf.taverna.t2.ui.menu.DefaultMenuBar;
+ * 
+ * public class FileMenu extends AbstractMenu {
+ * 
+ * 	private static final URI FILE_URI = URI
+ * 			.create(&quot;http://taverna.sf.net/2008/t2workbench/test#file&quot;);
+ * 
+ * 	public FileMenu() {
+ * 		super(DefaultMenuBar.DEFAULT_MENU_BAR, 10, FILE_URI, &quot;File&quot;);
+ * 	}
+ * 
+ * }
+ * </pre>
+ * <pre>
+ * package net.sf.taverna.t2.ui.perspectives.hello;
+ * 
+ * import java.awt.event.ActionEvent;
+ * import java.net.URI;
+ * 
+ * import javax.swing.AbstractAction;
+ * import javax.swing.Action;
+ * import javax.swing.JOptionPane;
+ * 
+ * import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+ * 
+ * public class FileOpenAction extends AbstractMenuAction {
+ *     public FileOpenAction() {
+ *         super(URI.create(&quot;http://taverna.sf.net/2008/t2workbench/test#file&quot;),
+ *                 20);
+ *     }
+ * 
+ *     &#064;Override
+ *     public Action createAction() {
+ *         return new AbstractAction(&quot;Open&quot;) {
+ *             public void actionPerformed(ActionEvent arg0) {
+ *                 JOptionPane.showMessageDialog(null, &quot;Open&quot;);
+ *             }
+ *         };
+ *     }
+ * }
+ * </pre>
+ * 
+ * <p>
+ * The implementation of the {@link net.sf.taverna.t2.ui.menu.MenuManager} itself is discovered by an
+ * internal SPI registry through {@link net.sf.taverna.t2.ui.menu.MenuManager#getInstance()}. The menu
+ * manager is observing the SPI registry, so that any updates to the registry
+ * from installing plugins etc. are reflected in an automatic rebuild of the
+ * menus. This update can also be triggered manually by calling
+ * {@link net.sf.taverna.t2.ui.menu.MenuManager#update()}.
+ * </p>
+ * 
+ * @author Stian Soiland-Reyes
+ * 
+ */
+package org.apache.taverna.ui.menu;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent b/taverna-menu-api/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
deleted file mode 100644
index c137386..0000000
--- a/taverna-menu-api/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
+++ /dev/null
@@ -1,4 +0,0 @@
-net.sf.taverna.t2.ui.menu.DefaultMenuBar
-net.sf.taverna.t2.ui.menu.DefaultToolBar
-net.sf.taverna.t2.ui.menu.DefaultContextualMenu
- 

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/resources/META-INF/services/org.apache.taverna.ui.menu.MenuComponent
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/resources/META-INF/services/org.apache.taverna.ui.menu.MenuComponent b/taverna-menu-api/src/main/resources/META-INF/services/org.apache.taverna.ui.menu.MenuComponent
new file mode 100644
index 0000000..8335f7e
--- /dev/null
+++ b/taverna-menu-api/src/main/resources/META-INF/services/org.apache.taverna.ui.menu.MenuComponent
@@ -0,0 +1,4 @@
+org.apache.taverna.ui.menu.DefaultMenuBar
+org.apache.taverna.ui.menu.DefaultToolBar
+org.apache.taverna.ui.menu.DefaultContextualMenu
+ 

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-menu-api/src/main/resources/META-INF/spring/menu-api-context.xml
----------------------------------------------------------------------
diff --git a/taverna-menu-api/src/main/resources/META-INF/spring/menu-api-context.xml b/taverna-menu-api/src/main/resources/META-INF/spring/menu-api-context.xml
index 734dbbe..1e8a1eb 100644
--- a/taverna-menu-api/src/main/resources/META-INF/spring/menu-api-context.xml
+++ b/taverna-menu-api/src/main/resources/META-INF/spring/menu-api-context.xml
@@ -3,8 +3,8 @@
 	xsi:schemaLocation="http://www.springframework.org/schema/beans 
                       http://www.springframework.org/schema/beans/spring-beans.xsd">
 
-	<bean id="DefaultMenuBar" class="net.sf.taverna.t2.ui.menu.DefaultMenuBar" />
-	<bean id="DefaultToolBar" class="net.sf.taverna.t2.ui.menu.DefaultToolBar" />
-	<bean id="DefaultContextualMenu" class="net.sf.taverna.t2.ui.menu.DefaultContextualMenu" />
+	<bean id="DefaultMenuBar" class="org.apache.taverna.ui.menu.DefaultMenuBar" />
+	<bean id="DefaultToolBar" class="org.apache.taverna.ui.menu.DefaultToolBar" />
+	<bean id="DefaultContextualMenu" class="org.apache.taverna.ui.menu.DefaultContextualMenu" />
 
 </beans>