http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentDeleteMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentDeleteMenuAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentDeleteMenuAction.java
new file mode 100644
index 0000000..99c75f9
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentDeleteMenuAction.java
@@ -0,0 +1,67 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import io.github.taverna_extras.component.ui.util.Utils;
+import org.apache.taverna.workbench.file.FileManager;
+
+/**
+ * @author alanrw
+ */
+public class ComponentDeleteMenuAction extends AbstractComponentMenuAction {
+       private static final URI DELETE_COMPONENT_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#componentDelete";);
+
+       private FileManager fm;
+       private ComponentServiceIcon icon;
+       private ComponentPreference prefs;
+       private Utils utils;
+
+       public ComponentDeleteMenuAction() {
+               super(1200, DELETE_COMPONENT_URI);
+       }
+
+       public void setFileManager(FileManager fm) {
+               this.fm = fm;
+       }
+       
+       public void setIcon(ComponentServiceIcon icon) {
+               this.icon = icon;
+       }
+
+       public void setPreferences(ComponentPreference prefs) {
+               this.prefs = prefs;
+       }
+
+       public void setUtils(Utils utils) {
+               this.utils = utils;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new ComponentDeleteAction(fm, prefs, icon, utils);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMenuAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMenuAction.java
new file mode 100644
index 0000000..1176e6d
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMenuAction.java
@@ -0,0 +1,56 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import static 
io.github.taverna_extras.component.ui.menu.component.ComponentMenuSection.COMPONENT_SECTION;
+
+import java.net.URI;
+
+import javax.swing.Action;
+import org.apache.taverna.ui.menu.AbstractMenuAction;
+
+/**
+ * Basis for all menu actions. Intended to be configured by Spring.
+ * 
+ * @author Donal Fellows
+ */
+public class ComponentMenuAction extends AbstractMenuAction {
+       /**
+        * Construct a menu action to appear within the "Components" menu.
+        * @param positionHint
+        *            Where on the menu this should come.
+        * @param id
+        *            How this should be identified to Taverna.
+        */
+       public ComponentMenuAction(int positionHint, String id) {
+               super(COMPONENT_SECTION, positionHint, URI.create(id));
+       }
+
+       private Action action;
+
+       public void setAction(Action action) {
+               this.action = action;
+       }
+
+       @Override
+       protected Action createAction() {
+               return action;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMenuSection.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMenuSection.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMenuSection.java
new file mode 100644
index 0000000..07e037d
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMenuSection.java
@@ -0,0 +1,37 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import static 
io.github.taverna_extras.component.ui.menu.ComponentMenu.COMPONENT;
+
+import java.net.URI;
+import org.apache.taverna.ui.menu.AbstractMenuSection;
+
+/**
+ * @author alanrw
+ */
+public class ComponentMenuSection extends AbstractMenuSection {
+       public static final URI COMPONENT_SECTION = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#componentSection";);
+
+       public ComponentMenuSection() {
+               super(COMPONENT, 400, COMPONENT_SECTION);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMergeAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMergeAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMergeAction.java
new file mode 100644
index 0000000..a350b16
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMergeAction.java
@@ -0,0 +1,135 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import static java.awt.GridBagConstraints.BOTH;
+import static java.awt.GridBagConstraints.WEST;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
+import static javax.swing.JOptionPane.OK_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JPanel;
+import javax.swing.border.TitledBorder;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.Component;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.ui.panel.ComponentChoiceMessage;
+import io.github.taverna_extras.component.ui.panel.ComponentChooserPanel;
+import io.github.taverna_extras.component.ui.panel.ProfileChoiceMessage;
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+
+/**
+ * @author alanrw
+ */
+public class ComponentMergeAction extends AbstractAction {
+       private static final long serialVersionUID = 6791184757725253807L;
+       private static final Logger logger = 
getLogger(ComponentMergeAction.class);
+       private static final String MERGE_COMPONENT = "Merge component...";
+
+       private final ComponentPreference prefs;
+
+       public ComponentMergeAction(ComponentPreference prefs,
+                       ComponentServiceIcon icon) {
+               super(MERGE_COMPONENT, icon.getIcon());
+               this.prefs = prefs;
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent arg0) {
+               JPanel overallPanel = new JPanel();
+               overallPanel.setLayout(new GridBagLayout());
+
+               GridBagConstraints gbc = new GridBagConstraints();
+
+               ComponentChooserPanel source = new ComponentChooserPanel(prefs);
+               source.setBorder(new TitledBorder("Source component"));
+
+               gbc.insets = new Insets(0, 5, 0, 5);
+               gbc.gridx = 0;
+               gbc.gridy = 0;
+               gbc.anchor = WEST;
+               gbc.fill = BOTH;
+               gbc.gridwidth = 2;
+               gbc.weightx = 1;
+               overallPanel.add(source, gbc);
+
+               final ComponentChooserPanel target = new 
ComponentChooserPanel(prefs);
+               target.setBorder(new TitledBorder("Target component"));
+               gbc.gridy++;
+               overallPanel.add(target, gbc);
+
+               source.addObserver(new Observer<ComponentChoiceMessage>() {
+                       @Override
+                       public void notify(Observable<ComponentChoiceMessage> 
sender,
+                                       ComponentChoiceMessage message) throws 
Exception {
+                               target.notify(null, new 
ProfileChoiceMessage(message
+                                               
.getComponentFamily().getComponentProfile()));
+                       }
+               });
+
+               int answer = showConfirmDialog(null, overallPanel, "Merge 
Component",
+                               OK_CANCEL_OPTION);
+               if (answer == OK_OPTION)
+                       doMerge(source.getChosenComponent(), 
target.getChosenComponent());
+       }
+
+       private void doMerge(Component sourceComponent, Component 
targetComponent) {
+               if (sourceComponent == null) {
+                       showMessageDialog(null, "Unable to determine source 
component",
+                                       "Component Merge Problem", 
ERROR_MESSAGE);
+                       return;
+               } else if (targetComponent == null) {
+                       showMessageDialog(null, "Unable to determine target 
component",
+                                       "Component Merge Problem", 
ERROR_MESSAGE);
+                       return;
+               } else if (sourceComponent.equals(targetComponent)) {
+                       showMessageDialog(null, "Cannot merge a component with 
itself",
+                                       "Component Merge Problem", 
ERROR_MESSAGE);
+                       return;
+               }
+
+               try {
+                       Version sourceVersion = 
sourceComponent.getComponentVersionMap()
+                                       
.get(sourceComponent.getComponentVersionMap().lastKey());
+                       targetComponent.addVersionBasedOn(
+                                       sourceVersion.getImplementation(), 
"Merge from "
+                                                       + 
sourceComponent.getFamily().getName() + ":"
+                                                       + 
sourceComponent.getName());
+               } catch (ComponentException e) {
+                       logger.error("failed to merge component", e);
+                       showMessageDialog(null, "Failed to merge component: " + 
e,
+                                       "Component Merge Problem", 
ERROR_MESSAGE);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMergeMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMergeMenuAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMergeMenuAction.java
new file mode 100644
index 0000000..1bcac6a
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentMergeMenuAction.java
@@ -0,0 +1,55 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+
+/**
+ * @author alanrw
+ */
+public class ComponentMergeMenuAction extends AbstractComponentMenuAction {
+       private static final URI MERGE_COMPONENT_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#componentMerge";);
+
+       private ComponentServiceIcon icon;
+       private ComponentPreference prefs;
+
+       public ComponentMergeMenuAction() {
+               super(900, MERGE_COMPONENT_URI);
+       }
+
+       public void setIcon(ComponentServiceIcon icon) {
+               this.icon = icon;
+       }
+
+       public void setPreferences(ComponentPreference prefs) {
+               this.prefs = prefs;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new ComponentMergeAction(prefs, icon);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSaveAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSaveAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSaveAction.java
new file mode 100644
index 0000000..0226432
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSaveAction.java
@@ -0,0 +1,69 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import org.apache.log4j.Logger;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import io.github.taverna_extras.component.ui.util.Utils;
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.file.events.FileManagerEvent;
+
+/**
+ * @author alanrw
+ */
+public class ComponentSaveAction extends AbstractAction implements
+               Observer<FileManagerEvent> {
+       private static final long serialVersionUID = -2391891750558659714L;
+       @SuppressWarnings("unused")
+       private static Logger logger = getLogger(ComponentSaveAction.class);
+       private static final String SAVE_COMPONENT = "Save component";
+
+       private Utils utils;
+       private Action saveWorkflowAction;
+
+       public ComponentSaveAction(Action saveAction, FileManager fm,
+                       ComponentServiceIcon icon, Utils utils) {
+               super(SAVE_COMPONENT, icon.getIcon());
+               saveWorkflowAction = saveAction;
+               this.utils = utils;
+               fm.addObserver(this);
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               saveWorkflowAction.actionPerformed(e);
+       }
+
+       @Override
+       public void notify(Observable<FileManagerEvent> sender,
+                       FileManagerEvent message) throws Exception {
+               setEnabled(saveWorkflowAction.isEnabled()
+                               && utils.currentDataflowIsComponent());
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSaveMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSaveMenuAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSaveMenuAction.java
new file mode 100644
index 0000000..cd0418d
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSaveMenuAction.java
@@ -0,0 +1,67 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import io.github.taverna_extras.component.ui.util.Utils;
+import org.apache.taverna.workbench.file.FileManager;
+
+/**
+ * @author alanrw
+ */
+public class ComponentSaveMenuAction extends AbstractComponentMenuAction {
+       private static final URI SAVE_COMPONENT_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#componentSave";);
+
+       private Action action;
+       private FileManager fm;
+       private ComponentServiceIcon icon;
+       private Utils utils;
+
+       public ComponentSaveMenuAction() {
+               super(1100, SAVE_COMPONENT_URI);
+       }
+
+       //FIXME beaninject 
net.sf.taverna.t2.workbench.file.impl.actions.SaveWorkflowAction
+       public void setSaveWorkflowAction(Action action) {
+               this.action = action;
+       }
+
+       public void setFileManager(FileManager fm) {
+               this.fm = fm;
+       }
+
+       public void setIcon(ComponentServiceIcon icon) {
+               this.icon = icon;
+       }
+
+       public void setUtils(Utils utils) {
+               this.utils = utils;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new ComponentSaveAction(action, fm, icon, utils);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSearchAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSearchAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSearchAction.java
new file mode 100644
index 0000000..56e7395
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSearchAction.java
@@ -0,0 +1,169 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import static java.awt.GridBagConstraints.BOTH;
+import static java.awt.GridBagConstraints.WEST;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
+import static javax.swing.JOptionPane.OK_OPTION;
+import static javax.swing.JOptionPane.QUESTION_MESSAGE;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static javax.swing.JOptionPane.showOptionDialog;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.util.Map.Entry;
+import java.util.SortedMap;
+
+import javax.swing.AbstractAction;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.ComponentFactory;
+import io.github.taverna_extras.component.api.Registry;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.api.profile.Profile;
+import io.github.taverna_extras.component.ui.panel.PrefixPanel;
+import io.github.taverna_extras.component.ui.panel.ProfileChooserPanel;
+import io.github.taverna_extras.component.ui.panel.RegistryChooserPanel;
+import io.github.taverna_extras.component.ui.panel.SearchChoicePanel;
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceDesc;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import org.apache.taverna.services.ServiceRegistry;
+import org.apache.taverna.ui.menu.MenuManager;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.selection.SelectionManager;
+import org.apache.taverna.workbench.ui.workflowview.WorkflowView;
+
+/**
+ * @author alanrw
+ */
+public class ComponentSearchAction extends AbstractAction {
+       private static final String WFDESC_PREFIX = "wfdesc";
+       private static final long serialVersionUID = -7780471499146286881L;
+       @SuppressWarnings("unused")
+       private static final Logger logger = 
getLogger(ComponentSearchAction.class);
+       private static final String SEARCH_FOR_COMPONENTS = "Search for 
components...";
+
+       private final ComponentPreference prefs;
+       private final ComponentFactory factory;
+       private final EditManager em;
+       private final MenuManager mm;
+       private final SelectionManager sm;
+       private final ServiceRegistry sr;
+       private final ComponentServiceIcon icon;
+
+       public ComponentSearchAction(ComponentPreference prefs,
+                       ComponentFactory factory, EditManager em, MenuManager 
mm,
+                       SelectionManager sm, ServiceRegistry sr, 
ComponentServiceIcon icon) {
+               super(SEARCH_FOR_COMPONENTS, icon.getIcon());
+               this.prefs = prefs;
+               this.factory = factory;
+               this.em = em;
+               this.mm = mm;
+               this.sm = sm;
+               this.sr = sr;
+               this.icon = icon;
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               JPanel overallPanel = new JPanel(new GridBagLayout());
+               GridBagConstraints gbc = new GridBagConstraints();
+
+               RegistryChooserPanel registryPanel = new 
RegistryChooserPanel(prefs);
+
+               gbc.insets.left = 5;
+               gbc.insets.right = 5;
+               gbc.gridx = 0;
+               gbc.anchor = WEST;
+               gbc.fill = BOTH;
+               gbc.gridwidth = 2;
+               gbc.weightx = 1;
+               gbc.gridy++;
+               overallPanel.add(registryPanel, gbc);
+
+               ProfileChooserPanel profilePanel = new 
ProfileChooserPanel(registryPanel);
+               gbc.gridx = 0;
+               gbc.gridy++;
+               overallPanel.add(profilePanel, gbc);
+
+               PrefixPanel prefixPanel = new PrefixPanel(profilePanel);
+               gbc.gridx = 0;
+               gbc.gridy++;
+               overallPanel.add(prefixPanel, gbc);
+
+               JTextArea queryPane = new JTextArea(20, 80);
+               gbc.gridx = 0;
+               gbc.weighty = 1;
+               gbc.gridy++;
+               overallPanel.add(new JScrollPane(queryPane), gbc);
+
+               int answer = showConfirmDialog(null, overallPanel,
+                               "Search for components", OK_CANCEL_OPTION);
+               if (answer == OK_OPTION)
+                       doSearch(registryPanel.getChosenRegistry(),
+                                       profilePanel.getChosenProfile(),
+                                       prefixPanel.getPrefixMap(), 
queryPane.getText());
+       }
+
+       private void doSearch(Registry chosenRegistry, Profile chosenProfile,
+                       SortedMap<String, String> prefixMap, String 
queryString) {
+               if (chosenRegistry == null) {
+                       showMessageDialog(null, "Unable to determine registry",
+                                       "Component Registry Problem", 
ERROR_MESSAGE);
+                       return;
+               }
+               if (chosenProfile == null) {
+                       showMessageDialog(null, "Unable to determine profile",
+                                       "Component Profile Problem", 
ERROR_MESSAGE);
+                       return;
+               }
+               StringBuilder prefixString = new StringBuilder();
+               for (Entry<String, String> entry : prefixMap.entrySet())
+                       if (!entry.getKey().equals(WFDESC_PREFIX))
+                               
prefixString.append(constructPrefixString(entry));
+
+               SearchChoicePanel searchChoicePanel = new SearchChoicePanel(
+                               chosenRegistry, prefixString.toString(), 
queryString);
+               int answer = showOptionDialog(null, searchChoicePanel,
+                               "Matching components", OK_CANCEL_OPTION, 
QUESTION_MESSAGE,
+                               null, new String[] { "Add to workflow", 
"Cancel" }, "Cancel");
+               if (answer == OK_OPTION) {
+                       Version.ID ident = 
searchChoicePanel.getVersionIdentification();
+                       if (ident != null)
+                               WorkflowView.importServiceDescription(new 
ComponentServiceDesc(prefs,
+                                               factory, icon, ident), false, 
em, mm, sm, sr);
+               }
+       }
+
+       private static String constructPrefixString(Entry<String, String> 
entry) {
+               String key = entry.getKey();
+               String value = entry.getValue();
+               return String.format("PREFIX %s:<%s>\n", key, value);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSearchMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSearchMenuAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSearchMenuAction.java
new file mode 100644
index 0000000..c621651
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentSearchMenuAction.java
@@ -0,0 +1,85 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import io.github.taverna_extras.component.api.ComponentFactory;
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import org.apache.taverna.services.ServiceRegistry;
+import org.apache.taverna.ui.menu.MenuManager;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.selection.SelectionManager;
+
+/**
+ * @author alanrw
+ */
+public class ComponentSearchMenuAction extends AbstractComponentMenuAction {
+       private static final URI SEARCH_COMPONENT_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#componentSearch";);
+       private ComponentPreference prefs;
+       private ComponentFactory factory;
+       private EditManager em;
+       private MenuManager mm;
+       private SelectionManager sm;
+       private ServiceRegistry serviceRegistry;
+       private ComponentServiceIcon icon;
+
+       public ComponentSearchMenuAction() {
+               super(1500, SEARCH_COMPONENT_URI);
+       }
+
+       public void setPreferences(ComponentPreference prefs) {
+               this.prefs = prefs;
+       }
+
+       public void setComponentFactory(ComponentFactory factory) {
+               this.factory = factory;
+       }
+
+       public void setEditManager(EditManager em) {
+               this.em = em;
+       }
+
+       public void setMenuManager(MenuManager mm) {
+               this.mm = mm;
+       }
+
+       public void setSelectionManager(SelectionManager sm) {
+               this.sm = sm;
+       }
+
+       public void setServiceRegistry(ServiceRegistry serviceRegistry) {
+               this.serviceRegistry = serviceRegistry;
+       }
+
+       public void setIcon(ComponentServiceIcon icon) {
+               this.icon = icon;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new ComponentSearchAction(prefs, factory, em, mm, sm,
+                               serviceRegistry, icon);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentServiceCreatorAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentServiceCreatorAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentServiceCreatorAction.java
new file mode 100644
index 0000000..0c7a668
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentServiceCreatorAction.java
@@ -0,0 +1,112 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static org.apache.log4j.Logger.getLogger;
+import static org.apache.taverna.scufl2.api.common.Scufl2Tools.NESTED_WORKFLOW;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.Version;
+import 
io.github.taverna_extras.component.ui.menu.component.ComponentCreatorSupport.CopiedProcessor;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+import org.apache.taverna.workbench.selection.SelectionManager;
+
+/**
+ * @author alanrw
+ */
+public class ComponentServiceCreatorAction extends AbstractAction {
+       private static final long serialVersionUID = -2611514696254112190L;
+       private static Logger logger = 
getLogger(ComponentServiceCreatorAction.class);
+
+       private final Processor p;
+       private final Profile profile;
+       private final ComponentCreatorSupport support;
+
+       public ComponentServiceCreatorAction(Processor processor, 
SelectionManager sm,
+                       ComponentCreatorSupport support, ComponentServiceIcon 
icon) {
+               super("Create component...", icon.getIcon());
+               this.support = support;
+               p = processor;
+               profile = sm.getSelectedProfile();
+       }
+
+       private Workflow getNestedWorkflow(Activity a) {
+               JsonNode nw = 
a.getConfiguration().getJson().get("nestedWorkflow");
+               return 
a.getParent().getParent().getWorkflows().getByName(nw.asText());
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent event) {
+               Version.ID ident = 
support.getNewComponentIdentification(p.getName());
+               if (ident == null)
+                       return;
+
+               Activity a = p.getActivity(profile);
+
+               try {
+                       Workflow d;
+                       if (NESTED_WORKFLOW.equals(a.getType()))
+                               d = getNestedWorkflow(a);
+                       else {
+                               d = new Workflow();
+
+                               /* TODO: Keep the description */
+                               // fm.setCurrentDataflow(current);
+
+                               CopiedProcessor processorElement = 
support.copyProcessor(p);
+
+                               Processor newProcessor;
+                               try {
+                                       newProcessor = 
support.pasteProcessor(processorElement, d);
+                               } catch (IllegalArgumentException e) {
+                                       logger.error(
+                                                       "failed to paste 
processor representing component",
+                                                       e);
+                                       showMessageDialog(null, e.getMessage(),
+                                                       "Component creation 
failure", ERROR_MESSAGE);
+                                       return;
+                               }
+
+                               support.connectNewProcessor(d, newProcessor);
+                       }
+
+                       Activity ca = new Activity();
+                       support.saveWorkflowAsComponent(d, 
ident).installConfiguration(ca);
+                       support.moveComponentActivityIntoPlace(a, p, ca);
+               } catch (Exception e) {
+                       logger.error("failed to instantiate component", e);
+                       showMessageDialog(null, e.getCause().getMessage(),
+                                       "Component creation failure", 
ERROR_MESSAGE);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentServiceCreatorMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentServiceCreatorMenuAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentServiceCreatorMenuAction.java
new file mode 100644
index 0000000..ef55fa5
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentServiceCreatorMenuAction.java
@@ -0,0 +1,77 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import 
io.github.taverna_extras.component.ui.menu.AbstractContextComponentMenuAction;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.workbench.selection.SelectionManager;
+
+/**
+ * @author alanrw
+ */
+public class ComponentServiceCreatorMenuAction extends
+               AbstractContextComponentMenuAction {
+       private static final URI configureSection = URI
+                       
.create("http://taverna.sf.net/2009/contextMenu/configure";);
+
+       private ComponentCreatorSupport support;
+       private SelectionManager sm;
+       private ComponentServiceIcon icon;
+
+       public ComponentServiceCreatorMenuAction() {
+               super(configureSection, 60);
+       }
+
+       public void setIcon(ComponentServiceIcon icon) {
+               this.icon = icon;
+       }
+
+       public void setSelectionManager(SelectionManager sm) {
+               this.sm = sm;
+       }
+       
+       public void setSupport(ComponentCreatorSupport support) {
+               this.support = support;
+       }
+
+       @Override
+       public boolean isEnabled() {
+               if (!super.isEnabled())
+                       return false;
+               Activity a = findActivity();
+               if (a == null)
+                       return false;
+               return !isComponentActivity(a);
+       }
+
+       @Override
+       protected Action createAction() {
+               return new ComponentServiceCreatorAction(
+                               (Processor) 
getContextualSelection().getSelection(), sm,
+                               support, icon);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentWorkflowCreatorAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentWorkflowCreatorAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentWorkflowCreatorAction.java
new file mode 100644
index 0000000..c21de5b
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentWorkflowCreatorAction.java
@@ -0,0 +1,84 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.event.ActionEvent;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.ui.ComponentAction;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import io.github.taverna_extras.component.ui.util.Utils;
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.file.events.FileManagerEvent;
+import org.apache.taverna.workbench.views.graph.GraphViewComponent;
+
+/**
+ * @author alanrw
+ */
+public class ComponentWorkflowCreatorAction extends ComponentAction implements
+               Observer<FileManagerEvent> {
+       private static final long serialVersionUID = -299685223430721587L;
+       private static Logger logger = 
getLogger(ComponentWorkflowCreatorAction.class);
+       private static final String CREATE_COMPONENT = "Create component from 
current workflow...";
+
+       private ComponentCreatorSupport support;
+       private FileManager fileManager;
+       private Utils utils;
+
+       public ComponentWorkflowCreatorAction(ComponentCreatorSupport support,
+                       FileManager fm, GraphViewComponent graphView,
+                       ComponentServiceIcon icon, Utils utils) {
+               super(CREATE_COMPONENT, graphView);
+               this.support = support;
+               this.utils = utils;
+               fm.addObserver(this);
+               this.setIcon(icon);
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent event) {
+               WorkflowBundle bundle = fileManager.getCurrentDataflow();
+               try {
+                       Version.ID ident = 
support.getNewComponentIdentification(bundle.getName());//TODO is this right
+                       if (ident == null)
+                               return;
+                       support.saveWorkflowAsComponent(bundle, ident);
+               } catch (Exception e) {
+                       showMessageDialog(graphView, e.getCause().getMessage(),
+                                       "Component creation failure", 
ERROR_MESSAGE);
+                       logger.error("failed to save workflow as component", e);
+               }
+       }
+
+       @Override
+       public void notify(Observable<FileManagerEvent> sender,
+                       FileManagerEvent message) throws Exception {
+               setEnabled(!utils.currentDataflowIsComponent());
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentWorkflowCreatorMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentWorkflowCreatorMenuAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentWorkflowCreatorMenuAction.java
new file mode 100644
index 0000000..8ddaf5c
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentWorkflowCreatorMenuAction.java
@@ -0,0 +1,72 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import io.github.taverna_extras.component.ui.util.Utils;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.views.graph.GraphViewComponent;
+
+/**
+ * @author alanrw
+ */
+public class ComponentWorkflowCreatorMenuAction extends 
AbstractComponentMenuAction {
+       private static final URI COMPONENT_WORKFLOW_CREATE_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#componentCreate";);
+
+       private ComponentCreatorSupport support;
+       private FileManager fm;
+       private GraphViewComponent graphView;
+       private ComponentServiceIcon icon;
+       private Utils utils;
+
+       public ComponentWorkflowCreatorMenuAction() {
+               super(600, COMPONENT_WORKFLOW_CREATE_URI);
+       }
+
+       public void setSupport(ComponentCreatorSupport support) {
+               this.support = support;
+       }
+
+       public void setFileManager(FileManager fm) {
+               this.fm = fm;
+       }
+
+       public void setGraphView(GraphViewComponent graphView) {
+               this.graphView = graphView;
+       }
+
+       public void setIcon(ComponentServiceIcon icon) {
+               this.icon = icon;
+       }
+
+       public void setUtils(Utils utils) {
+               this.utils = utils;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new ComponentWorkflowCreatorAction(support, fm, 
graphView, icon, utils);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/FileOpenFromComponentMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/FileOpenFromComponentMenuAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/FileOpenFromComponentMenuAction.java
new file mode 100644
index 0000000..016098f
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/FileOpenFromComponentMenuAction.java
@@ -0,0 +1,74 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.file.FileType;
+import org.apache.taverna.workbench.views.graph.GraphViewComponent;
+
+/**
+ * @author alanrw
+ */
+public class FileOpenFromComponentMenuAction extends
+               AbstractComponentMenuAction {
+       private static final URI FILE_OPEN_FROM_COMPONENT_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#componentOpen";);
+       private FileManager fm;
+       private FileType ft;
+       private ComponentPreference prefs;
+       private GraphViewComponent graphView;
+       private ComponentServiceIcon icon;
+
+       public FileOpenFromComponentMenuAction() {
+               super(700, FILE_OPEN_FROM_COMPONENT_URI);
+       }
+
+       public void setFileManager(FileManager fm) {
+               this.fm = fm;
+       }
+
+       public void setFileType(FileType ft) {
+               this.ft = ft;
+       }
+
+       public void setPreferences(ComponentPreference prefs) {
+               this.prefs = prefs;
+       }
+
+       public void setGraphView(GraphViewComponent graphView) {
+               this.graphView = graphView;
+       }
+
+       public void setIcon(ComponentServiceIcon icon) {
+               this.icon = icon;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new OpenWorkflowFromComponentAction(fm, ft, prefs, 
graphView,
+                               icon);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/OpenWorkflowFromComponentAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/OpenWorkflowFromComponentAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/OpenWorkflowFromComponentAction.java
new file mode 100644
index 0000000..373195f
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/OpenWorkflowFromComponentAction.java
@@ -0,0 +1,137 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import static javax.swing.JOptionPane.CANCEL_OPTION;
+import static javax.swing.JOptionPane.OK_OPTION;
+import static javax.swing.JOptionPane.QUESTION_MESSAGE;
+import static javax.swing.JOptionPane.YES_NO_OPTION;
+import static javax.swing.JOptionPane.showOptionDialog;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JOptionPane;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.Component;
+import io.github.taverna_extras.component.api.Family;
+import io.github.taverna_extras.component.api.Registry;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.ui.ComponentAction;
+import io.github.taverna_extras.component.ui.panel.ComponentChoiceMessage;
+import 
io.github.taverna_extras.component.ui.panel.ComponentVersionChooserPanel;
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.file.FileType;
+import org.apache.taverna.workbench.file.exceptions.OpenException;
+import org.apache.taverna.workbench.views.graph.GraphViewComponent;
+
+/**
+ * @author alanrw
+ */
+public class OpenWorkflowFromComponentAction extends ComponentAction {
+       private static final long serialVersionUID = 7382677337746318211L;
+       private static final Logger logger = 
getLogger(OpenWorkflowFromComponentAction.class);
+       private static final String ACTION_NAME = "Open component...";
+       private static final String ACTION_DESCRIPTION = "Open the workflow 
that implements a component";
+
+       private final FileManager fm;
+       private final FileType ft;
+       private final ComponentPreference prefs;
+
+       public OpenWorkflowFromComponentAction(FileManager fm, FileType ft,
+                       ComponentPreference prefs, GraphViewComponent graphView,
+                       ComponentServiceIcon icon) {
+               super(ACTION_NAME, graphView);
+               this.fm = fm;
+               this.ft = ft;
+               this.prefs = prefs;
+               setIcon(icon);
+               putValue(SHORT_DESCRIPTION, ACTION_DESCRIPTION);
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent arg) {
+               final ComponentVersionChooserPanel panel = new 
ComponentVersionChooserPanel(prefs);     
+               
+               final JButton okay = new JButton("OK");
+               okay.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               getOptionPane((JComponent) 
e.getSource()).setValue(OK_OPTION);
+                               doOpen(panel.getChosenRegistry(), 
panel.getChosenFamily(),
+                                               panel.getChosenComponent(),
+                                               
panel.getChosenComponentVersion());
+                       }
+               });
+               okay.setEnabled(false);
+               // Only enable the OK button of a component is not null
+               panel.getComponentChooserPanel().addObserver(
+                               new Observer<ComponentChoiceMessage>() {
+                                       @Override
+                                       public void notify(
+                                                       
Observable<ComponentChoiceMessage> sender,
+                                                       ComponentChoiceMessage 
message) throws Exception {
+                                               
okay.setEnabled(message.getChosenComponent() != null);
+                                       }
+                               });
+
+               final JButton cancel = new JButton("Cancel");
+               cancel.addActionListener(new ActionListener() {
+                   @Override
+                   public void actionPerformed(ActionEvent e) {
+                
getOptionPane((JComponent)e.getSource()).setValue(CANCEL_OPTION);
+                   }
+               });
+
+               showOptionDialog(graphView, panel, "Component version choice",
+                               YES_NO_OPTION, QUESTION_MESSAGE, null, new 
Object[] { okay,
+                                               cancel }, okay);
+       }
+       
+    protected JOptionPane getOptionPane(JComponent parent) {
+               if (parent instanceof JOptionPane)
+                       return (JOptionPane) parent;
+               return getOptionPane((JComponent) parent.getParent());
+    }
+
+       private void doOpen(Registry registry, Family family, Component 
component,
+                       Version version) {
+               Version.ID ident = new Version.Identifier(
+                               registry.getRegistryBase(), family.getName(),
+                               component.getName(), 
version.getVersionNumber());
+
+               try {
+                       WorkflowBundle d = fm.openDataflow(ft, ident);
+                       markGraphAsBelongingToComponent(d);
+               } catch (OpenException e) {
+                       logger.error("Failed to open component definition", e);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyCreateAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyCreateAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyCreateAction.java
new file mode 100644
index 0000000..0fe2ee4
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyCreateAction.java
@@ -0,0 +1,176 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.family;
+
+import static java.awt.GridBagConstraints.BOTH;
+import static java.awt.GridBagConstraints.WEST;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
+import static javax.swing.JOptionPane.OK_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.border.TitledBorder;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.License;
+import io.github.taverna_extras.component.api.Registry;
+import io.github.taverna_extras.component.api.SharingPolicy;
+import io.github.taverna_extras.component.api.profile.Profile;
+import io.github.taverna_extras.component.ui.panel.LicenseChooserPanel;
+import io.github.taverna_extras.component.ui.panel.ProfileChooserPanel;
+import io.github.taverna_extras.component.ui.panel.RegistryChooserPanel;
+import io.github.taverna_extras.component.ui.panel.SharingPolicyChooserPanel;
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+
+/**
+ * @author alanrw
+ */
+public class ComponentFamilyCreateAction extends AbstractAction {
+       private static final long serialVersionUID = -7780471499146286881L;
+       private static final Logger logger = 
getLogger(ComponentFamilyCreateAction.class);
+       private static final String CREATE_FAMILY = "Create family...";
+
+       private ComponentPreference prefs;
+       private JPanel overallPanel;
+       private GridBagConstraints gbc;
+
+       public ComponentFamilyCreateAction(ComponentPreference prefs,
+                       ComponentServiceIcon iconProvider) {
+               super(CREATE_FAMILY, iconProvider.getIcon());
+               this.prefs = prefs;
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent arg0) {
+               overallPanel = new JPanel(new GridBagLayout());
+               gbc = new GridBagConstraints();
+
+               RegistryChooserPanel registryPanel = new 
RegistryChooserPanel(prefs);
+
+               gbc.insets.left = 5;
+               gbc.insets.right = 5;
+               gbc.gridx = 0;
+               gbc.anchor = WEST;
+               gbc.fill = BOTH;
+               gbc.gridwidth = 2;
+               gbc.weightx = 1;
+               gbc.gridy++;
+               overallPanel.add(registryPanel, gbc);
+
+               ProfileChooserPanel profilePanel = new ProfileChooserPanel(
+                               registryPanel);
+               gbc.gridx = 0;
+               gbc.weighty = 1;
+               gbc.gridy++;
+               overallPanel.add(profilePanel, gbc);
+
+               gbc.gridx = 0;
+               gbc.gridwidth = 1;
+               gbc.weightx = 0;
+               gbc.weighty = 0;
+               gbc.gridy++;
+               overallPanel.add(new JLabel("Component family name:"), gbc);
+
+               gbc.gridx = 1;
+               gbc.weightx = 1;
+               JTextField familyNameField = new JTextField(60);
+               overallPanel.add(familyNameField, gbc);
+
+               gbc.gridx = 0;
+               gbc.gridwidth = 2;
+               gbc.weightx = 0;
+               gbc.weighty = 0;
+               gbc.gridy++;
+               JTextArea familyDescription = new JTextArea(10, 60);
+               JScrollPane familyDescriptionPane = new 
JScrollPane(familyDescription);
+               familyDescriptionPane.setBorder(new TitledBorder("Family 
description"));
+               overallPanel.add(familyDescriptionPane, gbc);
+
+               gbc.gridx = 0;
+               gbc.gridwidth = 2;
+               gbc.weightx = 1;
+               gbc.weighty = 1;
+               gbc.gridy++;
+               SharingPolicyChooserPanel permissionPanel = new 
SharingPolicyChooserPanel(
+                               registryPanel);
+               overallPanel.add(permissionPanel, gbc);
+
+               gbc.gridy++;
+               LicenseChooserPanel licensePanel = new LicenseChooserPanel();
+               registryPanel.addObserver(licensePanel);
+               overallPanel.add(licensePanel, gbc);
+
+               int answer = showConfirmDialog(null, overallPanel,
+                               "Create Component Family", OK_CANCEL_OPTION);
+               if (answer == OK_OPTION)
+                       doCreate(registryPanel.getChosenRegistry(),
+                                       profilePanel.getChosenProfile(), 
familyNameField.getText(),
+                                       familyDescription.getText(),
+                                       permissionPanel.getChosenPermission(),
+                                       licensePanel.getChosenLicense());
+       }
+
+       private void doCreate(Registry chosenRegistry, Profile chosenProfile,
+                       String newName, String familyDescription, SharingPolicy 
permission,
+                       License license) {
+               if (chosenRegistry == null) {
+                       showMessageDialog(null, "Unable to determine registry",
+                                       "Component Registry Problem", 
ERROR_MESSAGE);
+                       return;
+               } else if (chosenProfile == null) {
+                       showMessageDialog(null, "Unable to determine profile",
+                                       "Component Profile Problem", 
ERROR_MESSAGE);
+                       return;
+               } else if ((newName == null) || newName.isEmpty()) {
+                       showMessageDialog(null, "Name must be specified",
+                                       "Missing component family name", 
ERROR_MESSAGE);
+                       return;
+               }
+
+               try {
+                       if (chosenRegistry.getComponentFamily(newName) != null) 
{
+                               showMessageDialog(null, newName + " is already 
used",
+                                               "Duplicate component family 
name", ERROR_MESSAGE);
+                               return;
+                       }
+                       chosenRegistry.createComponentFamily(newName, 
chosenProfile,
+                                       familyDescription, license, permission);
+               } catch (ComponentException e) {
+                       logger.error("failed to create family", e);
+                       showMessageDialog(null,
+                                       "Unable to create family: " + 
e.getMessage(),
+                                       "Family creation problem", 
ERROR_MESSAGE);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyCreateMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyCreateMenuAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyCreateMenuAction.java
new file mode 100644
index 0000000..94c0080
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyCreateMenuAction.java
@@ -0,0 +1,58 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.family;
+
+import static 
io.github.taverna_extras.component.ui.menu.family.ComponentFamilyMenuSection.COMPONENT_FAMILY_SECTION;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import org.apache.taverna.ui.menu.AbstractMenuAction;
+
+/**
+ * @author alanrw
+ */
+public class ComponentFamilyCreateMenuAction extends AbstractMenuAction {
+       private static final URI COMPONENT_FAMILY_CREATE_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#componentFamilyCreate";);
+
+       private ComponentPreference prefs;
+       private ComponentServiceIcon iconProvider;
+
+       public ComponentFamilyCreateMenuAction() {
+               super(COMPONENT_FAMILY_SECTION, 400, 
COMPONENT_FAMILY_CREATE_URI);
+       }
+
+       public void setPreferences(ComponentPreference prefs) {
+               this.prefs = prefs;
+       }
+
+       public void setIcon(ComponentServiceIcon iconProvider) {
+               this.iconProvider = iconProvider;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new ComponentFamilyCreateAction(prefs, iconProvider);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyDeleteAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyDeleteAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyDeleteAction.java
new file mode 100644
index 0000000..4ac20e4
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyDeleteAction.java
@@ -0,0 +1,201 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.family;
+
+import static java.awt.GridBagConstraints.BOTH;
+import static java.awt.GridBagConstraints.WEST;
+import static java.lang.String.format;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
+import static javax.swing.JOptionPane.OK_OPTION;
+import static javax.swing.JOptionPane.YES_NO_OPTION;
+import static javax.swing.JOptionPane.YES_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.util.concurrent.ExecutionException;
+
+import javax.swing.AbstractAction;
+import javax.swing.JPanel;
+import javax.swing.SwingWorker;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.Family;
+import io.github.taverna_extras.component.api.Registry;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.ui.panel.FamilyChooserPanel;
+import io.github.taverna_extras.component.ui.panel.RegistryChooserPanel;
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceProviderConfig;
+import io.github.taverna_extras.component.ui.util.Utils;
+
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.workbench.file.FileManager;
+
+/**
+ * @author alanrw
+ */
+public class ComponentFamilyDeleteAction extends AbstractAction {
+       private static final String CONFIRM_MSG = "Are you sure you want to 
delete %s";
+       private static final String CONFIRM_TITLE = "Delete Component Family 
Confirmation";
+       private static final String DELETE_FAMILY_LABEL = "Delete family...";
+       private static final String ERROR_TITLE = "Component Family Deletion 
Error";
+       private static final String FAILED_MSG = "Unable to delete %s: %s";
+       private static final String FAMILY_FAIL_TITLE = "Component Family 
Problem";
+       private static final String OPEN_MSG = "Components in the family are 
open";
+       private static final String PICK_FAMILY_TITLE = "Delete Component 
Family";
+       private static final String REGISTRY_FAIL_TITLE = "Component Registry 
Problem";
+       private static final String WHAT_FAMILY_MSG = "Unable to determine 
family";
+       private static final String WHAT_REGISTRY_MSG = "Unable to determine 
registry";
+       private static final Logger logger = 
getLogger(ComponentFamilyDeleteAction.class);
+       private static final long serialVersionUID = -4976161883778371344L;
+
+       private final FileManager fm;
+       private final ComponentPreference prefs;
+       private final Utils utils;
+
+       public ComponentFamilyDeleteAction(FileManager fm,
+                       ComponentPreference prefs, ComponentServiceIcon icon, 
Utils utils) {
+               super(DELETE_FAMILY_LABEL, icon.getIcon());
+               this.fm = fm;
+               this.prefs = prefs;
+               this.utils = utils;
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent ev) {
+               JPanel overallPanel = new JPanel(new GridBagLayout());
+               GridBagConstraints gbc = new GridBagConstraints();
+
+               RegistryChooserPanel registryPanel = new 
RegistryChooserPanel(prefs);
+
+               gbc.insets = new Insets(0, 5, 0, 5);
+               gbc.gridx = 0;
+               gbc.gridy = 0;
+               gbc.anchor = WEST;
+               gbc.fill = BOTH;
+               gbc.gridwidth = 2;
+               gbc.weightx = 1;
+               overallPanel.add(registryPanel, gbc);
+
+               FamilyChooserPanel familyPanel = new 
FamilyChooserPanel(registryPanel);
+               gbc.gridx = 0;
+               gbc.gridy = 1;
+               gbc.weighty = 1;
+               overallPanel.add(familyPanel, gbc);
+
+               int answer = showConfirmDialog(null, overallPanel, 
PICK_FAMILY_TITLE,
+                               OK_CANCEL_OPTION);
+               if (answer == OK_OPTION)
+                       deletionActionFlow(registryPanel.getChosenRegistry(),
+                                       familyPanel.getChosenFamily());
+       }
+
+       /**
+        * Check if the preconditions for the deletion action are satisfied.
+        * 
+        * @param chosenRegistry
+        *            What registry contains the family.
+        * @param chosenFamily
+        */
+       private void deletionActionFlow(Registry chosenRegistry,
+                       final Family chosenFamily) {
+               if (chosenRegistry == null) {
+                       showMessageDialog(null, WHAT_REGISTRY_MSG, 
REGISTRY_FAIL_TITLE,
+                                       ERROR_MESSAGE);
+                       return;
+               } else if (chosenFamily == null) {
+                       showMessageDialog(null, WHAT_FAMILY_MSG, 
FAMILY_FAIL_TITLE,
+                                       ERROR_MESSAGE);
+                       return;
+               } else if (familyIsInUse(chosenRegistry, chosenFamily)) {
+                       showMessageDialog(null, OPEN_MSG, FAMILY_FAIL_TITLE, 
ERROR_MESSAGE);
+                       return;
+               } else if (showConfirmDialog(null,
+                               format(CONFIRM_MSG, chosenFamily.getName()), 
CONFIRM_TITLE,
+                               YES_NO_OPTION) == YES_OPTION)
+                       new SwingWorker<ComponentServiceProviderConfig, 
Object>() {
+                               @Override
+                               protected ComponentServiceProviderConfig 
doInBackground()
+                                               throws Exception {
+                                       return deleteFamily(chosenFamily);
+                               }
+
+                               @Override
+                               protected void done() {
+                                       deletionDone(chosenFamily, this);
+                               }
+                       }.execute();
+       }
+
+       private ComponentServiceProviderConfig deleteFamily(Family family)
+                       throws ComponentException {
+               ComponentServiceProviderConfig config = new 
ComponentServiceProviderConfig(
+                               family);
+               family.delete();
+               return config;
+       }
+
+       private void deletionDone(Family family,
+                       SwingWorker<ComponentServiceProviderConfig, Object> 
worker) {
+               Configuration config;
+               try {
+               config = worker.get().getConfiguration();
+               } catch (InterruptedException e) {
+                       logger.warn("interrupted during removal of component 
family", e);
+                       return;
+               } catch (ExecutionException e) {
+                       logger.error("failed to delete family", e.getCause());
+                       showMessageDialog(
+                                       null,
+                                       format(FAILED_MSG, family.getName(), 
e.getCause()
+                                                       .getMessage()), 
ERROR_TITLE, ERROR_MESSAGE);
+                       return;
+               }
+               try {
+                       utils.removeComponentServiceProvider(config);
+               } catch (Exception e) {
+                       logger.error("failed to update service provider panel "
+                                       + "after deleting family", e);
+               }
+       }
+
+       private boolean familyIsInUse(Registry chosenRegistry, Family 
chosenFamily) {
+               for (WorkflowBundle d : fm.getOpenDataflows()) {
+                       Object dataflowSource = fm.getDataflowSource(d);
+                       if (dataflowSource instanceof Version.ID) {
+                               Version.ID ident = (Version.ID) dataflowSource;
+                               if (ident.getRegistryBase().toString()
+                                               
.equals(chosenRegistry.getRegistryBase().toString())
+                                               && 
ident.getFamilyName().equals(chosenFamily.getName()))
+                                       return true;
+                       }
+               }
+               return false;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyDeleteMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyDeleteMenuAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyDeleteMenuAction.java
new file mode 100644
index 0000000..ffb3cbf
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyDeleteMenuAction.java
@@ -0,0 +1,69 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.family;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import io.github.taverna_extras.component.ui.util.Utils;
+import org.apache.taverna.ui.menu.AbstractMenuAction;
+import org.apache.taverna.workbench.file.FileManager;
+
+/**
+ * @author alanrw
+ */
+public class ComponentFamilyDeleteMenuAction extends AbstractMenuAction {
+       private static final URI COMPONENT_FAMILY_DELETE_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#componentFamilyDelete";);
+
+       private FileManager fm;
+       private ComponentPreference prefs;
+       private ComponentServiceIcon icon;
+       private Utils utils;
+
+       public ComponentFamilyDeleteMenuAction() {
+               super(ComponentFamilyMenuSection.COMPONENT_FAMILY_SECTION, 500,
+                               COMPONENT_FAMILY_DELETE_URI);
+       }
+
+       public void setFileManager(FileManager fm) {
+               this.fm = fm;
+       }
+
+       public void setIcon(ComponentServiceIcon icon) {
+               this.icon = icon;
+       }
+       
+       public void setPreferences(ComponentPreference prefs) {
+               this.prefs = prefs;
+       }
+
+       public void setUtils(Utils utils) {
+               this.utils = utils;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new ComponentFamilyDeleteAction(fm, prefs, icon, utils);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyMenuSection.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyMenuSection.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyMenuSection.java
new file mode 100644
index 0000000..dbc331e
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/family/ComponentFamilyMenuSection.java
@@ -0,0 +1,37 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.family;
+
+import java.net.URI;
+
+import io.github.taverna_extras.component.ui.menu.ComponentMenu;
+import org.apache.taverna.ui.menu.AbstractMenuSection;
+
+/**
+ * @author alanrw
+ */
+public class ComponentFamilyMenuSection extends AbstractMenuSection {
+       public static final URI COMPONENT_FAMILY_SECTION = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#componentFamilySection";);
+
+       public ComponentFamilyMenuSection() {
+               super(ComponentMenu.COMPONENT, 300, COMPONENT_FAMILY_SECTION);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/profile/ComponentProfileCopyAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/profile/ComponentProfileCopyAction.java
 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/profile/ComponentProfileCopyAction.java
new file mode 100644
index 0000000..2d8295a
--- /dev/null
+++ 
b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/profile/ComponentProfileCopyAction.java
@@ -0,0 +1,177 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.profile;
+
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
+import static javax.swing.JOptionPane.OK_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JPanel;
+import javax.swing.border.TitledBorder;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.License;
+import io.github.taverna_extras.component.api.Registry;
+import io.github.taverna_extras.component.api.SharingPolicy;
+import io.github.taverna_extras.component.api.profile.Profile;
+import io.github.taverna_extras.component.ui.panel.LicenseChooserPanel;
+import io.github.taverna_extras.component.ui.panel.ProfileChooserPanel;
+import io.github.taverna_extras.component.ui.panel.RegistryChooserPanel;
+import io.github.taverna_extras.component.ui.panel.SharingPolicyChooserPanel;
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import 
io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+
+/**
+ * @author alanrw
+ */
+public class ComponentProfileCopyAction extends AbstractAction {
+       private static final long serialVersionUID = 6332253931049645259L;
+       private static final Logger log = 
getLogger(ComponentProfileCopyAction.class);
+       private static final String COPY_PROFILE = "Copy profile...";
+
+       private final ComponentPreference prefs;
+
+       public ComponentProfileCopyAction(ComponentPreference prefs,
+                       ComponentServiceIcon iconProvider) {
+               super(COPY_PROFILE, iconProvider.getIcon());
+               this.prefs = prefs;
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent ev) {
+               JPanel overallPanel = new JPanel();
+               overallPanel.setLayout(new GridBagLayout());
+
+               GridBagConstraints gbc = new GridBagConstraints();
+
+               RegistryChooserPanel sourceRegistryPanel = new 
RegistryChooserPanel(prefs);
+               sourceRegistryPanel.setBorder(new TitledBorder("Source 
registry"));
+
+               gbc.insets = new Insets(0, 5, 0, 5);
+               gbc.gridx = 0;
+               gbc.gridy = 0;
+               gbc.anchor = GridBagConstraints.WEST;
+               gbc.fill = GridBagConstraints.BOTH;
+               gbc.gridwidth = 2;
+               gbc.weightx = 1;
+               overallPanel.add(sourceRegistryPanel, gbc);
+
+               ProfileChooserPanel profilePanel = new 
ProfileChooserPanel(sourceRegistryPanel);
+               profilePanel.setBorder(new TitledBorder("Source profile"));
+
+               gbc.gridx = 0;
+               gbc.gridy = 1;
+               gbc.weighty = 1;
+               overallPanel.add(profilePanel, gbc);
+
+               RegistryChooserPanel targetRegistryPanel = new 
RegistryChooserPanel(prefs);
+               targetRegistryPanel.setBorder(new TitledBorder("Target 
registry"));
+               gbc.gridy = 2;
+               overallPanel.add(targetRegistryPanel, gbc);
+
+               gbc.gridx = 0;
+               gbc.gridwidth = 2;
+               gbc.weightx = 1;
+               gbc.weighty = 1;
+               gbc.gridy++;
+               SharingPolicyChooserPanel permissionPanel = new 
SharingPolicyChooserPanel(targetRegistryPanel);
+               overallPanel.add(permissionPanel, gbc);
+
+               gbc.gridy++;
+               LicenseChooserPanel licensePanel = new LicenseChooserPanel();
+               targetRegistryPanel.addObserver(licensePanel);
+               overallPanel.add(licensePanel, gbc);
+
+               int answer = showConfirmDialog(null, overallPanel,
+                               "Copy Component Profile", OK_CANCEL_OPTION);
+               try {
+                       if (answer == OK_OPTION) 
+                               doCopy(sourceRegistryPanel.getChosenRegistry(),
+                                               profilePanel.getChosenProfile(),
+                                               
targetRegistryPanel.getChosenRegistry(),
+                                               
permissionPanel.getChosenPermission(),
+                                               
licensePanel.getChosenLicense());
+               } catch (ComponentException e) {
+                       log.error("failed to copy profile", e);
+                       showMessageDialog(null, "Unable to save profile: " + 
e.getMessage(),
+                                       "Registry Exception", ERROR_MESSAGE);
+               }
+       }
+
+       private void doCopy(Registry sourceRegistry, Profile sourceProfile,
+                       Registry targetRegistry, SharingPolicy permission, 
License license)
+                       throws ComponentException {
+               if (sourceRegistry == null) {
+                       showMessageDialog(null, "Unable to determine source 
registry",
+                                       "Component Registry Problem", 
ERROR_MESSAGE);
+                       return;
+               }
+               if (targetRegistry == null) {
+                       showMessageDialog(null, "Unable to determine target 
registry",
+                                       "Component Registry Problem", 
ERROR_MESSAGE);
+                       return;
+               }
+               if (sourceRegistry.equals(targetRegistry)) {
+                       showMessageDialog(null, "Cannot copy to the same 
registry",
+                                       "Copy Problem", ERROR_MESSAGE);
+                       return;
+               }
+               if (sourceProfile == null) {
+                       showMessageDialog(null, "Unable to determine source 
profile",
+                                       "Component Profile Problem", 
ERROR_MESSAGE);
+                       return;
+               }
+               for (Profile p : targetRegistry.getComponentProfiles()) {
+                       if (p.getName().equals(sourceProfile.getName())) {
+                               showMessageDialog(null,
+                                               "Target registry already 
contains a profile named "
+                                                               + 
sourceProfile.getName(), "Copy Problem",
+                                               ERROR_MESSAGE);
+                               return;
+                       }
+                       String sourceId = sourceProfile.getId();
+                       if (sourceId == null) {
+                               showMessageDialog(null,
+                                               "Source profile \"" + 
sourceProfile.getName()
+                                                               + "\" has no id 
", "Copy Problem",
+                                               ERROR_MESSAGE);
+                               return;
+                       }
+                       String id = p.getId();
+                       if (sourceId.equals(id)) {
+                               showMessageDialog(null,
+                                               "Target registry already 
contains a profile with id "
+                                                               + sourceId, 
"Copy Problem", ERROR_MESSAGE);
+                               return;
+                       }
+               }
+               targetRegistry.addComponentProfile(sourceProfile, license, 
permission);
+       }
+}

Reply via email to