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("http://example.com/menu#file"));
+ * </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->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("http://taverna.sf.net/2008/t2workbench/test#file");
+ *
+ * public FileMenu() {
+ * super(DefaultMenuBar.DEFAULT_MENU_BAR, 10, FILE_URI, "File");
+ * }
+ *
+ * }
+ * </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("http://taverna.sf.net/2008/t2workbench/test#file"),
+ * 20);
+ * }
+ *
+ * @Override
+ * public Action createAction() {
+ * return new AbstractAction("Open") {
+ * public void actionPerformed(ActionEvent arg0) {
+ * JOptionPane.showMessageDialog(null, "Open");
+ * }
+ * };
+ * }
+ * }
+ * </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>