http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-httpproxy-config/src/main/java/net/sf/taverna/t2/workbench/httpproxy/config/HttpProxyConfigurationUIFactory.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-httpproxy-config/src/main/java/net/sf/taverna/t2/workbench/httpproxy/config/HttpProxyConfigurationUIFactory.java
 
b/taverna-workbench-httpproxy-config/src/main/java/net/sf/taverna/t2/workbench/httpproxy/config/HttpProxyConfigurationUIFactory.java
new file mode 100644
index 0000000..9f6ac8c
--- /dev/null
+++ 
b/taverna-workbench-httpproxy-config/src/main/java/net/sf/taverna/t2/workbench/httpproxy/config/HttpProxyConfigurationUIFactory.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ 
******************************************************************************/
+package net.sf.taverna.t2.workbench.httpproxy.config;
+
+import javax.swing.JPanel;
+
+import uk.org.taverna.configuration.Configurable;
+import uk.org.taverna.configuration.ConfigurationUIFactory;
+import uk.org.taverna.configuration.proxy.HttpProxyConfiguration;
+
+/**
+ * A Factory to create a HttpProxyConfiguration
+ *
+ * @author alanrw
+ * @author David Withers
+ */
+public class HttpProxyConfigurationUIFactory implements ConfigurationUIFactory 
{
+       private HttpProxyConfiguration httpProxyConfiguration;
+
+       @Override
+       public boolean canHandle(String uuid) {
+               return uuid.equals(getConfigurable().getUUID());
+       }
+
+       @Override
+       public JPanel getConfigurationPanel() {
+               return new HttpProxyConfigurationPanel(httpProxyConfiguration);
+       }
+
+       @Override
+       public Configurable getConfigurable() {
+               return httpProxyConfiguration;
+       }
+
+       public void setHttpProxyConfiguration(HttpProxyConfiguration 
httpProxyConfiguration) {
+               this.httpProxyConfiguration = httpProxyConfiguration;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-httpproxy-config/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.configuration.ConfigurationUIFactory
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-httpproxy-config/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.configuration.ConfigurationUIFactory
 
b/taverna-workbench-httpproxy-config/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.configuration.ConfigurationUIFactory
new file mode 100644
index 0000000..d87772b
--- /dev/null
+++ 
b/taverna-workbench-httpproxy-config/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.configuration.ConfigurationUIFactory
@@ -0,0 +1 @@
+net.sf.taverna.t2.workbench.httpproxy.config.HttpProxyConfigurationUIFactory
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-httpproxy-config/src/main/resources/META-INF/spring/httpproxy-config-context-osgi.xml
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-httpproxy-config/src/main/resources/META-INF/spring/httpproxy-config-context-osgi.xml
 
b/taverna-workbench-httpproxy-config/src/main/resources/META-INF/spring/httpproxy-config-context-osgi.xml
new file mode 100644
index 0000000..631bdb4
--- /dev/null
+++ 
b/taverna-workbench-httpproxy-config/src/main/resources/META-INF/spring/httpproxy-config-context-osgi.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns:beans="http://www.springframework.org/schema/beans";
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      
http://www.springframework.org/schema/beans/spring-beans.xsd
+                      http://www.springframework.org/schema/osgi
+                      
http://www.springframework.org/schema/osgi/spring-osgi.xsd";>
+
+       <service ref="HttpProxyConfigurationUIFactory" 
interface="uk.org.taverna.configuration.ConfigurationUIFactory" />
+
+       <reference id="httpProxyConfiguration" 
interface="uk.org.taverna.configuration.proxy.HttpProxyConfiguration" />
+
+</beans:beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-httpproxy-config/src/main/resources/META-INF/spring/httpproxy-config-context.xml
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-httpproxy-config/src/main/resources/META-INF/spring/httpproxy-config-context.xml
 
b/taverna-workbench-httpproxy-config/src/main/resources/META-INF/spring/httpproxy-config-context.xml
new file mode 100644
index 0000000..6d6060f
--- /dev/null
+++ 
b/taverna-workbench-httpproxy-config/src/main/resources/META-INF/spring/httpproxy-config-context.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      
http://www.springframework.org/schema/beans/spring-beans.xsd";>
+
+       <bean id="HttpProxyConfigurationUIFactory" 
class="net.sf.taverna.t2.workbench.httpproxy.config.HttpProxyConfigurationUIFactory">
+               <property name="httpProxyConfiguration" 
ref="httpProxyConfiguration" />
+       </bean>
+
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-menu-impl/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-menu-impl/pom.xml 
b/taverna-workbench-menu-impl/pom.xml
new file mode 100644
index 0000000..d95bf49
--- /dev/null
+++ b/taverna-workbench-menu-impl/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>net.sf.taverna.t2</groupId>
+               <artifactId>ui-impl</artifactId>
+               <version>2.0-SNAPSHOT</version>
+       </parent>
+       <groupId>net.sf.taverna.t2.ui-impl</groupId>
+       <artifactId>menu-impl</artifactId>
+       <packaging>bundle</packaging>
+       <name>Menu generation implementation</name>
+       <description>The main workbench ui</description>
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.felix</groupId>
+                               <artifactId>maven-bundle-plugin</artifactId>
+                               <configuration>
+                                       <instructions>
+                                               
<Embed-Dependency>javahelp</Embed-Dependency>
+                                               
<Import-Package>org.jdesktop.jdic.browser;resolution:=optional,*</Import-Package>
+                                       </instructions>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+       <dependencies>
+               <dependency>
+                       <groupId>net.sf.taverna.t2.ui-api</groupId>
+                       <artifactId>workbench-api</artifactId>
+                       <version>${t2.ui.api.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>net.sf.taverna.t2.ui-api</groupId>
+                       <artifactId>menu-api</artifactId>
+                       <version>${t2.ui.api.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>net.sf.taverna.t2.ui-api</groupId>
+                       <artifactId>helper-api</artifactId>
+                       <version>${t2.ui.api.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>net.sf.taverna.t2.lang</groupId>
+                       <artifactId>ui</artifactId>
+                       <version>${t2.lang.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>uk.org.taverna.configuration</groupId>
+                       <artifactId>taverna-app-configuration-api</artifactId>
+                       <version>${taverna.configuration.version}</version>
+               </dependency>
+
+               <dependency>
+                       <groupId>javax.help</groupId>
+                       <artifactId>javahelp</artifactId>
+               </dependency>
+
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <scope>test</scope>
+               </dependency>
+       </dependencies>
+</project>

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

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

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

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

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

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

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

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

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

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-menu-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuManager
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-menu-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuManager
 
b/taverna-workbench-menu-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuManager
new file mode 100644
index 0000000..3b06fd9
--- /dev/null
+++ 
b/taverna-workbench-menu-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuManager
@@ -0,0 +1 @@
+net.sf.taverna.t2.ui.menu.impl.MenuManagerImpl
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-menu-impl/src/main/resources/META-INF/spring/menu-impl-context-osgi.xml
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-menu-impl/src/main/resources/META-INF/spring/menu-impl-context-osgi.xml
 
b/taverna-workbench-menu-impl/src/main/resources/META-INF/spring/menu-impl-context-osgi.xml
new file mode 100644
index 0000000..3a1eadf
--- /dev/null
+++ 
b/taverna-workbench-menu-impl/src/main/resources/META-INF/spring/menu-impl-context-osgi.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns:beans="http://www.springframework.org/schema/beans";
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      
http://www.springframework.org/schema/beans/spring-beans.xsd
+                      http://www.springframework.org/schema/osgi
+                      
http://www.springframework.org/schema/osgi/spring-osgi.xsd";>
+
+       <service ref="MenuManagerImpl" 
interface="net.sf.taverna.t2.ui.menu.MenuManager" />
+
+       <service ref="FileMenu" auto-export="interfaces" />
+       <service ref="EditMenu" auto-export="interfaces" />
+       <service ref="AdvancedMenu" auto-export="interfaces" />
+       <service ref="HelpMenu" auto-export="interfaces" />
+       <service ref="OnlineHelpMenuAction" auto-export="interfaces" />
+       <service ref="FeedbackMenuAction" auto-export="interfaces" />
+       <service ref="ShowLogsAndDataMenuAction" auto-export="interfaces" />
+
+       <reference id="applicationConfiguration" 
interface="uk.org.taverna.configuration.app.ApplicationConfiguration" />
+       <reference id="selectionManager" 
interface="net.sf.taverna.t2.workbench.selection.SelectionManager" />
+
+       <list id="menuComponents" 
interface="net.sf.taverna.t2.ui.menu.MenuComponent" cardinality="0..N" 
greedy-proxying="true">
+               <listener ref="MenuManagerImpl" bind-method="update" 
unbind-method="update" />
+       </list>
+
+</beans:beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-menu-impl/src/main/resources/META-INF/spring/menu-impl-context.xml
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-menu-impl/src/main/resources/META-INF/spring/menu-impl-context.xml
 
b/taverna-workbench-menu-impl/src/main/resources/META-INF/spring/menu-impl-context.xml
new file mode 100644
index 0000000..62fd24e
--- /dev/null
+++ 
b/taverna-workbench-menu-impl/src/main/resources/META-INF/spring/menu-impl-context.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans";
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      
http://www.springframework.org/schema/beans/spring-beans.xsd";>
+
+       <bean id="MenuManagerImpl" 
class="net.sf.taverna.t2.ui.menu.impl.MenuManagerImpl">
+               <property name="menuComponents" ref="menuComponents" />
+               <property name="selectionManager" ref="selectionManager" />
+       </bean>
+
+       <bean id="FileMenu" 
class="net.sf.taverna.t2.workbench.ui.impl.menu.FileMenu" />
+       <bean id="EditMenu" 
class="net.sf.taverna.t2.workbench.ui.impl.menu.EditMenu" />
+       <bean id="AdvancedMenu" 
class="net.sf.taverna.t2.workbench.ui.impl.menu.AdvancedMenu" />
+       <bean id="HelpMenu" 
class="net.sf.taverna.t2.workbench.ui.impl.menu.HelpMenu" />
+       <bean id="OnlineHelpMenuAction"
+               
class="net.sf.taverna.t2.workbench.ui.impl.menu.OnlineHelpMenuAction" />
+       <bean id="FeedbackMenuAction"
+               
class="net.sf.taverna.t2.workbench.ui.impl.menu.FeedbackMenuAction" />
+       <bean id="ShowLogsAndDataMenuAction"
+               
class="net.sf.taverna.t2.workbench.ui.impl.menu.ShowLogsAndDataMenuAction">
+               <property name="applicationConfiguration" 
ref="applicationConfiguration" />
+       </bean>
+
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-plugin-manager/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-plugin-manager/pom.xml 
b/taverna-workbench-plugin-manager/pom.xml
new file mode 100644
index 0000000..4e9f0c1
--- /dev/null
+++ b/taverna-workbench-plugin-manager/pom.xml
@@ -0,0 +1,49 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>net.sf.taverna.t2</groupId>
+               <artifactId>ui-impl</artifactId>
+               <version>2.0-SNAPSHOT</version>
+       </parent>
+       <groupId>net.sf.taverna.t2.ui-impl</groupId>
+       <artifactId>plugin-manager</artifactId>
+       <packaging>bundle</packaging>
+       <name>Taverna Workbench Plugin Manager</name>
+       <dependencies>
+               <dependency>
+                       <groupId>net.sf.taverna.t2.ui-api</groupId>
+                       <artifactId>menu-api</artifactId>
+                       <version>${t2.ui.api.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>net.sf.taverna.t2.ui-api</groupId>
+                       <artifactId>workbench-api</artifactId>
+                       <version>${t2.ui.api.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>uk.org.taverna.commons</groupId>
+                       <artifactId>taverna-plugin-api</artifactId>
+                       <version> ${taverna.commons.version}</version>
+               </dependency>
+
+               <dependency>
+                       <groupId>org.osgi</groupId>
+                       <artifactId>org.osgi.compendium</artifactId>
+                       <version>${osgi.core.version}</version>
+               </dependency>
+
+               <!-- <dependency>
+                       <groupId>uk.org.taverna.commons</groupId>
+                       <artifactId>taverna-download-impl</artifactId>
+                       <version>0.1.0-SNAPSHOT</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>uk.org.taverna.commons</groupId>
+                       <artifactId>taverna-plugin-impl</artifactId>
+                       <version>0.1.0-SNAPSHOT</version>
+                       <scope>test</scope>
+               </dependency> -->
+       </dependencies>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/AvailablePluginPanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/AvailablePluginPanel.java
 
b/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/AvailablePluginPanel.java
new file mode 100644
index 0000000..f189f91
--- /dev/null
+++ 
b/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/AvailablePluginPanel.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (C) 2013 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ 
******************************************************************************/
+package net.sf.taverna.t2.workbench.plugin.impl;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import uk.org.taverna.commons.plugin.PluginException;
+import uk.org.taverna.commons.plugin.PluginManager;
+import uk.org.taverna.commons.plugin.xml.jaxb.PluginVersions;
+
+/**
+ * @author David Withers
+ */
+@SuppressWarnings("serial")
+public class AvailablePluginPanel extends PluginPanel {
+       private final PluginManager pluginManager;
+       private final PluginVersions pluginVersions;
+
+       public AvailablePluginPanel(PluginVersions pluginVersions,
+                       PluginManager pluginManager) {
+               super(pluginVersions.getName(), 
pluginVersions.getOrganization(),
+                               pluginVersions.getLatestVersion().getVersion(), 
pluginVersions
+                                               .getDescription());
+               this.pluginVersions = pluginVersions;
+               this.pluginManager = pluginManager;
+       }
+
+       @Override
+       public Action getPluginAction() {
+               return new PluginAction();
+       }
+
+       class PluginAction extends AbstractAction {
+               public PluginAction() {
+                       putValue(NAME, "Install");
+               }
+
+               @Override
+               public void actionPerformed(ActionEvent e) {
+                       setEnabled(false);
+                       putValue(NAME, "Installing");
+                       try {
+                               
pluginManager.installPlugin(pluginVersions.getPluginSiteUrl(),
+                                               
pluginVersions.getLatestVersion().getFile()).start();
+                       } catch (PluginException ex) {
+                               ex.printStackTrace();
+                       }
+                       putValue(NAME, "Installed");
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/InstalledPluginPanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/InstalledPluginPanel.java
 
b/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/InstalledPluginPanel.java
new file mode 100644
index 0000000..a08cf14
--- /dev/null
+++ 
b/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/InstalledPluginPanel.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (C) 2013 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ 
******************************************************************************/
+package net.sf.taverna.t2.workbench.plugin.impl;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import uk.org.taverna.commons.plugin.Plugin;
+import uk.org.taverna.commons.plugin.PluginException;
+
+/**
+ * @author David Withers
+ */
+@SuppressWarnings("serial")
+public class InstalledPluginPanel extends PluginPanel {
+       private final Plugin plugin;
+
+       public InstalledPluginPanel(Plugin plugin) {
+               super(plugin.getName(), plugin.getOrganization(), 
plugin.getVersion()
+                               .toString(), plugin.getDescription());
+               this.plugin = plugin;
+       }
+
+       @Override
+       public Action getPluginAction() {
+               return new PluginAction();
+       }
+
+       class PluginAction extends AbstractAction {
+               public PluginAction() {
+                       putValue(NAME, "Uninstall");
+               }
+
+               @Override
+               public void actionPerformed(ActionEvent e) {
+                       setEnabled(false);
+                       putValue(NAME, "Uninstalling");
+                       try {
+                               plugin.uninstall();
+                       } catch (PluginException ex) {
+                               ex.printStackTrace();
+                       }
+                       putValue(NAME, "Uninstalled");
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/PluginManagerPanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/PluginManagerPanel.java
 
b/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/PluginManagerPanel.java
new file mode 100644
index 0000000..dfef2fe
--- /dev/null
+++ 
b/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/PluginManagerPanel.java
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * Copyright (C) 2013 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ 
******************************************************************************/
+package net.sf.taverna.t2.workbench.plugin.impl;
+
+import static java.awt.GridBagConstraints.BOTH;
+import static java.awt.GridBagConstraints.EAST;
+import static java.awt.GridBagConstraints.NONE;
+import static java.awt.GridBagConstraints.WEST;
+import static java.lang.Math.max;
+import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER;
+import static javax.swing.SwingConstants.CENTER;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.LayoutManager;
+import java.util.List;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.commons.plugin.Plugin;
+import uk.org.taverna.commons.plugin.PluginException;
+import uk.org.taverna.commons.plugin.PluginManager;
+import uk.org.taverna.commons.plugin.xml.jaxb.PluginVersions;
+
+/**
+ * @author David Withers
+ */
+@SuppressWarnings("serial")
+public class PluginManagerPanel extends JPanel {
+       private static final Logger logger = Logger
+                       .getLogger(PluginManagerPanel.class);
+
+       private PluginManager pluginManager;
+       private JLabel message = new JLabel("");
+
+       public PluginManagerPanel(PluginManager pluginManager) {
+               this.pluginManager = pluginManager;
+               initialize();
+       }
+
+       public void initialize() {
+               removeAll();
+               setLayout(new GridBagLayout());
+
+               GridBagConstraints gbc = new GridBagConstraints();
+               gbc.anchor = WEST;
+               gbc.gridy = 0;
+               gbc.insets.left = 5;
+               gbc.insets.right = 5;
+               gbc.insets.top = 5;
+
+               JTabbedPane tabbedPane = new JTabbedPane();
+               tabbedPane.addTab("Available", createAvailablePluginsPanel());
+               tabbedPane.addTab("Installed", createInstalledPluginsPanel());
+               tabbedPane.addTab("Updates", createUpdatePluginsPanel());
+
+               gbc.weightx = 1;
+               gbc.weighty = 1;
+               gbc.gridy = 1;
+               gbc.fill = BOTH;
+               add(tabbedPane, gbc);
+
+               gbc.anchor = EAST;
+               gbc.fill = NONE;
+               gbc.weightx = 0;
+               gbc.weighty = 0;
+               gbc.gridy = 2;
+               gbc.insets.bottom = 5;
+               add(message, gbc);
+       }
+
+       public void checkForUpdates() {
+               message.setText("Checking for updates");
+               try {
+                       pluginManager.checkForUpdates();
+               } catch (PluginException e) {
+                       logger.info("Error checking for plugin updates", e);
+               } finally {
+                       message.setText("");
+               }
+       }
+
+       private static Component scrolled(Component view) {
+               JScrollPane scrollPane = new JScrollPane(view);
+               
scrollPane.setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_NEVER);
+               scrollPane.setBorder(null);
+               return scrollPane;
+       }
+
+       private Component createAvailablePluginsPanel() {
+               try {
+                       List<PluginVersions> availablePlugins = pluginManager
+                                       .getAvailablePlugins();
+                       if (availablePlugins.size() == 0)
+                               return new JLabel("No new plugins available", 
CENTER);
+
+                       JPanel panel = new JPanel(new ListLayout());
+                       for (PluginVersions plugin : availablePlugins)
+                               panel.add(new AvailablePluginPanel(plugin, 
pluginManager));
+                       return scrolled(panel);
+               } catch (PluginException e) {
+                       logger.info("Error looking for new plugins", e);
+                       return new JLabel("No new plugins available", CENTER);
+               }
+       }
+
+       private Component createInstalledPluginsPanel() {
+               try {
+                       List<Plugin> installedPlugins = 
pluginManager.getInstalledPlugins();
+                       if (installedPlugins.size() == 0)
+                               return new JLabel("No installed plugins", 
CENTER);
+
+                       JPanel panel = new JPanel(new ListLayout());
+                       for (Plugin plugin : installedPlugins)
+                               panel.add(new InstalledPluginPanel(plugin));
+                       return scrolled(panel);
+               } catch (PluginException e) {
+                       return new JLabel("No installed plugins", CENTER);
+               }
+       }
+
+       private Component createUpdatePluginsPanel() {
+               try {
+                       List<PluginVersions> pluginUpdates = pluginManager
+                                       .getPluginUpdates();
+                       if (pluginUpdates.size() == 0)
+                               return new JLabel("All plugins are up to date", 
CENTER);
+
+                       JPanel panel = new JPanel(new ListLayout());
+                       for (PluginVersions plugin : pluginUpdates)
+                               panel.add(new UpdatePluginPanel(plugin, 
pluginManager));
+                       return scrolled(panel);
+               } catch (PluginException e) {
+                       return new JLabel("All plugins are up to date", CENTER);
+               }
+       }
+
+       private final class ListLayout implements LayoutManager {
+               @Override
+               public void addLayoutComponent(String name, Component comp) {
+               }
+
+               @Override
+               public void removeLayoutComponent(Component comp) {
+               }
+
+               @Override
+               public Dimension preferredLayoutSize(Container parent) {
+                       Dimension preferredLayoutSize = new Dimension(0, 1);
+                       for (Component component : parent.getComponents()) {
+                               Dimension preferredSize = 
component.getPreferredSize();
+                               preferredLayoutSize.width = 
max(preferredSize.width,
+                                               preferredLayoutSize.width);
+                               preferredLayoutSize.height = 
preferredSize.height
+                                               + preferredLayoutSize.height - 
1;
+                       }
+                       return preferredLayoutSize;
+               }
+
+               @Override
+               public Dimension minimumLayoutSize(Container parent) {
+                       Dimension minimumLayoutSize = new Dimension(0, 1);
+                       for (Component component : parent.getComponents()) {
+                               Dimension minimumSize = 
component.getMinimumSize();
+                               minimumLayoutSize.width = max(minimumSize.width,
+                                               minimumLayoutSize.width);
+                               minimumLayoutSize.height = minimumSize.height
+                                               + minimumLayoutSize.height - 1;
+                       }
+                       return minimumLayoutSize;
+               }
+
+               @Override
+               public void layoutContainer(Container parent) {
+                       int y = 0;
+                       for (Component component : parent.getComponents()) {
+                               component.setLocation(0, y);
+                               component.setSize(parent.getSize().width,
+                                               
component.getPreferredSize().height);
+                               y += component.getHeight() - 1;
+                       }
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/PluginManagerView.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/PluginManagerView.java
 
b/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/PluginManagerView.java
new file mode 100644
index 0000000..27822a6
--- /dev/null
+++ 
b/taverna-workbench-plugin-manager/src/main/java/net/sf/taverna/t2/workbench/plugin/impl/PluginManagerView.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (C) 2013 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ 
******************************************************************************/
+package net.sf.taverna.t2.workbench.plugin.impl;
+
+import static net.sf.taverna.t2.workbench.MainWindow.getMainWindow;
+
+import javax.swing.JDialog;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+import uk.org.taverna.commons.plugin.PluginManager;
+
+/**
+ * @author David Withers
+ */
+public class PluginManagerView implements EventHandler {
+       private JDialog dialog;
+       private PluginManagerPanel pluginManagerPanel;
+       private PluginManager pluginManager;
+
+       public void showDialog() {
+               getDialog().setVisible(true);
+               getPluginManagerPanel().checkForUpdates();
+       }
+
+       private JDialog getDialog() {
+               if (dialog == null) {
+                       dialog = new JDialog(getMainWindow(), "Plugin Manager");
+                       dialog.add(getPluginManagerPanel());
+                       dialog.setSize(700, 500);
+                       dialog.setLocationRelativeTo(dialog.getOwner());
+                       dialog.setVisible(true);
+               }
+               return dialog;
+       }
+
+       private PluginManagerPanel getPluginManagerPanel() {
+               if (pluginManagerPanel == null)
+                       pluginManagerPanel = new 
PluginManagerPanel(pluginManager);
+               return pluginManagerPanel;
+       }
+
+       @Override
+       public void handleEvent(Event event) {
+               pluginManagerPanel.initialize();
+               pluginManagerPanel.revalidate();
+       }
+
+       public void setPluginManager(PluginManager pluginManager) {
+               this.pluginManager = pluginManager;
+       }
+}

Reply via email to