From https://github.com/taverna/taverna-dataflow-activity-ui master
diff --git a/taverna-dataflow-activity-ui/pom.xml b/taverna-dataflow-activity-ui/pom.xml
new file mode 100644
index 0000000..d93cf07
--- /dev/null
+++ b/taverna-dataflow-activity-ui/pom.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+                <groupId>net.sf.taverna</groupId>
+                <artifactId>taverna-parent</artifactId>
+                <version>3.0.1-SNAPSHOT</version>
+	</parent>
+	<groupId>net.sf.taverna.t2.ui-activities</groupId>
+	<artifactId>dataflow-activity-ui</artifactId>
+        <version>2.0-SNAPSHOT</version>
+	<packaging>bundle</packaging>
+	<name>Taverna 2 Dataflow Activity UI</name>
+	<dependencies>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>activity-icons-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>activity-palette-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>contextual-views-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>file-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>edits-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-components</groupId>
+			<artifactId>workflow-view</artifactId>
+			<version>${t2.ui.components.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-components</groupId>
+			<artifactId>graph-view</artifactId>
+			<version>${t2.ui.components.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>uk.org.taverna.scufl2</groupId>
+			<artifactId>scufl2-api</artifactId>
+			<version>${scufl2.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>javax.help</groupId>
+			<artifactId>javahelp</artifactId>
+                        <version>${javahelp.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>activity-tools</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>helper-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+
+		<!--  testing dependencies -->
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+                        <version> ${junit.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-impl</groupId>
+			<artifactId>file-impl</artifactId>
+			<version>${t2.ui.impl.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-impl</groupId>
+			<artifactId>edits-impl</artifactId>
+			<version>${t2.ui.impl.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<!-- <dependency>
+			<groupId>uk.org.taverna.scufl2</groupId>
+			<artifactId>scufl2-t2flow</artifactId>
+			<version>${scufl2.version}</version>
+			<scope>test</scope>
+		</dependency> -->
+	</dependencies>
+	<repositories>
+		<repository>
+			<releases />
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+			<id>mygrid-repository</id>
+			<name>myGrid Repository</name>
+			<url>http://www.mygrid.org.uk/maven/repository
+			</url>
+		</repository>
+		<repository>
+			<releases>
+				<enabled>false</enabled>
+			</releases>
+			<snapshots />
+			<id>mygrid-snapshot-repository</id>
+			<name>myGrid Snapshot Repository</name>
+			<url>http://www.mygrid.org.uk/maven/snapshot-repository</url>
+		</repository>
+	</repositories>
+</project>
+
diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/actions/EditNestedDataflowAction.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/actions/EditNestedDataflowAction.java
new file mode 100644
index 0000000..679209c
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/actions/EditNestedDataflowAction.java
@@ -0,0 +1,49 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.activities.dataflow.actions;
+
+import java.awt.event.ActionEvent;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import net.sf.taverna.t2.activities.dataflow.servicedescriptions.DataflowTemplateService;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.common.Scufl2Tools;
+import uk.org.taverna.scufl2.api.configurations.Configuration;
+import uk.org.taverna.scufl2.api.core.Processor;
+import uk.org.taverna.scufl2.api.core.Workflow;
+import uk.org.taverna.scufl2.api.profiles.ProcessorBinding;
+
+@SuppressWarnings("serial")
+public class EditNestedDataflowAction extends AbstractAction {
+
+	private final Activity activity;
+	private final SelectionManager selectionManager;
+
+	private Scufl2Tools scufl2Tools = new Scufl2Tools();
+
+	public EditNestedDataflowAction(Activity activity, SelectionManager selectionManager) {
+		super("Edit nested workflow");
+		this.activity = activity;
+		this.selectionManager = selectionManager;
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		if (activity.getType().equals(DataflowTemplateService.ACTIVITY_TYPE)) {
+			for (Configuration configuration : scufl2Tools.configurationsFor(activity, selectionManager.getSelectedProfile())) {
+				JsonNode nested = configuration.getJson().get("nestedWorkflow");
+				Workflow nestedWorkflow = selectionManager.getSelectedWorkflowBundle().getWorkflows().getByName(nested.asText());
+				if (nestedWorkflow != null) {
+					selectionManager.setSelectedWorkflow(nestedWorkflow);
+					break;
+				}
+			}
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/menu/EditNestedDataflowMenuAction.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/menu/EditNestedDataflowMenuAction.java
new file mode 100644
index 0000000..8bdf0e1
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/menu/EditNestedDataflowMenuAction.java
@@ -0,0 +1,28 @@
+package net.sf.taverna.t2.activities.dataflow.menu;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.activities.dataflow.actions.EditNestedDataflowAction;
+import net.sf.taverna.t2.activities.dataflow.servicedescriptions.DataflowTemplateService;
+import net.sf.taverna.t2.workbench.activitytools.AbstractConfigureActivityMenuAction;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+
+public class EditNestedDataflowMenuAction extends AbstractConfigureActivityMenuAction {
+
+	private SelectionManager selectionManager;
+
+	public EditNestedDataflowMenuAction() {
+		super(DataflowTemplateService.ACTIVITY_TYPE);
+	}
+
+	@Override
+	protected Action createAction() {
+		EditNestedDataflowAction configAction = new EditNestedDataflowAction(findActivity(), selectionManager);
+		return configAction;
+	}
+
+	public void setSelectionManager(SelectionManager selectionManager) {
+		this.selectionManager = selectionManager;
+	}
+
+}
diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/servicedescriptions/DataflowActivityIcon.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/servicedescriptions/DataflowActivityIcon.java
new file mode 100644
index 0000000..6d7e766
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/servicedescriptions/DataflowActivityIcon.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.dataflow.servicedescriptions;
+
+import java.net.URI;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI;
+
+/**
+ *
+ * @author Alex Nenadic
+ * @author alanrw
+ *
+ */
+public class DataflowActivityIcon implements ActivityIconSPI{
+
+	private static Icon icon;
+
+	public int canProvideIconScore(URI activityType) {
+		if (DataflowTemplateService.ACTIVITY_TYPE.equals(activityType))
+			return DEFAULT_ICON + 1;
+		else
+			return NO_ICON;
+	}
+
+	public Icon getIcon(URI activityType) {
+		return getDataflowIcon();
+	}
+
+	public static Icon getDataflowIcon() {
+		if (icon == null) {
+			icon = new ImageIcon(DataflowActivityIcon.class.getResource("/dataflow.png"));
+		}
+		return icon;
+	}
+}
diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/servicedescriptions/DataflowTemplateService.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/servicedescriptions/DataflowTemplateService.java
new file mode 100644
index 0000000..f5cd8f2
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/servicedescriptions/DataflowTemplateService.java
@@ -0,0 +1,54 @@
+package net.sf.taverna.t2.activities.dataflow.servicedescriptions;
+
+import java.net.URI;
+
+import javax.swing.Icon;
+
+import net.sf.taverna.t2.servicedescriptions.AbstractTemplateService;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescription;
+import uk.org.taverna.scufl2.api.configurations.Configuration;
+
+public class DataflowTemplateService extends AbstractTemplateService {
+
+	public static final URI ACTIVITY_TYPE = URI.create("http://ns.taverna.org.uk/2010/activity/nested-workflow");
+
+	private static final String A_CONFIGURABLE_NESTED_WORKFLOW = "A service that allows you to have one workflow nested within another";
+	private static final String DATAFLOW = "Nested workflow";
+
+	private static final URI providerId = URI.create("http://taverna.sf.net/2010/service-provider/dataflow");
+
+	@Override
+	public URI getActivityType() {
+		return ACTIVITY_TYPE;
+	}
+
+	@Override
+	public Configuration getActivityConfiguration() {
+		Configuration configuration = new Configuration();
+		configuration.setType(ACTIVITY_TYPE.resolve("#Config"));
+		return configuration;
+	}
+
+	@Override
+	public Icon getIcon() {
+		return DataflowActivityIcon.getDataflowIcon();
+	}
+
+	public String getName() {
+		return DATAFLOW;
+	}
+
+	public String getDescription() {
+		return A_CONFIGURABLE_NESTED_WORKFLOW;
+	}
+
+	public static ServiceDescription getServiceDescription() {
+		DataflowTemplateService dts = new DataflowTemplateService();
+		return dts.templateService;
+	}
+
+	public String getId() {
+		return providerId.toString();
+	}
+
+}
diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/views/DataflowActivityContextualView.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/views/DataflowActivityContextualView.java
new file mode 100644
index 0000000..7bc44cb
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/views/DataflowActivityContextualView.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.dataflow.views;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+import net.sf.taverna.t2.activities.dataflow.actions.EditNestedDataflowAction;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.ui.menu.MenuManager;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.configuration.workbench.WorkbenchConfiguration;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.importworkflow.actions.ReplaceNestedWorkflowAction;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+import net.sf.taverna.t2.workbench.ui.actions.activity.HTMLBasedActivityContextualView;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.activity.Activity;
+
+@SuppressWarnings("serial")
+public class DataflowActivityContextualView extends HTMLBasedActivityContextualView {
+
+	static Logger logger = Logger.getLogger(DataflowActivityContextualView.class);
+
+	private final EditManager editManager;
+	private final FileManager fileManager;
+	private final MenuManager menuManager;
+	private final ActivityIconManager activityIconManager;
+	private final ColourManager colourManager;
+	private final WorkbenchConfiguration workbenchConfiguration;
+	private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+	private final SelectionManager selectionManager;
+
+	public DataflowActivityContextualView(Activity activity, EditManager editManager,
+			FileManager fileManager, MenuManager menuManager,
+			ActivityIconManager activityIconManager, ColourManager colourManager,
+			ServiceDescriptionRegistry serviceDescriptionRegistry,
+			WorkbenchConfiguration workbenchConfiguration, SelectionManager selectionManager) {
+		super(activity, colourManager);
+		this.editManager = editManager;
+		this.fileManager = fileManager;
+		this.menuManager = menuManager;
+		this.activityIconManager = activityIconManager;
+		this.colourManager = colourManager;
+		this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+		this.workbenchConfiguration = workbenchConfiguration;
+		this.selectionManager = selectionManager;
+		addEditButtons();
+	}
+
+	@Override
+	public Activity getActivity() {
+		return super.getActivity();
+	}
+
+	public void addEditButtons() {
+		JComponent mainFrame = getMainFrame();
+		JButton viewWorkflowButton = new JButton("Edit workflow");
+		viewWorkflowButton.addActionListener(new EditNestedDataflowAction(getActivity(),
+				selectionManager));
+		JButton configureButton = new JButton(new ReplaceNestedWorkflowAction(getActivity(),
+				editManager, fileManager, menuManager, activityIconManager, colourManager,
+				serviceDescriptionRegistry, workbenchConfiguration, selectionManager));
+		configureButton.setIcon(null);
+		JPanel flowPanel = new JPanel(new FlowLayout());
+		flowPanel.add(viewWorkflowButton);
+		flowPanel.add(configureButton);
+		mainFrame.add(flowPanel, BorderLayout.SOUTH);
+		mainFrame.revalidate();
+	}
+
+//	@Override
+//	public JComponent getMainFrame() {
+//		JComponent mainFrame = super.getMainFrame();
+//		JButton viewWorkflowButton = new JButton("Edit workflow");
+//		viewWorkflowButton.addActionListener(new EditNestedDataflowAction(getActivity(),
+//				selectionManager));
+//		JButton configureButton = new JButton(new ReplaceNestedWorkflowAction(getActivity(),
+//				editManager, fileManager, menuManager, activityIconManager, colourManager,
+//				serviceDescriptionRegistry, workbenchConfiguration, selectionManager));
+//		configureButton.setIcon(null);
+//		JPanel flowPanel = new JPanel(new FlowLayout());
+//		flowPanel.add(viewWorkflowButton);
+//		flowPanel.add(configureButton);
+//		mainFrame.add(flowPanel, BorderLayout.SOUTH);
+//		return mainFrame;
+//	}
+
+	@Override
+	protected String getRawTableRowsHtml() {
+		return ("<tr><td colspan=2>" + getActivity().getName() + "</td></tr>");
+	}
+
+	@Override
+	public String getViewTitle() {
+		return "Nested workflow";
+	}
+
+	@Override
+	public Action getConfigureAction(Frame owner) {
+		return null;
+		// return new OpenNestedDataflowFromFileAction(
+		// (DataflowActivity) getActivity(), owner);
+	}
+
+	@Override
+	public int getPreferredPosition() {
+		return 100;
+	}
+
+}
diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/views/DataflowActivityViewFactory.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/views/DataflowActivityViewFactory.java
new file mode 100644
index 0000000..e5d8f33
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/activities/dataflow/views/DataflowActivityViewFactory.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.dataflow.views;
+
+import java.util.Arrays;
+import java.util.List;
+
+import net.sf.taverna.t2.activities.dataflow.servicedescriptions.DataflowTemplateService;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.ui.menu.MenuManager;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.configuration.workbench.WorkbenchConfiguration;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory;
+import uk.org.taverna.scufl2.api.activity.Activity;
+
+public class DataflowActivityViewFactory implements ContextualViewFactory<Activity> {
+
+	private EditManager editManager;
+	private FileManager fileManager;
+	private MenuManager menuManager;
+	private ColourManager colourManager;
+	private ActivityIconManager activityIconManager;
+	private WorkbenchConfiguration workbenchConfiguration;
+	private ServiceDescriptionRegistry serviceDescriptionRegistry;
+	private SelectionManager selectionManager;
+
+	public boolean canHandle(Object object) {
+		return object instanceof Activity
+				&& ((Activity) object).getType().equals(DataflowTemplateService.ACTIVITY_TYPE);
+	}
+
+	public List<ContextualView> getViews(Activity activity) {
+		return Arrays.asList(new ContextualView[] { new DataflowActivityContextualView(activity,
+				editManager, fileManager, menuManager, activityIconManager, colourManager,
+				serviceDescriptionRegistry, workbenchConfiguration, selectionManager) });
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setFileManager(FileManager fileManager) {
+		this.fileManager = fileManager;
+	}
+
+	public void setMenuManager(MenuManager menuManager) {
+		this.menuManager = menuManager;
+	}
+
+	public void setActivityIconManager(ActivityIconManager activityIconManager) {
+		this.activityIconManager = activityIconManager;
+	}
+
+	public void setColourManager(ColourManager colourManager) {
+		this.colourManager = colourManager;
+	}
+
+	public void setServiceDescriptionRegistry(ServiceDescriptionRegistry serviceDescriptionRegistry) {
+		this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+	}
+
+	public void setWorkbenchConfiguration(WorkbenchConfiguration workbenchConfiguration) {
+		this.workbenchConfiguration = workbenchConfiguration;
+	}
+
+	public void setSelectionManager(SelectionManager selectionManager) {
+		this.selectionManager = selectionManager;
+	}
+
+}
diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/DataflowMerger.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/DataflowMerger.java
new file mode 100644
index 0000000..327e5a7
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/DataflowMerger.java
@@ -0,0 +1,124 @@
+package net.sf.taverna.t2.workbench.file.importworkflow;

+

+import java.util.ArrayList;

+import java.util.List;

+

+import net.sf.taverna.t2.workbench.edits.CompoundEdit;

+import net.sf.taverna.t2.workbench.edits.Edit;

+import net.sf.taverna.t2.workflow.edits.AddChildEdit;

+import net.sf.taverna.t2.workflow.edits.AddDataLinkEdit;

+import net.sf.taverna.t2.workflow.edits.AddProcessorEdit;

+import net.sf.taverna.t2.workflow.edits.AddWorkflowInputPortEdit;

+import net.sf.taverna.t2.workflow.edits.AddWorkflowOutputPortEdit;

+import uk.org.taverna.scufl2.api.common.AbstractCloneable;

+import uk.org.taverna.scufl2.api.container.WorkflowBundle;

+import uk.org.taverna.scufl2.api.core.ControlLink;

+import uk.org.taverna.scufl2.api.core.DataLink;

+import uk.org.taverna.scufl2.api.core.Processor;

+import uk.org.taverna.scufl2.api.core.Workflow;

+import uk.org.taverna.scufl2.api.port.InputWorkflowPort;

+import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;

+

+/**

+ * A tool that allows merging of two workflow.

+ * <p>

+ * The merge is performed as a series of edit, inserting a copy of the source

+ * workflow into the destination workflow.

+ *

+ * @author Stian Soiland-Reyes

+ * @author David Withers

+ */

+public class DataflowMerger {

+

+	/**

+	 * Make a copy of a workflow.

+	 *

+	 * @param source

+	 *            workflow to copy

+	 * @return A copy of the workflow.

+	 */

+	public static Workflow copyWorkflow(Workflow source) {

+		WorkflowBundle workflowBundle = AbstractCloneable.cloneWorkflowBean(source.getParent());

+		return workflowBundle.getWorkflows().getByName(source.getName());

+	}

+

+	private final Workflow destinationWorkflow;

+

+	/**

+	 * Construct a {@link DataflowMerger} for the given destination workflow.

+	 *

+	 * @param destinationWorkflow

+	 *            Workflow to be merged into

+	 */

+	public DataflowMerger(Workflow destinationWorkflow) {

+		this.destinationWorkflow = destinationWorkflow;

+	}

+

+	/**

+	 * Make an {@link Edit} that when performed merges the given source dataflow

+	 * into the destination dataflow.

+	 * <p>

+	 * Internally a copy is made of the source dataflow, to avoid modifying the

+	 * links and processors.

+	 *

+	 * @param sourceDataflow

+	 *            Dataflow to merge from

+	 * @return An edit that can perform and undo the insertion of the components

+	 *         from the source dataflow.

+	 * @throws MergeException

+	 *             If the merge cannot be performed.

+	 */

+	public CompoundEdit getMergeEdit(Workflow sourceDataflow)

+			throws MergeException {

+		return getMergeEdit(sourceDataflow, "");

+	}

+

+	/**

+	 * Make an {@link Edit} that when performed merges the given source dataflow

+	 * into the destination dataflow.

+	 * <p>

+	 * Internally a copy is made of the source dataflow, to avoid modifying the

+	 * links and processors.

+	 *

+	 * @param sourceWorkflow

+	 *            Dataflow to merge from

+	 * @param prefix

+	 *            A prefix which will be inserted in front of the names for the

+	 *            merged workflow components.

+	 * @return An edit that can perform and undo the insertion of the components

+	 *         from the source dataflow.

+	 * @throws MergeException

+	 *             If the merge cannot be performed.

+	 */

+	public CompoundEdit getMergeEdit(Workflow sourceWorkflow, String prefix)

+			throws MergeException {

+		List<Edit<?>> compoundEdit = new ArrayList<>();

+

+		Workflow workflow = copyWorkflow(sourceWorkflow);

+

+		for (InputWorkflowPort input : workflow.getInputPorts()) {

+			destinationWorkflow.getInputPorts().addWithUniqueName(input);

+			destinationWorkflow.getInputPorts().remove(input);

+			compoundEdit.add(new AddWorkflowInputPortEdit(destinationWorkflow, input));

+		}

+		for (OutputWorkflowPort output : workflow.getOutputPorts()) {

+			destinationWorkflow.getOutputPorts().addWithUniqueName(output);

+			destinationWorkflow.getOutputPorts().remove(output);

+			compoundEdit.add(new AddWorkflowOutputPortEdit(destinationWorkflow, output));

+		}

+		for (Processor processor : workflow.getProcessors()) {

+			processor.setName(prefix + processor.getName());

+			compoundEdit.add(new AddProcessorEdit(destinationWorkflow, processor));

+		}

+		for (DataLink dataLink : workflow.getDataLinks()) {

+			compoundEdit.add(new AddDataLinkEdit(destinationWorkflow, dataLink));

+		}

+		for (ControlLink controlLink : workflow.getControlLinks()) {

+			compoundEdit.add(new AddChildEdit<Workflow>(destinationWorkflow, controlLink));

+		}

+

+		return new CompoundEdit(compoundEdit);

+

+	}

+

+}

diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/MergeException.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/MergeException.java
new file mode 100644
index 0000000..3645f91
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/MergeException.java
@@ -0,0 +1,22 @@
+package net.sf.taverna.t2.workbench.file.importworkflow;

+

+public class MergeException extends Exception {

+	private static final long serialVersionUID = 6018700359518335402L;

+

+	public MergeException() {

+		super();

+	}

+

+	public MergeException(String message, Throwable cause) {

+		super(message, cause);

+	}

+

+	public MergeException(String message) {

+		super(message);

+	}

+

+	public MergeException(Throwable cause) {

+		super(cause);

+	}

+	

+}

diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/AddNestedWorkflowAction.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/AddNestedWorkflowAction.java
new file mode 100644
index 0000000..d6f04dd
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/AddNestedWorkflowAction.java
@@ -0,0 +1,59 @@
+package net.sf.taverna.t2.workbench.file.importworkflow.actions;

+

+import java.awt.Component;

+import java.awt.event.ActionEvent;

+

+import javax.swing.AbstractAction;

+

+import net.sf.taverna.t2.activities.dataflow.servicedescriptions.DataflowActivityIcon;

+import net.sf.taverna.t2.ui.menu.MenuManager;

+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;

+import net.sf.taverna.t2.workbench.configuration.workbench.WorkbenchConfiguration;

+import net.sf.taverna.t2.workbench.edits.EditManager;

+import net.sf.taverna.t2.workbench.file.FileManager;

+import net.sf.taverna.t2.workbench.file.importworkflow.gui.ImportWorkflowWizard;

+import net.sf.taverna.t2.workbench.selection.SelectionManager;

+import net.sf.taverna.t2.workbench.ui.Utils;

+

+/**

+ * An action for adding a nested workflow.

+ *

+ * @author Stian Soiland-Reyes

+ *

+ */

+public class AddNestedWorkflowAction extends AbstractAction {

+	private static final long serialVersionUID = -2242979457902699028L;

+	private final EditManager editManager;

+	private final FileManager fileManager;

+	private final MenuManager menuManager;

+	private final ColourManager colourManager;

+	private final WorkbenchConfiguration workbenchConfiguration;

+	private final SelectionManager selectionManager;

+

+	public AddNestedWorkflowAction(EditManager editManager, FileManager fileManager,

+			MenuManager menuManager, ColourManager colourManager,

+			WorkbenchConfiguration workbenchConfiguration, SelectionManager selectionManager) {

+		super("Add nested workflow", DataflowActivityIcon.getDataflowIcon());

+		this.editManager = editManager;

+		this.fileManager = fileManager;

+		this.menuManager = menuManager;

+		this.colourManager = colourManager;

+		this.workbenchConfiguration = workbenchConfiguration;

+		this.selectionManager = selectionManager;

+	}

+

+	public void actionPerformed(ActionEvent e) {

+		final Component parentComponent;

+		if (e.getSource() instanceof Component) {

+			parentComponent = (Component) e.getSource();

+		} else {

+			parentComponent = null;

+		}

+		ImportWorkflowWizard wizard = new ImportWorkflowWizard(

+				Utils.getParentFrame(parentComponent), editManager, fileManager, menuManager,

+				colourManager, workbenchConfiguration, selectionManager);

+		wizard.setMergeEnabled(false);

+		wizard.setVisible(true);

+	}

+

+}

diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/ImportWorkflowAction.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/ImportWorkflowAction.java
new file mode 100644
index 0000000..6d9fffb
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/ImportWorkflowAction.java
@@ -0,0 +1,59 @@
+package net.sf.taverna.t2.workbench.file.importworkflow.actions;

+

+import java.awt.Component;

+import java.awt.event.ActionEvent;

+

+import javax.swing.AbstractAction;

+

+import net.sf.taverna.t2.activities.dataflow.servicedescriptions.DataflowActivityIcon;

+import net.sf.taverna.t2.ui.menu.MenuManager;

+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;

+import net.sf.taverna.t2.workbench.configuration.workbench.WorkbenchConfiguration;

+import net.sf.taverna.t2.workbench.edits.EditManager;

+import net.sf.taverna.t2.workbench.file.FileManager;

+import net.sf.taverna.t2.workbench.file.importworkflow.gui.ImportWorkflowWizard;

+import net.sf.taverna.t2.workbench.selection.SelectionManager;

+import net.sf.taverna.t2.workbench.ui.Utils;

+

+/**

+ * A general version of {@link AddNestedWorkflowAction} and {@link MergeWorkflowAction} that allows

+ * the user to choose which action to perform.

+ *

+ * @author Stian Soiland-Reyes

+ *

+ */

+public class ImportWorkflowAction extends AbstractAction {

+	private static final long serialVersionUID = -2242979457902699028L;

+	private final EditManager editManager;

+	private final FileManager fileManager;

+	private final MenuManager menuManager;

+	private final ColourManager colourManager;

+	private final WorkbenchConfiguration workbenchConfiguration;

+	private final SelectionManager selectionManager;

+

+	public ImportWorkflowAction(EditManager editManager, FileManager fileManager,

+			MenuManager menuManager, ColourManager colourManager,

+			WorkbenchConfiguration workbenchConfiguration, SelectionManager selectionManager) {

+		super("Import workflow", DataflowActivityIcon.getDataflowIcon());

+		this.editManager = editManager;

+		this.fileManager = fileManager;

+		this.menuManager = menuManager;

+		this.colourManager = colourManager;

+		this.workbenchConfiguration = workbenchConfiguration;

+		this.selectionManager = selectionManager;

+	}

+

+	public void actionPerformed(ActionEvent e) {

+		final Component parentComponent;

+		if (e.getSource() instanceof Component) {

+			parentComponent = (Component) e.getSource();

+		} else {

+			parentComponent = null;

+		}

+		ImportWorkflowWizard wizard = new ImportWorkflowWizard(

+				Utils.getParentFrame(parentComponent), editManager, fileManager, menuManager,

+				colourManager, workbenchConfiguration, selectionManager);

+		wizard.setVisible(true);

+	}

+

+}

diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/MergeWorkflowAction.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/MergeWorkflowAction.java
new file mode 100644
index 0000000..d86f97c
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/MergeWorkflowAction.java
@@ -0,0 +1,58 @@
+package net.sf.taverna.t2.workbench.file.importworkflow.actions;

+

+import java.awt.Component;

+import java.awt.event.ActionEvent;

+

+import javax.swing.AbstractAction;

+

+import net.sf.taverna.t2.ui.menu.MenuManager;

+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;

+import net.sf.taverna.t2.workbench.configuration.workbench.WorkbenchConfiguration;

+import net.sf.taverna.t2.workbench.edits.EditManager;

+import net.sf.taverna.t2.workbench.file.FileManager;

+import net.sf.taverna.t2.workbench.file.importworkflow.gui.ImportWorkflowWizard;

+import net.sf.taverna.t2.workbench.selection.SelectionManager;

+import net.sf.taverna.t2.workbench.ui.Utils;

+

+/**

+ * An action for merging two workflows

+ *

+ * @author Stian Soiland-Reyes

+ *

+ */

+public class MergeWorkflowAction extends AbstractAction {

+	private static final long serialVersionUID = -2242979457902699028L;

+	private final EditManager editManager;

+	private final FileManager fileManager;

+	private final MenuManager menuManager;

+	private final ColourManager colourManager;

+	private final WorkbenchConfiguration workbenchConfiguration;

+	private final SelectionManager selectionManager;

+

+	public MergeWorkflowAction(EditManager editManager, FileManager fileManager,

+			MenuManager menuManager, ColourManager colourManager,

+			WorkbenchConfiguration workbenchConfiguration, SelectionManager selectionManager) {

+		super("Merge workflow");

+		this.editManager = editManager;

+		this.fileManager = fileManager;

+		this.menuManager = menuManager;

+		this.colourManager = colourManager;

+		this.workbenchConfiguration = workbenchConfiguration;

+		this.selectionManager = selectionManager;

+	}

+

+	public void actionPerformed(ActionEvent e) {

+		final Component parentComponent;

+		if (e.getSource() instanceof Component) {

+			parentComponent = (Component) e.getSource();

+		} else {

+			parentComponent = null;

+		}

+		ImportWorkflowWizard wizard = new ImportWorkflowWizard(

+				Utils.getParentFrame(parentComponent), editManager, fileManager, menuManager,

+				colourManager, workbenchConfiguration, selectionManager);

+		wizard.setNestedEnabled(false);

+		wizard.setVisible(true);

+	}

+

+}

diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/OpenSourceWorkflowAction.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/OpenSourceWorkflowAction.java
new file mode 100644
index 0000000..f392405
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/OpenSourceWorkflowAction.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (C) 2013 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.importworkflow.actions;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.prefs.Preferences;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+import javax.swing.filechooser.FileFilter;
+
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.icons.WorkbenchIcons;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author David Withers
+ */
+@SuppressWarnings("serial")
+public abstract class OpenSourceWorkflowAction extends AbstractAction {
+
+	private static Logger logger = Logger.getLogger(OpenSourceWorkflowAction.class);
+
+	private static final String OPEN_WORKFLOW = "Open workflow...";
+
+	protected FileManager fileManager;
+
+	public OpenSourceWorkflowAction(FileManager fileManager) {
+		super(OPEN_WORKFLOW, WorkbenchIcons.openIcon);
+		this.fileManager = fileManager;
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		final Component parentComponent;
+		if (e.getSource() instanceof Component) {
+			parentComponent = (Component) e.getSource();
+		} else {
+			parentComponent = null;
+		}
+		openWorkflows(parentComponent);
+	}
+
+	public abstract void openWorkflows(Component parentComponent, File[] files);
+
+	/**
+	 * Pop up an Open-dialogue to select one or more workflow files to open.
+	 *
+	 * @param parentComponent
+	 *            The UI parent component to use for pop up dialogues
+	 * @param openCallback
+	 *            An {@link OpenCallback} to be called during the file opening.
+	 *            The callback will be invoked for each file that has been
+	 *            opened, as file opening happens in a separate thread that
+	 *            might execute after the return of this method.
+	 * @return <code>false</code> if no files were selected or the dialogue was
+	 *         cancelled, or <code>true</code> if the process of opening one or
+	 *         more files has been started.
+	 */
+	public boolean openWorkflows(final Component parentComponent) {
+		JFileChooser fileChooser = new JFileChooser();
+		Preferences prefs = Preferences.userNodeForPackage(getClass());
+		String curDir = prefs.get("currentDir", System.getProperty("user.home"));
+		fileChooser.setDialogTitle(OPEN_WORKFLOW);
+
+		fileChooser.resetChoosableFileFilters();
+		fileChooser.setAcceptAllFileFilterUsed(false);
+		List<FileFilter> fileFilters = fileManager.getOpenFileFilters();
+		if (fileFilters.isEmpty()) {
+			logger.warn("No file types found for opening workflow");
+			JOptionPane
+					.showMessageDialog(parentComponent,
+							"No file types found for opening workflow.", "Error",
+							JOptionPane.ERROR_MESSAGE);
+			return false;
+		}
+		for (FileFilter fileFilter : fileFilters) {
+			fileChooser.addChoosableFileFilter(fileFilter);
+		}
+
+		fileChooser.setFileFilter(fileFilters.get(0));
+
+		fileChooser.setCurrentDirectory(new File(curDir));
+		fileChooser.setMultiSelectionEnabled(true);
+
+		int returnVal = fileChooser.showOpenDialog(parentComponent);
+		if (returnVal == JFileChooser.APPROVE_OPTION) {
+			prefs.put("currentDir", fileChooser.getCurrentDirectory().toString());
+			final File[] selectedFiles = fileChooser.getSelectedFiles();
+			if (selectedFiles.length == 0) {
+				logger.warn("No files selected");
+				return false;
+			}
+			new FileOpenerThread(parentComponent, selectedFiles).start();
+			return true;
+		}
+		return false;
+	}
+
+	private final class FileOpenerThread extends Thread {
+		private final File[] files;
+		private final Component parentComponent;
+
+		private FileOpenerThread(Component parentComponent, File[] selectedFiles) {
+			super("Opening workflows(s) " + Arrays.asList(selectedFiles));
+			this.parentComponent = parentComponent;
+			this.files = selectedFiles;
+		}
+
+		@Override
+		public void run() {
+			openWorkflows(parentComponent, files);
+		}
+	}
+
+}
diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/ReplaceNestedWorkflowAction.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/ReplaceNestedWorkflowAction.java
new file mode 100644
index 0000000..9199ab5
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/actions/ReplaceNestedWorkflowAction.java
@@ -0,0 +1,84 @@
+package net.sf.taverna.t2.workbench.file.importworkflow.actions;

+

+import java.awt.Component;

+import java.awt.event.ActionEvent;

+

+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;

+import net.sf.taverna.t2.ui.menu.MenuManager;

+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;

+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;

+import net.sf.taverna.t2.workbench.configuration.workbench.WorkbenchConfiguration;

+import net.sf.taverna.t2.workbench.edits.Edit;

+import net.sf.taverna.t2.workbench.edits.EditManager;

+import net.sf.taverna.t2.workbench.file.FileManager;

+import net.sf.taverna.t2.workbench.file.importworkflow.gui.ImportWorkflowWizard;

+import net.sf.taverna.t2.workbench.selection.SelectionManager;

+import net.sf.taverna.t2.workbench.ui.Utils;

+import net.sf.taverna.t2.workbench.ui.actions.activity.ActivityConfigurationAction;

+import net.sf.taverna.t2.workflow.edits.ConfigureEdit;

+import uk.org.taverna.scufl2.api.activity.Activity;

+import uk.org.taverna.scufl2.api.configurations.Configuration;

+import uk.org.taverna.scufl2.api.core.Workflow;

+

+public class ReplaceNestedWorkflowAction extends ActivityConfigurationAction {

+	private static final long serialVersionUID = 1L;

+

+	private final EditManager editManager;

+	private final FileManager fileManager;

+	private final MenuManager menuManager;

+

+	private final ColourManager colourManager;

+

+	private final WorkbenchConfiguration workbenchConfiguration;

+

+	private final SelectionManager selectionManager;

+

+	public ReplaceNestedWorkflowAction(Activity activity, EditManager editManager,

+			FileManager fileManager, MenuManager menuManager,

+			ActivityIconManager activityIconManager, ColourManager colourManager,

+			ServiceDescriptionRegistry serviceDescriptionRegistry,

+			WorkbenchConfiguration workbenchConfiguration, SelectionManager selectionManager) {

+		super(activity, activityIconManager, serviceDescriptionRegistry);

+		this.editManager = editManager;

+		this.fileManager = fileManager;

+		this.menuManager = menuManager;

+		this.colourManager = colourManager;

+		this.workbenchConfiguration = workbenchConfiguration;

+		this.selectionManager = selectionManager;

+		putValue(NAME, "Replace nested workflow");

+	}

+

+	public void actionPerformed(ActionEvent e) {

+		final Component parentComponent;

+		if (e.getSource() instanceof Component) {

+			parentComponent = (Component) e.getSource();

+		} else {

+			parentComponent = null;

+		}

+		ImportWorkflowWizard wizard = new ImportWorkflowWizard(

+				Utils.getParentFrame(parentComponent), editManager, fileManager, menuManager,

+				colourManager, workbenchConfiguration, selectionManager) {

+			private static final long serialVersionUID = 1L;

+

+//			@Override

+//			protected Edit<?> makeInsertNestedWorkflowEdit(Workflow nestedFlow, String name) {

+//				Configuration configuration = new Configuration();

+//				configuration.setType(null);

+//				// TODO use service registry

+//				return new ConfigureEdit<Activity>(getActivity(), null, configuration);

+//			}

+

+//			@Override

+//			protected Activity getInsertedActivity() {

+//				return getActivity();

+//			}

+		};

+

+		wizard.setMergeEnabled(false);

+//		wizard.setCustomDestinationDataflow(fileManager.getCurrentDataflow(),

+//				"Existing nested workflow");

+//		wizard.setDestinationEnabled(false);

+		wizard.setVisible(true);

+	}

+

+}

diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/gui/ImportWorkflowWizard.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/gui/ImportWorkflowWizard.java
new file mode 100644
index 0000000..b8ddf1a
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/gui/ImportWorkflowWizard.java
@@ -0,0 +1,1272 @@
+package net.sf.taverna.t2.workbench.file.importworkflow.gui;

+

+import java.awt.BorderLayout;

+import java.awt.Color;

+import java.awt.Component;

+import java.awt.Container;

+import java.awt.Frame;

+import java.awt.GridBagConstraints;

+import java.awt.GridBagLayout;

+import java.awt.event.ActionEvent;

+import java.awt.event.ActionListener;

+import java.awt.event.FocusAdapter;

+import java.awt.event.FocusEvent;

+import java.awt.event.ItemEvent;

+import java.awt.event.ItemListener;

+import java.io.File;

+import java.lang.reflect.InvocationTargetException;

+import java.net.MalformedURLException;

+import java.net.URL;

+import java.util.ArrayList;

+import java.util.HashSet;

+import java.util.List;

+import java.util.Set;

+

+import javax.swing.AbstractAction;

+import javax.swing.BorderFactory;

+import javax.swing.ButtonGroup;

+import javax.swing.ButtonModel;

+import javax.swing.JButton;

+import javax.swing.JComboBox;

+import javax.swing.JLabel;

+import javax.swing.JOptionPane;

+import javax.swing.JPanel;

+import javax.swing.JRadioButton;

+import javax.swing.JTextField;

+import javax.swing.ProgressMonitor;

+import javax.swing.SwingUtilities;

+

+import net.sf.taverna.t2.activities.dataflow.servicedescriptions.DataflowTemplateService;

+import net.sf.taverna.t2.ui.menu.MenuManager;

+import net.sf.taverna.t2.workbench.MainWindow;

+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;

+import net.sf.taverna.t2.workbench.configuration.workbench.WorkbenchConfiguration;

+import net.sf.taverna.t2.workbench.edits.CompoundEdit;

+import net.sf.taverna.t2.workbench.edits.Edit;

+import net.sf.taverna.t2.workbench.edits.EditException;

+import net.sf.taverna.t2.workbench.edits.EditManager;

+import net.sf.taverna.t2.workbench.file.DataflowInfo;

+import net.sf.taverna.t2.workbench.file.FileManager;

+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;

+import net.sf.taverna.t2.workbench.file.importworkflow.DataflowMerger;

+import net.sf.taverna.t2.workbench.file.importworkflow.MergeException;

+import net.sf.taverna.t2.workbench.file.importworkflow.actions.OpenSourceWorkflowAction;

+import net.sf.taverna.t2.workbench.helper.HelpEnabledDialog;

+import net.sf.taverna.t2.workbench.models.graph.svg.SVGGraphController;

+import net.sf.taverna.t2.workbench.selection.SelectionManager;

+import net.sf.taverna.t2.workflow.edits.AddChildEdit;

+import net.sf.taverna.t2.workflow.edits.AddProcessorEdit;

+

+import org.apache.batik.swing.JSVGCanvas;

+import org.apache.log4j.Logger;

+

+import uk.org.taverna.scufl2.api.activity.Activity;

+import uk.org.taverna.scufl2.api.common.Scufl2Tools;

+import uk.org.taverna.scufl2.api.configurations.Configuration;

+import uk.org.taverna.scufl2.api.container.WorkflowBundle;

+import uk.org.taverna.scufl2.api.core.Processor;

+import uk.org.taverna.scufl2.api.core.Workflow;

+import uk.org.taverna.scufl2.api.iterationstrategy.CrossProduct;

+import uk.org.taverna.scufl2.api.port.InputActivityPort;

+import uk.org.taverna.scufl2.api.port.InputProcessorPort;

+import uk.org.taverna.scufl2.api.port.InputWorkflowPort;

+import uk.org.taverna.scufl2.api.port.OutputActivityPort;

+import uk.org.taverna.scufl2.api.port.OutputProcessorPort;

+import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;

+import uk.org.taverna.scufl2.api.profiles.ProcessorBinding;

+import uk.org.taverna.scufl2.api.profiles.ProcessorInputPortBinding;

+import uk.org.taverna.scufl2.api.profiles.ProcessorOutputPortBinding;

+import uk.org.taverna.scufl2.api.profiles.Profile;

+

+import com.fasterxml.jackson.databind.node.ObjectNode;

+

+@SuppressWarnings("serial")

+public class ImportWorkflowWizard extends HelpEnabledDialog {

+

+	private static Logger logger = Logger.getLogger(ImportWorkflowWizard.class);

+

+	private Scufl2Tools scufl2Tools = new Scufl2Tools();

+

+	protected BrowseFileOnClick browseFileOnClick = new BrowseFileOnClick();

+	protected JButton buttonBrowse;

+	protected JComboBox chooseDataflow;

+	protected DataflowOpenerThread dataflowOpenerThread;

+

+	private WorkflowBundle destinationWorkflowBundle;

+	private Workflow destinationWorkflow;

+	private Profile destinationProfile;

+	private Workflow sourceWorkflow;

+

+	protected JTextField fieldFile;

+

+	protected JTextField fieldUrl;

+	protected boolean mergeEnabled = true;

+	protected boolean nestedEnabled = true;

+	protected JSVGCanvas previewSource = new JSVGCanvas(null, false, false);

+	protected JSVGCanvas previewDestination = new JSVGCanvas(null, false, false);

+	protected JTextField prefixField;

+	protected JRadioButton radioFile;

+	protected JRadioButton radioNew;

+	protected JRadioButton radioOpened;

+	protected JRadioButton radioUrl;

+	protected ButtonGroup sourceSelection;

+	protected ActionListener updateChosenListener = new UpdateChosenListener();

+	protected Thread updatePreviewsThread;

+	protected Component sourceSelectionPanel;

+	protected JLabel prefixLabel;

+	protected JLabel prefixHelp;

+//	protected JPanel destinationSelectionPanel;

+//	protected ButtonGroup destinationSelection;

+//	protected JRadioButton radioNewDestination;

+//	protected JRadioButton radioOpenDestination;

+//	protected JComboBox destinationAlreadyOpen;

+	protected JPanel introductionPanel;

+	protected ButtonGroup actionSelection;

+	protected JRadioButton actionNested;

+	protected JRadioButton actionMerge;

+	protected JRadioButton radioCustomSource;

+	protected JRadioButton radioCustomDestination;

+

+	private final EditManager editManager;

+	private final FileManager fileManager;

+	private final MenuManager menuManager;

+	private final ColourManager colourManager;

+	private final WorkbenchConfiguration workbenchConfiguration;

+	private final SelectionManager selectionManager;

+

+	private WorkflowBundle customSourceDataFlow = null;

+//	private Workflow customDestinationDataflow = null;

+	private String customSourceName = "";

+//	private String customDestinationName = "";

+

+	private boolean sourceEnabled = true;

+//	private boolean destinationEnabled = true;

+	private Activity insertedActivity;

+

+	public ImportWorkflowWizard(Frame parentFrame, EditManager editManager,

+			FileManager fileManager, MenuManager menuManager, ColourManager colourManager,

+			WorkbenchConfiguration workbenchConfiguration, SelectionManager selectionManager) {

+		super(parentFrame, "Import workflow", true, null);

+		this.selectionManager = selectionManager;

+		destinationWorkflow = selectionManager.getSelectedWorkflow();

+		destinationProfile = selectionManager.getSelectedProfile();

+		destinationWorkflowBundle = selectionManager.getSelectedWorkflowBundle();

+

+		this.editManager = editManager;

+		this.fileManager = fileManager;

+		this.menuManager = menuManager;

+		this.colourManager = colourManager;

+		this.workbenchConfiguration = workbenchConfiguration;

+

+		setSize(600, 600);

+		add(makeContentPane(), BorderLayout.CENTER);

+		// Add some space

+		add(new JPanel(), BorderLayout.WEST);

+		add(new JPanel(), BorderLayout.NORTH);

+		add(new JPanel(), BorderLayout.SOUTH);

+		add(new JPanel(), BorderLayout.EAST);

+		findChosenDataflow(this, true);

+		updateAll();

+	}

+

+	public void setMergeEnabled(boolean importEnabled) {

+		this.mergeEnabled = importEnabled;

+		updateAll();

+	}

+

+	public void setNestedEnabled(boolean nestedEnabled) {

+		this.nestedEnabled = nestedEnabled;

+		updateAll();

+	}

+

+	/**

+	 * Silly workaround to avoid "Cannot call invokeAndWait from the event dispatcher thread"

+	 * exception.

+	 *

+	 * @param runnable

+	 */

+	public static void invokeAndWait(Runnable runnable) {

+		if (SwingUtilities.isEventDispatchThread()) {

+			runnable.run();

+			return;

+		}

+		try {

+			SwingUtilities.invokeAndWait(runnable);

+		} catch (InterruptedException ex) {

+			// logger.warn("Runnable " + runnable + " was interrupted " + runnable, ex);

+		} catch (InvocationTargetException e) {

+			logger.warn("Can't invoke " + runnable, e);

+		}

+	}

+

+	protected Component makeWorkflowImage() {

+		JPanel workflowImages = new JPanel(new GridBagLayout());

+		GridBagConstraints gbc = new GridBagConstraints();

+		gbc.gridy = 0;

+		gbc.fill = GridBagConstraints.BOTH;

+		gbc.weighty = 0.1;

+

+		gbc.weightx = 0.1;

+		workflowImages.add(new JPanel(), gbc);// filler

+

+		gbc.weightx = 0.0;

+		previewSource.setBackground(workflowImages.getBackground());

+		workflowImages.add(previewSource, gbc);

+

+		JLabel arrow = new JLabel("\u2192");

+		arrow.setFont(arrow.getFont().deriveFont(48f));

+		workflowImages.add(arrow, gbc);

+

+		previewDestination.setBackground(workflowImages.getBackground());

+		workflowImages.add(previewDestination, gbc);

+

+		gbc.weightx = 0.1;

+		workflowImages.add(new JPanel(), gbc);

+		gbc.weightx = 0.0;

+

+		return workflowImages;

+	}

+

+	protected void updateAll() {

+		updatePreviews(); // will go in separate thread anyway, do it first

+		updateHeader();

+		updateSourceSection();

+//		updateDestinationSection();

+		updateFooter();

+	}

+

+//	protected void updateDestinationSection() {

+//

+//		radioNewDestination.setVisible(false);

+//

+//		radioCustomDestination.setText(customDestinationName);

+//		radioCustomDestination.setVisible(customDestinationDataflow != null);

+//

+//		// radioNewDestination.setVisible(nestedEnabled);

+//		// radioNewDestination.setEnabled(actionNested.isSelected());

+//

+//		destinationSelectionPanel.setVisible(destinationEnabled);

+//

+//	}

+

+	protected synchronized void updatePreviews() {

+		if (updatePreviewsThread != null && updatePreviewsThread.isAlive()) {

+			updatePreviewsThread.interrupt();

+		}

+		updatePreviewsThread = new UpdatePreviewsThread();

+		updatePreviewsThread.start();

+	}

+

+	protected void updateDestinationPreview() {

+		updateWorkflowGraphic(previewDestination, destinationWorkflow, destinationProfile);

+	}

+

+	protected void updateSourcePreview() {

+		Profile sourceProfile = null;

+		if (sourceWorkflow != null) {

+			sourceProfile = sourceWorkflow.getParent().getMainProfile();

+		}

+		updateWorkflowGraphic(previewSource, sourceWorkflow, sourceProfile);

+	}

+

+	protected void updateFooter() {

+		prefixField.setVisible(mergeEnabled);

+		prefixLabel.setVisible(mergeEnabled);

+		prefixHelp.setVisible(mergeEnabled);

+

+		prefixField.setEnabled(actionMerge.isSelected());

+		prefixLabel.setEnabled(actionMerge.isSelected());

+		prefixHelp.setEnabled(actionMerge.isSelected());

+		if (actionMerge.isSelected()) {

+			prefixHelp.setForeground(prefixLabel.getForeground());

+		} else {

+			// Work around

+			// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4303706

+			// and assume gray is the 'disabled' colour in our Look n Feel

+			prefixHelp.setForeground(Color.gray);

+		}

+

+	}

+

+	protected void updateHeader() {

+		makeIntroductionPanel();

+	}

+

+	protected void updateSourceSection() {

+		radioCustomSource.setText(customSourceName);

+		radioCustomSource.setVisible(customSourceDataFlow != null);

+

+		radioNew.setVisible(nestedEnabled);

+		radioNew.setEnabled(actionNested.isSelected());

+

+		if (actionNested.isSelected() && sourceSelection.getSelection() == null) {

+			// Preselect the new workflow

+			radioNew.setSelected(true);

+		}

+

+		sourceSelectionPanel.setVisible(sourceEnabled);

+	}

+

+	/**

+	 * Create a PNG image of the workflow and place inside an ImageIcon

+	 *

+	 * @param dataflow

+	 * @return

+	 * @throws InvocationTargetException

+	 * @throws InterruptedException

+	 */

+	protected void updateWorkflowGraphic(final JSVGCanvas svgCanvas, final Workflow workflow, final Profile profile) {

+		try {

+			SwingUtilities.invokeAndWait(new Runnable() {

+				public void run() {

+					// Set it to blank while reloading

+					svgCanvas.setSVGDocument(null);

+					if (workflow != null) {

+						SVGGraphController currentWfGraphController = new SVGGraphController(

+								workflow, profile, false, svgCanvas,

+								editManager, menuManager, colourManager, workbenchConfiguration);

+					}

+				}

+			});

+		} catch (InterruptedException e) {

+			// logger.error(e);

+		} catch (InvocationTargetException e) {

+			// logger.error(e);

+		}

+	}

+

+	/**

+	 * Open the selected source and destination workflows. If background is true, this method will

+	 * return immediately while a {@link DataflowOpenerThread} performs the updates. If a

+	 * DataflowOpenerThread is already running, it will be interrupted and stopped.

+	 *

+	 * @param parentComponent

+	 *            The parent component for showing dialogues

+	 * @param background

+	 *            If true, will run in separate thread.

+	 * @return <code>false</code> if running in the background, or if a dialogue was shown and the

+	 *         operation is aborted by the user, or <code>true</code> if not running in the

+	 *         background and the method completed without user interruption.

+	 */

+	protected synchronized boolean findChosenDataflow(Component parentComponent, boolean background) {

+		if (dataflowOpenerThread != null && dataflowOpenerThread.isAlive()) {

+			if (background) {

+				// We've changed our mind

+				dataflowOpenerThread.interrupt();

+			} else {

+				// We'll let it finish, we don't need to do it again

+				try {

+					dataflowOpenerThread.join();

+				} catch (InterruptedException e) {

+					Thread.currentThread().interrupt();

+				}

+				return !dataflowOpenerThread.shownWarning;

+			}

+		}

+		dataflowOpenerThread = new DataflowOpenerThread(parentComponent, background);

+

+		if (background) {

+			dataflowOpenerThread.start();

+			return false;

+		} else {

+			dataflowOpenerThread.run();

+			return !dataflowOpenerThread.shownWarning;

+		}

+

+	}

+

+	protected Container makeContentPane() {

+		JPanel panel = new JPanel(new GridBagLayout());

+		GridBagConstraints gbc = new GridBagConstraints();

+

+		gbc.ipadx = 5;

+		gbc.ipady = 5;

+

+		gbc.gridx = 0;

+		gbc.weightx = 0.1;

+		gbc.fill = GridBagConstraints.BOTH;

+

+		introductionPanel = makeIntroductionPanel();

+		panel.add(introductionPanel, gbc);

+

+		sourceSelectionPanel = makeSourceSelectionPanel();

+		panel.add(sourceSelectionPanel, gbc);

+

+//		destinationSelectionPanel = makeDestinationSelectionPanel();

+//		panel.add(destinationSelectionPanel, gbc);

+

+		gbc.weighty = 0.1;

+		panel.add(makeImportStylePanel(), gbc);

+

+		return panel;

+	}

+

+	protected JPanel makeIntroductionPanel() {

+		if (introductionPanel == null) {

+			introductionPanel = new JPanel(new GridBagLayout());

+		} else {

+			introductionPanel.removeAll();

+		}

+		boolean bothEnabled = mergeEnabled && nestedEnabled;

+		if (bothEnabled) {

+			introductionPanel.setBorder(BorderFactory.createTitledBorder("Import method"));

+		} else {

+			introductionPanel.setBorder(BorderFactory.createEmptyBorder());

+		}

+		GridBagConstraints gbc = new GridBagConstraints();

+		gbc.gridx = 0;

+		// gbc.gridy = 0;

+		gbc.weightx = 0.1;

+		gbc.fill = GridBagConstraints.BOTH;

+		gbc.anchor = GridBagConstraints.FIRST_LINE_START;

+

+		StringBuilder nestedHelp = new StringBuilder();

+		nestedHelp.append("<html><small>");

+		nestedHelp.append("Add a <strong>nested workflow</strong> ");

+		nestedHelp.append("into the ");

+		nestedHelp.append("destination workflow as a single service. ");

+		nestedHelp.append("The nested workflow ");

+		nestedHelp.append("can be <em>edited separately</em>, but is shown ");

+		nestedHelp.append("expanded in the diagram of the parent  ");

+		nestedHelp.append("workflow. In the parent workflow you can ");

+		nestedHelp.append("connect to the input and output ports of the nested ");

+		nestedHelp.append("workflow. ");

+		nestedHelp.append("</small></html>");

+

+		StringBuilder mergeHelp = new StringBuilder();

+		mergeHelp.append("<html><small>");

+		mergeHelp.append("<strong>Merge</strong> a workflow ");

+		mergeHelp.append("by copying all services, ports and links ");

+		mergeHelp.append("directly into the destination workflow. This can be  ");

+		mergeHelp.append("useful for merging smaller workflow fragments. For ");

+		mergeHelp.append("inclusion of larger workflows you might find using ");

+		mergeHelp.append("<em>nested workflows</em> more beneficial.");

+		mergeHelp.append("</small></html>");

+

+		actionSelection = new ButtonGroup();

+		actionNested = new JRadioButton(nestedHelp.toString());

+		ActionListener updateListener = new ActionListener() {

+			public void actionPerformed(ActionEvent e) {

+				updateSourceSection();

+//				updateDestinationSection();

+				updateFooter();

+			}

+		};

+		actionNested.addActionListener(updateListener);

+		actionSelection.add(actionNested);

+

+		actionMerge = new JRadioButton(mergeHelp.toString());

+		actionMerge.addActionListener(updateListener);

+		actionSelection.add(actionMerge);

+

+		if (bothEnabled) {

+			introductionPanel.add(actionNested, gbc);

+			introductionPanel.add(actionMerge, gbc);

+			actionNested.setSelected(true);

+		} else if (nestedEnabled) {

+			introductionPanel.add(new JLabel(nestedHelp.toString()), gbc);

+			actionNested.setSelected(true);

+		} else if (mergeEnabled) {

+			introductionPanel.add(new JLabel(mergeHelp.toString()), gbc);

+			actionMerge.setSelected(true);

+		}

+		return introductionPanel;

+	}

+

+//	protected JPanel makeDestinationSelectionPanel() {

+//		JPanel j = new JPanel(new GridBagLayout());

+//		j.setBorder(BorderFactory.createTitledBorder("Workflow destination"));

+//

+//		GridBagConstraints gbc = new GridBagConstraints();

+//		gbc.gridx = 0;

+//		gbc.gridy = 0;

+//		gbc.fill = GridBagConstraints.BOTH;

+//

+//		destinationSelection = new ButtonGroup();

+//		radioNewDestination = new JRadioButton("New workflow");

+//		gbc.gridy = 0;

+//		j.add(radioNewDestination, gbc);

+//		destinationSelection.add(radioNewDestination);

+//		radioNewDestination.addActionListener(updateChosenListener);

+//

+//		radioOpenDestination = new JRadioButton("Already opened workflow");

+//		gbc.gridy = 2;

+//		j.add(radioOpenDestination, gbc);

+//		destinationSelection.add(radioOpenDestination);

+//		radioOpenDestination.addActionListener(updateChosenListener);

+//		gbc.weightx = 0.1;

+//		gbc.gridx = 1;

+//		destinationAlreadyOpen = makeSelectOpenWorkflowComboBox(true);

+//		j.add(destinationAlreadyOpen, gbc);

+//

+//		radioCustomDestination = new JRadioButton(customDestinationName);

+//		radioCustomDestination.setVisible(customDestinationName != null);

+//		gbc.gridx = 0;

+//		gbc.gridy = 3;

+//		gbc.gridwidth = 2;

+//		j.add(radioCustomDestination, gbc);

+//		destinationSelection.add(radioCustomDestination);

+//		radioCustomDestination.addActionListener(updateChosenListener);

+//		gbc.gridwidth = 1;

+//

+//		radioOpenDestination.setSelected(true);

+//		return j;

+//	}

+

+	protected Component makeImportStylePanel() {

+		JPanel j = new JPanel(new GridBagLayout());

+		GridBagConstraints gbc = new GridBagConstraints();

+		gbc.gridx = 0;

+		gbc.gridy = 0;

+		gbc.fill = GridBagConstraints.BOTH;

+

+		j.setBorder(BorderFactory.createTitledBorder("Import"));

+

+		prefixLabel = new JLabel("Prefix");

+		j.add(prefixLabel, gbc);

+		gbc.weightx = 0.1;

+		gbc.gridx = 1;

+

+		prefixField = new JTextField(10);

+		prefixLabel.setLabelFor(prefixField);

+		j.add(prefixField, gbc);

+

+		gbc.gridx = 0;

+		gbc.gridy = 1;

+		gbc.gridwidth = 2;

+

+		prefixHelp = new JLabel(

+				"<html><small>Optional prefix to be prepended to the name of the "

+						+ "inserted services and workflow ports. Even if no prefix is given, duplicate names will be "

+						+ "resolved by adding numbers, for instance <code>my_service_2</code> if <code>my_service</code> already "

+						+ "existed." + "</small></html>");

+		prefixHelp.setLabelFor(prefixField);

+		j.add(prefixHelp, gbc);

+

+		gbc.gridy = 2;

+		gbc.weightx = 0.1;

+		gbc.weighty = 0.1;

+

+		j.add(makeWorkflowImage(), gbc);

+

+		gbc.gridy = 3;

+		gbc.weighty = 0.0;

+		j.add(new JPanel(), gbc);

+

+		gbc.gridy = 4;

+		gbc.fill = GridBagConstraints.NONE;

+		JButton comp = new JButton(new ImportWorkflowAction());

+		j.add(comp, gbc);

+		return j;

+

+	}

+

+	protected Component makeSelectFile() {

+		JPanel j = new JPanel(new GridBagLayout());

+		j.setBorder(BorderFactory.createEtchedBorder());

+

+		GridBagConstraints gbc = new GridBagConstraints();

+		gbc.gridx = 0;

+		gbc.gridy = 0;

+		gbc.fill = GridBagConstraints.BOTH;

+		gbc.weightx = 0.1;

+

+		fieldFile = new JTextField(20);

+		fieldFile.setEditable(false);

+		fieldFile.addFocusListener(new FocusAdapter() {

+			public void focusGained(FocusEvent e) {

+				radioFile.setSelected(true);

+			}

+

+			@Override

+			public void focusLost(FocusEvent e) {

+				findChosenDataflow(e.getComponent(), true);

+			}

+		});

+		j.add(fieldFile, gbc);

+		radioFile.addItemListener(new ItemListener() {

+

+			public void itemStateChanged(ItemEvent e) {

+				if (e.getStateChange() == ItemEvent.SELECTED) {

+					browseFileOnClick.checkEmptyFile();

+				}

+			}

+		});

+

+		gbc.gridx = 1;

+		gbc.weightx = 0.0;

+		gbc.fill = GridBagConstraints.NONE;

+		buttonBrowse = new JButton(new OpenSourceWorkflowAction(fileManager) {

+			@Override

+			public void openWorkflows(Component parentComponent, File[] files) {

+				if (files.length == 0) {

+					radioFile.setSelected(false);

+					fieldFile.setText("");

+					radioFile.requestFocus();

+					return;

+				}

+				fieldFile.setText(files[0].getPath());

+				if (!radioFile.isSelected()) {

+					radioFile.setSelected(true);

+				}

+				findChosenDataflow(parentComponent, true);

+			}

+		});

+		buttonBrowse.setText("Browse");

+		j.add(buttonBrowse, gbc);

+

+		// This just duplicates things - we already have actions on

+		// the radioFile and fieldFile that will handle the events

+		// radioFile.addActionListener(browseFileOnClick);

+		// fieldFile.addActionListener(browseFileOnClick);

+		return j;

+	}

+

+	protected JComboBox makeSelectOpenWorkflowComboBox(boolean selectCurrent) {

+		List<DataflowSelection> openDataflows = new ArrayList<DataflowSelection>();

+		DataflowSelection current = null;

+		for (WorkflowBundle df : fileManager.getOpenDataflows()) {

+			String name = df.getMainWorkflow().getName();

+			boolean isCurrent = df.equals(fileManager.getCurrentDataflow());

+			if (isCurrent) {

+				// Wrapping as HTML causes weird drop-down box under MAC, so

+				// we just use normal text

+				// name = "<html><body>" + name

+				// + " <i>(current)</i></body></html>";

+				name = name + " (current)";

+			}

+			DataflowSelection selection = new DataflowSelection(df, name);

+			openDataflows.add(selection);

+			if (isCurrent) {

+				current = selection;

+			}

+		}

+		JComboBox chooseDataflow = new JComboBox(openDataflows.toArray());

+		if (selectCurrent) {

+			chooseDataflow.setSelectedItem(current);

+		}

+		chooseDataflow.addActionListener(updateChosenListener);

+		return chooseDataflow;

+

+	}

+

+	protected Component makeSourceSelectionPanel() {

+		JPanel j = new JPanel(new GridBagLayout());

+		j.setBorder(BorderFactory.createTitledBorder("Workflow source"));

+

+		GridBagConstraints gbc = new GridBagConstraints();

+		gbc.gridx = 0;

+		gbc.gridy = 0;

+		gbc.fill = GridBagConstraints.BOTH;

+

+		sourceSelection = new ButtonGroup();

+		radioNew = new JRadioButton("New workflow");

+		gbc.gridy = 0;

+		j.add(radioNew, gbc);

+		sourceSelection.add(radioNew);

+

+		radioNew.addActionListener(updateChosenListener);

+

+		radioFile = new JRadioButton("Import from file");

+		gbc.gridy = 1;

+		j.add(radioFile, gbc);

+		sourceSelection.add(radioFile);

+		radioFile.addActionListener(updateChosenListener);

+

+		radioUrl = new JRadioButton("Import from URL");

+		gbc.gridy = 2;

+		j.add(radioUrl, gbc);

+		sourceSelection.add(radioUrl);

+		radioUrl.addActionListener(updateChosenListener);

+

+		radioOpened = new JRadioButton("Already opened workflow");

+		gbc.gridy = 3;

+		j.add(radioOpened, gbc);

+		sourceSelection.add(radioOpened);

+		radioOpened.addActionListener(updateChosenListener);

+

+		radioCustomSource = new JRadioButton(customSourceName);

+		radioCustomSource.setVisible(customSourceDataFlow != null);

+		gbc.gridy = 4;

+		gbc.gridwidth = 2;

+		j.add(radioCustomSource, gbc);

+		sourceSelection.add(radioCustomSource);

+		radioCustomSource.addActionListener(updateChosenListener);

+		gbc.gridwidth = 1;

+

+		gbc.gridx = 1;

+		gbc.gridy = 1;

+		gbc.weightx = 0.1;

+		j.add(makeSelectFile(), gbc);

+

+		gbc.gridy = 2;

+		fieldUrl = new JTextField(20);

+		j.add(fieldUrl, gbc);

+		fieldUrl.addFocusListener(new FocusAdapter() {

+			@Override

+			public void focusGained(FocusEvent e) {

+				radioUrl.setSelected(true);

+			}

+

+			@Override

+			public void focusLost(FocusEvent e) {

+				findChosenDataflow(e.getComponent(), true);

+			}

+		});

+

+		gbc.gridy = 3;

+		chooseDataflow = makeSelectOpenWorkflowComboBox(false);

+		chooseDataflow.addFocusListener(new FocusAdapter() {

+			@Override

+			public void focusGained(FocusEvent e) {

+				radioOpened.setSelected(true);

+			}

+		});

+		j.add(chooseDataflow, gbc);

+

+		return j;

+	}

+

+	protected Edit<?> makeInsertNestedWorkflowEdit(Workflow nestedFlow) {

+		Processor processor = new Processor();

+		processor.setName("nestedWorkflow");

+

+		CrossProduct crossProduct = new CrossProduct();

+		crossProduct.setParent(processor.getIterationStrategyStack());

+

+		Activity activity = new Activity();

+		activity.setType(DataflowTemplateService.ACTIVITY_TYPE);

+		Configuration configuration = new Configuration();

+		configuration.setType(DataflowTemplateService.ACTIVITY_TYPE.resolve("#Config"));

+		destinationWorkflowBundle.getWorkflows().addWithUniqueName(nestedFlow);

+		((ObjectNode) configuration.getJson()).put("nestedWorkflow", nestedFlow.getName());

+		destinationWorkflowBundle.getWorkflows().remove(nestedFlow);

+		configuration.setConfigures(activity);

+

+		ProcessorBinding processorBinding = new ProcessorBinding();

+		processorBinding.setBoundProcessor(processor);

+		processorBinding.setBoundActivity(activity);

+

+		for (InputWorkflowPort workflowPort : nestedFlow.getInputPorts()) {

+			InputActivityPort activityPort = new InputActivityPort(activity, workflowPort.getName());

+			activityPort.setDepth(workflowPort.getDepth());

+			// create processor port

+			InputProcessorPort processorPort = new InputProcessorPort(processor, activityPort.getName());

+			processorPort.setDepth(activityPort.getDepth());

+			// add a new port binding

+			new ProcessorInputPortBinding(processorBinding, processorPort, activityPort);

+		}

+		for (OutputWorkflowPort workflowPort : nestedFlow.getOutputPorts()) {

+			OutputActivityPort activityPort = new OutputActivityPort(activity, workflowPort.getName());

+			// TODO calculate output depth

+			activityPort.setDepth(0);

+			activityPort.setGranularDepth(0);

+			// create processor port

+			OutputProcessorPort processorPort = new OutputProcessorPort(processor, activityPort.getName());

+			processorPort.setDepth(activityPort.getDepth());

+			processorPort.setGranularDepth(activityPort.getGranularDepth());

+			// add a new port binding

+			new ProcessorOutputPortBinding(processorBinding, activityPort, processorPort);

+		}

+

+		List<Edit<?>> editList = new ArrayList<Edit<?>>();

+		editList.add(new AddChildEdit<Profile>(destinationProfile, activity));

+		editList.add(new AddChildEdit<Profile>(destinationProfile, configuration));

+		editList.add(new AddChildEdit<Profile>(destinationProfile, processorBinding));

+		editList.add(new AddProcessorEdit(destinationWorkflow, processor));

+

+		editList.add(makeInsertWorkflowEdit(nestedFlow, nestedFlow.getParent().getMainProfile()));

+

+		return new CompoundEdit(editList);

+	}

+

+	protected Edit<?> makeInsertWorkflowEdit(Workflow nestedFlow, Profile profile) {

+		return makeInsertWorkflowEdit(nestedFlow, profile, new HashSet<>());

+	}

+

+	protected Edit<?> makeInsertWorkflowEdit(Workflow nestedFlow, Profile profile, Set<Object> seen) {

+		List<Edit<?>> editList = new ArrayList<Edit<?>>();

+		// add the nested workflow to the workflow bundle

+		editList.add(new AddChildEdit<WorkflowBundle>(destinationWorkflowBundle, nestedFlow));

+		seen.add(nestedFlow);

+		for (Processor processor : nestedFlow.getProcessors()) {

+			// add processor bindings to the profile

+			List<ProcessorBinding> processorBindings = scufl2Tools.processorBindingsForProcessor(processor, profile);

+			for (ProcessorBinding processorBinding : processorBindings) {

+				editList.add(new AddChildEdit<Profile>(destinationProfile, processorBinding));

+				// add activity to the profile

+				Activity activity = processorBinding.getBoundActivity();

+				if (!seen.contains(activity)) {

+					editList.add(new AddChildEdit<Profile>(destinationProfile, activity));

+					// add activity configurations to the profile

+					for (Configuration configuration : scufl2Tools.configurationsFor(activity, profile)) {

+						editList.add(new AddChildEdit<Profile>(destinationProfile, configuration));

+					}

+					seen.add(activity);

+				}

+			}

+			// add processor configurations to the profile

+			List<Configuration> configurations = scufl2Tools.configurationsFor(processor, profile);

+			for (Configuration configuration : configurations) {

+				editList.add(new AddChildEdit<Profile>(destinationProfile, configuration));

+			}

+

+			for (Workflow workflow : scufl2Tools.nestedWorkflowsForProcessor(processor, profile)) {

+				if (!seen.contains(workflow)) {

+					// recursively add nested workflows

+					editList.add(makeInsertWorkflowEdit(workflow, profile, seen));

+				}

+			}

+		}

+		return new CompoundEdit(editList);

+	}

+

+//	protected Activity getInsertedActivity() {

+//		return insertedActivity;

+//	}

+

+	protected class ImportWorkflowAction extends AbstractAction implements Runnable {

+		private static final String VALID_NAME_REGEX = "[\\p{L}\\p{Digit}_.]+";

+		private Component parentComponent;

+		private ProgressMonitor progressMonitor;

+

+		protected ImportWorkflowAction() {

+			super("Import workflow");

+		}

+

+		public void actionPerformed(ActionEvent e) {

+			/*

+			 * if (e.getSource() instanceof Component) { parentComponent = (Component)

+			 * e.getSource(); } else { parentComponent = null; }

+			 */

+			parentComponent = MainWindow.getMainWindow();

+			Thread t = new Thread(this, "Import workflow");

+			progressMonitor = new ProgressMonitor(parentComponent, "Importing workflow", "", 0, 100);

+			progressMonitor.setMillisToDecideToPopup(200);

+			progressMonitor.setProgress(5);

+			t.start();

+			setVisible(false);

+		}

+

+		protected void nested() {

+			if (progressMonitor.isCanceled()) {

+				return;

+			}

+			progressMonitor.setProgress(15);

+			selectionManager.setSelectedWorkflowBundle(destinationWorkflowBundle);

+			if (progressMonitor.isCanceled()) {

+				return;

+			}

+

+			progressMonitor.setNote("Copying source workflow");

+			Workflow nestedFlow;

+			try {

+				nestedFlow = DataflowMerger.copyWorkflow(sourceWorkflow);

+			} catch (Exception ex) {

+				logger.warn("Could not copy nested workflow", ex);

+				progressMonitor.setProgress(100);

+				JOptionPane.showMessageDialog(parentComponent,

+						"An error occured while copying workflow:\n" + ex.getLocalizedMessage(),

+						"Could not copy nested workflow", JOptionPane.WARNING_MESSAGE);

+				return;

+			}

+			if (progressMonitor.isCanceled()) {

+				return;

+			}

+

+			progressMonitor.setNote("Creating nested workflow");

+			progressMonitor.setProgress(45);

+

+			Edit<?> edit = makeInsertNestedWorkflowEdit(nestedFlow);

+			if (progressMonitor.isCanceled()) {

+				return;

+			}

+

+			progressMonitor.setNote("Inserting nested workflow");

+			progressMonitor.setProgress(65);

+

+			try {

+				editManager.doDataflowEdit(destinationWorkflowBundle, edit);

+			} catch (EditException e) {

+				progressMonitor.setProgress(100);

+				logger.warn("Could not import nested workflow", e);

+				JOptionPane.showMessageDialog(parentComponent,

+						"An error occured while importing workflow:\n" + e.getLocalizedMessage(),

+						"Could not import workflows", JOptionPane.WARNING_MESSAGE);

+				return;

+			}

+

+			if (radioNew.isSelected()) {

+				progressMonitor.setNote("Opening new nested workflow for editing");

+				progressMonitor.setProgress(90);

+				selectionManager.setSelectedWorkflow(nestedFlow);

+			}

+			progressMonitor.setProgress(100);

+		}

+

+		protected void merge() {

+			progressMonitor.setProgress(10);

+			DataflowMerger merger = new DataflowMerger(destinationWorkflow);

+			progressMonitor.setProgress(25);

+			progressMonitor.setNote("Planning workflow merging");

+

+			String prefix = prefixField.getText();

+			if (!prefix.equals("")) {

+				if (!prefix.matches("[_.]$")) {

+					prefix = prefix + "_";

+				}

+				if (!prefix.matches(VALID_NAME_REGEX)) {

+					progressMonitor.setProgress(100);

+					final String wrongPrefix = prefix;

+					SwingUtilities.invokeLater(new Runnable() {

+						public void run() {

+							JOptionPane.showMessageDialog(parentComponent, "The merge prefix '"

+									+ wrongPrefix + "' is not valid. Try "

+									+ "using only letters, numbers, " + "underscore and dot.",

+									"Invalid merge prefix", JOptionPane.ERROR_MESSAGE);

+							prefixField.requestFocus();

+							ImportWorkflowWizard.this.setVisible(true);

+						}

+					});

+					return;

+				}

+			}

+

+			CompoundEdit mergeEdit;

+			try {

+				mergeEdit = merger.getMergeEdit(ImportWorkflowWizard.this.sourceWorkflow, prefix);

+			} catch (MergeException e1) {

+				progressMonitor.setProgress(100);

+				logger.warn("Could not merge workflow", e1);

+				JOptionPane.showMessageDialog(parentComponent,

+						"An error occured while merging workflows:\n" + e1.getLocalizedMessage(),

+						"Could not merge workflows", JOptionPane.WARNING_MESSAGE);

+				return;

+			}

+

+			progressMonitor.setProgress(55);

+			selectionManager.setSelectedWorkflowBundle(destinationWorkflowBundle);

+

+			progressMonitor.setNote("Merging workflows");

+			progressMonitor.setProgress(75);

+

+			if (progressMonitor.isCanceled()) {

+				return;

+			}

+

+			try {

+				editManager.doDataflowEdit(destinationWorkflowBundle, mergeEdit);

+			} catch (EditException e1) {

+				progressMonitor.setProgress(100);

+				JOptionPane.showMessageDialog(parentComponent,

+						"An error occured while merging workflows:\n" + e1.getLocalizedMessage(),

+						"Could not merge workflows", JOptionPane.WARNING_MESSAGE);

+				return;

+			}

+			progressMonitor.setProgress(100);

+

+		}

+

+		public void run() {

+			boolean completed = findChosenDataflow(parentComponent, false);

+			if (!completed) {

+				return;

+			}

+			if (actionMerge.isSelected()) {

+				merge();

+			} else if (actionNested.isSelected()) {

+				nested();

+			}

+		}

+	}

+

+	protected class UpdatePreviewsThread extends Thread {

+		protected UpdatePreviewsThread() {

+			super("Updating destination previews");

+		}

+

+		public void run() {

+			if (Thread.interrupted()) {

+				return;

+			}

+			updateSourcePreview();

+

+			if (Thread.interrupted()) {

+				return;

+			}

+			updateDestinationPreview();

+		}

+	}

+

+	protected class BrowseFileOnClick implements ActionListener {

+		public void actionPerformed(ActionEvent e) {

+			checkEmptyFile();

+		}

+

+		public void checkEmptyFile() {

+			if (radioFile.isSelected() && fieldFile.getText().equals("")) {

+				// On first label click pop up Browse dialogue.

+				buttonBrowse.doClick();

+			}

+		}

+	}

+

+	protected class DataflowOpenerThread extends Thread {

+		private final boolean background;

+		private final Component parentComponent;

+		private boolean shouldStop = false;

+		private boolean shownWarning = false;

+

+		protected DataflowOpenerThread(Component parentComponent, boolean background) {

+			super("Inspecting selected workflow");

+			this.parentComponent = parentComponent;

+			this.background = background;

+		}

+

+		@Override

+		public void interrupt() {

+			this.shouldStop = true;

+			super.interrupt();

+		}

+

+		public void run() {

+			updateSource();

+//			updateDestination();

+		}

+

+//		public void updateDestination() {

+//			ButtonModel selection = destinationSelection.getSelection();

+//			Workflow chosenDataflow = null;

+//			if (selection == null) {

+//				chosenDataflow = null;

+//			} else if (selection.equals(radioNewDestination.getModel())) {

+//				chosenDataflow = new Workflow();

+//			} else if (selection.equals(radioOpenDestination.getModel())) {

+//				DataflowSelection chosen = (DataflowSelection) destinationAlreadyOpen

+//						.getSelectedItem();

+//				chosenDataflow = chosen.getDataflow();

+//			} else if (selection.equals(radioCustomDestination.getModel())) {

+//				chosenDataflow = customDestinationDataflow;

+//			} else {

+//				logger.error("Unknown selection " + selection);

+//			}

+//

+//			if (chosenDataflow == null) {

+//				if (!background && !shownWarning) {

+//					shownWarning = true;

+//					SwingUtilities.invokeLater(new Runnable() {

+//						public void run() {

+//							JOptionPane.showMessageDialog(parentComponent,

+//									"You need to choose a destination workflow",

+//									"No destination workflow chosen", JOptionPane.ERROR_MESSAGE);

+//							setVisible(true);

+//						}

+//					});

+//					return;

+//				}

+//			}

+//			if (checkInterrupted()) {

+//				return;

+//			}

+//			if (chosenDataflow != ImportWorkflowWizard.this.destinationDataflow) {

+//				updateWorkflowGraphic(previewDestination, chosenDataflow);

+//				if (checkInterrupted()) {

+//					return;

+//				}

+//				ImportWorkflowWizard.this.destinationDataflow = chosenDataflow;

+//			}

+//

+//		}

+

+		public void updateSource() {

+			ButtonModel selection = sourceSelection.getSelection();

+			Workflow chosenDataflow = null;

+			if (selection == null) {

+				chosenDataflow = null;

+			} else if (selection.equals(radioNew.getModel())) {

+				WorkflowBundle workflowBundle = new WorkflowBundle();

+				workflowBundle.setMainWorkflow(new Workflow());

+				workflowBundle.getMainWorkflow().setName(fileManager.getDefaultWorkflowName());

+				workflowBundle.setMainProfile(new Profile());

+				scufl2Tools.setParents(workflowBundle);

+				chosenDataflow = workflowBundle.getMainWorkflow();

+			} else if (selection.equals(radioFile.getModel())) {

+				final String filePath = fieldFile.getText();

+				try {

+					DataflowInfo opened = fileManager

+							.openDataflowSilently(null, new File(filePath));

+					if (checkInterrupted()) {

+						return;

+					}

+					chosenDataflow = opened.getDataflow().getMainWorkflow();

+				} catch (final OpenException e1) {

+					if (!background && !shownWarning) {

+						shownWarning = true;

+						logger.warn("Could not open workflow for merging: " + filePath, e1);

+						SwingUtilities.invokeLater(new Runnable() {

+							public void run() {

+								radioFile.requestFocus();

+								JOptionPane.showMessageDialog(parentComponent,

+										"An error occured while trying to open " + filePath + "\n"

+												+ e1.getMessage(), "Could not open workflow",

+										JOptionPane.WARNING_MESSAGE);

+								setVisible(true);

+							}

+						});

+					}

+				}

+			} else if (selection.equals(radioUrl.getModel())) {

+				final String url = fieldUrl.getText();

+				try {

+					DataflowInfo opened = fileManager.openDataflowSilently(null, new URL(url));

+					if (checkInterrupted()) {

+						return;

+					}

+					chosenDataflow = opened.getDataflow().getMainWorkflow();

+				} catch (final OpenException e1) {

+					if (!background && !shownWarning) {

+						logger.warn("Could not open source workflow: " + url, e1);

+						shownWarning = true;

+						SwingUtilities.invokeLater(new Runnable() {

+							public void run() {

+								fieldUrl.requestFocus();

+								JOptionPane.showMessageDialog(

+										parentComponent,

+										"An error occured while trying to open " + url + "\n"

+												+ e1.getMessage(), "Could not open workflow",

+										JOptionPane.WARNING_MESSAGE);

+								setVisible(true);

+							}

+						});

+

+					}

+					if (checkInterrupted()) {

+						return;

+					}

+				} catch (final MalformedURLException e1) {

+					if (!background && !shownWarning) {

+						logger.warn("Invalid workflow URL: " + url, e1);

+						shownWarning = true;

+						SwingUtilities.invokeLater(new Runnable() {

+							public void run() {

+								fieldUrl.requestFocus();

+								JOptionPane.showMessageDialog(

+										parentComponent,

+										"The workflow location " + url + " is invalid\n"

+												+ e1.getLocalizedMessage(), "Invalid URL",

+										JOptionPane.ERROR_MESSAGE);

+								setVisible(true);

+							}

+						});

+					}

+					if (checkInterrupted()) {

+						return;

+					}

+				}

+			} else if (selection.equals(radioOpened.getModel())) {

+				DataflowSelection chosen = (DataflowSelection) chooseDataflow.getSelectedItem();

+				chosenDataflow = chosen.getDataflow().getMainWorkflow();

+			} else if (selection.equals(radioCustomSource.getModel())) {

+				chosenDataflow = customSourceDataFlow.getMainWorkflow();

+			} else {

+				logger.error("Unknown selection " + selection);

+			}

+			if (checkInterrupted()) {

+				return;

+			}

+			if (chosenDataflow != ImportWorkflowWizard.this.sourceWorkflow) {

+				Profile chosenProfile = null;

+				if (chosenDataflow != null) {

+					chosenProfile = chosenDataflow.getParent().getMainProfile();

+				}

+				updateWorkflowGraphic(previewSource, chosenDataflow, chosenProfile);

+				if (checkInterrupted()) {

+					return;

+				}

+				ImportWorkflowWizard.this.sourceWorkflow = chosenDataflow;

+			}

+			if (chosenDataflow == null) {

+				if (!background && !shownWarning) {

+					shownWarning = true;

+					SwingUtilities.invokeLater(new Runnable() {

+						public void run() {

+							JOptionPane.showMessageDialog(parentComponent,

+									"You need to choose a workflow for merging",

+									"No workflow chosen", JOptionPane.ERROR_MESSAGE);

+							setVisible(true);

+						}

+					});

+				}

+			}

+		}

+

+		private boolean checkInterrupted() {

+			if (Thread.interrupted() || this.shouldStop) {

+				// ImportWorkflowWizard.this.chosenDataflow = null;

+				return true;

+			}

+			return false;

+		}

+	}

+

+	public static class DataflowSelection {

+		private final WorkflowBundle dataflow;

+		private final String name;

+

+		public DataflowSelection(WorkflowBundle dataflow, String name) {

+			this.dataflow = dataflow;

+			this.name = name;

+		}

+

+		public WorkflowBundle getDataflow() {

+			return dataflow;

+		}

+

+		public String getName() {

+			return name;

+		}

+

+		@Override

+		public String toString() {

+			return name;

+		}

+

+	}

+

+	protected class UpdateChosenListener implements ActionListener {

+		public void actionPerformed(ActionEvent e) {

+			Component parentComponent;

+			if (e.getSource() instanceof Component) {

+				parentComponent = (Component) e.getSource();

+			} else {

+				parentComponent = null;

+			}

+			findChosenDataflow(parentComponent, true);

+

+		}

+	}

+

+	public void setCustomSourceDataflow(WorkflowBundle sourceDataflow, String label) {

+		this.customSourceDataFlow = sourceDataflow;

+		this.customSourceName = label;

+		updateSourceSection();

+		radioCustomSource.doClick();

+	}

+

+//	public void setCustomDestinationDataflow(Workflow destinationDataflow, String label) {

+//		this.customDestinationDataflow = destinationDataflow;

+//		this.customDestinationName = label;

+//		updateDestinationSection();

+//		radioCustomDestination.doClick();

+//	}

+

+//	public void setDestinationEnabled(boolean destinationEnabled) {

+//		this.destinationEnabled = destinationEnabled;

+//		updateDestinationSection();

+//	}

+

+	public void setSourceEnabled(boolean sourceEnabled) {

+		this.sourceEnabled = sourceEnabled;

+		updateSourceSection();

+	}

+}

diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/menu/AddNestedWorkflowMenuAction.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/menu/AddNestedWorkflowMenuAction.java
new file mode 100644
index 0000000..a37e308
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/menu/AddNestedWorkflowMenuAction.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (C) 2007-2009 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.importworkflow.menu;
+
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.net.URI;
+
+import javax.swing.Action;
+import javax.swing.KeyStroke;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.ui.menu.MenuManager;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.configuration.workbench.WorkbenchConfiguration;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.importworkflow.actions.AddNestedWorkflowAction;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+import net.sf.taverna.t2.workbench.views.graph.menu.InsertMenu;
+
+/**
+ * An action to add a nested workflow activity + a wrapping processor to the
+ * workflow.
+ *
+ * @author Alex Nenadic
+ * @author Stian Soiland-Reyes
+ *
+ */
+public class AddNestedWorkflowMenuAction extends AbstractMenuAction {
+
+	private static final String ADD_NESTED_WORKFLOW = "Nested workflow";
+
+	private static final URI ADD_NESTED_WORKFLOW_URI = URI
+			.create("http://taverna.sf.net/2008/t2workbench/menu#graphMenuAddNestedWorkflow");
+
+	private EditManager editManager;
+	private FileManager fileManager;
+	private MenuManager menuManager;
+	private ColourManager colourManager;
+	private WorkbenchConfiguration workbenchConfiguration;
+	private SelectionManager selectionManager;
+
+	public AddNestedWorkflowMenuAction() {
+		super(InsertMenu.INSERT, 400, ADD_NESTED_WORKFLOW_URI);
+	}
+
+	@Override
+	protected Action createAction() {
+		AddNestedWorkflowAction a = new AddNestedWorkflowAction(editManager, fileManager,
+				menuManager, colourManager, workbenchConfiguration, selectionManager);
+		// Override name to avoid "Add "
+		a.putValue(Action.NAME, ADD_NESTED_WORKFLOW);
+		a.putValue(Action.SHORT_DESCRIPTION, ADD_NESTED_WORKFLOW);
+		a.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
+				KeyEvent.VK_N, InputEvent.SHIFT_DOWN_MASK
+						| InputEvent.ALT_DOWN_MASK));
+		return a;
+
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setFileManager(FileManager fileManager) {
+		this.fileManager = fileManager;
+	}
+
+	public void setMenuManager(MenuManager menuManager) {
+		this.menuManager = menuManager;
+	}
+
+	public void setColourManager(ColourManager colourManager) {
+		this.colourManager = colourManager;
+	}
+
+	public void setWorkbenchConfiguration(WorkbenchConfiguration workbenchConfiguration) {
+		this.workbenchConfiguration = workbenchConfiguration;
+	}
+
+	public void setSelectionManager(SelectionManager selectionManager) {
+		this.selectionManager = selectionManager;
+	}
+
+}
diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/menu/ImportWorkflowMenuAction.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/menu/ImportWorkflowMenuAction.java
new file mode 100644
index 0000000..1c8b40b
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/menu/ImportWorkflowMenuAction.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (C) 2007-2009 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.importworkflow.menu;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractContextualMenuAction;
+import net.sf.taverna.t2.ui.menu.MenuManager;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.configuration.workbench.WorkbenchConfiguration;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.importworkflow.actions.ImportWorkflowAction;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+import uk.org.taverna.scufl2.api.core.Workflow;
+
+/**
+ * An action to import nested/merged workflows.
+ *
+ * @author Alex Nenadic
+ * @author Stian Soiland-Reyes
+ *
+ */
+public class ImportWorkflowMenuAction extends AbstractContextualMenuAction {
+
+	private static final URI insertSection = URI
+			.create("http://taverna.sf.net/2009/contextMenu/insert");
+
+	private EditManager editManager;
+	private FileManager fileManager;
+	private MenuManager menuManager;
+	private ColourManager colourManager;
+	private WorkbenchConfiguration workbenchConfiguration;
+	private SelectionManager selectionManager;
+
+	public ImportWorkflowMenuAction() {
+		super(insertSection, 400);
+	}
+
+	@Override
+	public boolean isEnabled() {
+		return super.isEnabled() && getContextualSelection().getSelection() instanceof Workflow;
+	}
+
+	@Override
+	protected Action createAction() {
+		ImportWorkflowAction myAction = new ImportWorkflowAction(editManager, fileManager,
+				menuManager, colourManager, workbenchConfiguration, selectionManager);
+		// Just "Workflow" as we go under the "Insert" menu
+		myAction.putValue(Action.NAME, "Nested workflow");
+		return myAction;
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setFileManager(FileManager fileManager) {
+		this.fileManager = fileManager;
+	}
+
+	public void setMenuManager(MenuManager menuManager) {
+		this.menuManager = menuManager;
+	}
+
+	public void setColourManager(ColourManager colourManager) {
+		this.colourManager = colourManager;
+	}
+
+	public void setWorkbenchConfiguration(WorkbenchConfiguration workbenchConfiguration) {
+		this.workbenchConfiguration = workbenchConfiguration;
+	}
+
+	public void setSelectionManager(SelectionManager selectionManager) {
+		this.selectionManager = selectionManager;
+	}
+
+}
diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/menu/MergeWorkflowMenuAction.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/menu/MergeWorkflowMenuAction.java
new file mode 100644
index 0000000..7ce4891
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/menu/MergeWorkflowMenuAction.java
@@ -0,0 +1,65 @@
+package net.sf.taverna.t2.workbench.file.importworkflow.menu;

+

+import java.net.URI;

+

+import javax.swing.Action;

+

+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;

+import net.sf.taverna.t2.ui.menu.MenuManager;

+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;

+import net.sf.taverna.t2.workbench.configuration.workbench.WorkbenchConfiguration;

+import net.sf.taverna.t2.workbench.edits.EditManager;

+import net.sf.taverna.t2.workbench.file.FileManager;

+import net.sf.taverna.t2.workbench.file.importworkflow.actions.MergeWorkflowAction;

+import net.sf.taverna.t2.workbench.selection.SelectionManager;

+

+public class MergeWorkflowMenuAction extends AbstractMenuAction {

+

+	public static final URI INSERT_URI = URI

+			.create("http://taverna.sf.net/2008/t2workbench/menu#insert");

+

+	public static final URI IMPORT_URI = URI

+			.create("http://taverna.sf.net/2008/t2workbench/menu#insert");

+

+	private EditManager editManager;

+	private FileManager fileManager;

+	private MenuManager menuManager;

+	private ColourManager colourManager;

+	private WorkbenchConfiguration workbenchConfiguration;

+	private SelectionManager selectionManager;

+

+	public MergeWorkflowMenuAction() {

+		super(INSERT_URI, 2000, IMPORT_URI);

+	}

+

+	@Override

+	protected Action createAction() {

+		return new MergeWorkflowAction(editManager, fileManager, menuManager, colourManager,

+				workbenchConfiguration, selectionManager);

+	}

+

+	public void setEditManager(EditManager editManager) {

+		this.editManager = editManager;

+	}

+

+	public void setFileManager(FileManager fileManager) {

+		this.fileManager = fileManager;

+	}

+

+	public void setMenuManager(MenuManager menuManager) {

+		this.menuManager = menuManager;

+	}

+

+	public void setColourManager(ColourManager colourManager) {

+		this.colourManager = colourManager;

+	}

+

+	public void setWorkbenchConfiguration(WorkbenchConfiguration workbenchConfiguration) {

+		this.workbenchConfiguration = workbenchConfiguration;

+	}

+

+	public void setSelectionManager(SelectionManager selectionManager) {

+		this.selectionManager = selectionManager;

+	}

+

+}

diff --git a/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/menu/ReplaceNestedWorkflowMenuAction.java b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/menu/ReplaceNestedWorkflowMenuAction.java
new file mode 100644
index 0000000..3d424df
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/java/net/sf/taverna/t2/workbench/file/importworkflow/menu/ReplaceNestedWorkflowMenuAction.java
@@ -0,0 +1,76 @@
+package net.sf.taverna.t2.workbench.file.importworkflow.menu;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.ui.menu.MenuManager;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.activitytools.AbstractConfigureActivityMenuAction;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.configuration.workbench.WorkbenchConfiguration;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.importworkflow.actions.ReplaceNestedWorkflowAction;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+
+public class ReplaceNestedWorkflowMenuAction extends AbstractConfigureActivityMenuAction {
+
+	private static final URI NESTED_ACTIVITY = URI.create("http://ns.taverna.org.uk/2010/activity/nested-workflow");
+
+	private EditManager editManager;
+	private FileManager fileManager;
+	private MenuManager menuManager;
+	private ActivityIconManager activityIconManager;
+	private ColourManager colourManager;
+	private WorkbenchConfiguration workbenchConfiguration;
+	private ServiceDescriptionRegistry serviceDescriptionRegistry;
+	private SelectionManager selectionManager;
+
+	public ReplaceNestedWorkflowMenuAction() {
+		super(NESTED_ACTIVITY);
+	}
+
+	@Override
+	protected Action createAction() {
+		ReplaceNestedWorkflowAction configAction = new ReplaceNestedWorkflowAction(findActivity(),
+				editManager, fileManager, menuManager, activityIconManager, colourManager,
+				serviceDescriptionRegistry, workbenchConfiguration, selectionManager);
+		addMenuDots(configAction);
+		return configAction;
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setFileManager(FileManager fileManager) {
+		this.fileManager = fileManager;
+	}
+
+	public void setMenuManager(MenuManager menuManager) {
+		this.menuManager = menuManager;
+	}
+
+	public void setActivityIconManager(ActivityIconManager activityIconManager) {
+		this.activityIconManager = activityIconManager;
+	}
+
+	public void setColourManager(ColourManager colourManager) {
+		this.colourManager = colourManager;
+	}
+
+	public void setServiceDescriptionRegistry(ServiceDescriptionRegistry serviceDescriptionRegistry) {
+		this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+	}
+
+	public void setWorkbenchConfiguration(WorkbenchConfiguration workbenchConfiguration) {
+		this.workbenchConfiguration = workbenchConfiguration;
+	}
+
+	public void setSelectionManager(SelectionManager selectionManager) {
+		this.selectionManager = selectionManager;
+	}
+
+}
diff --git a/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider b/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider
new file mode 100644
index 0000000..bf42bef
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.dataflow.servicedescriptions.DataflowTemplateService
diff --git a/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent b/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
new file mode 100644
index 0000000..6e7eec5
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
@@ -0,0 +1,9 @@
+# Needs to be first AbstractConfigureActivityMenuAction to be
+# picked up as the automatic 'configure' action for template services
+net.sf.taverna.t2.workbench.file.importworkflow.menu.ReplaceNestedWorkflowMenuAction
+
+net.sf.taverna.t2.workbench.file.importworkflow.menu.AddNestedWorkflowMenuAction
+net.sf.taverna.t2.workbench.file.importworkflow.menu.ImportWorkflowMenuAction
+net.sf.taverna.t2.workbench.file.importworkflow.menu.MergeWorkflowMenuAction
+
+net.sf.taverna.t2.activities.dataflow.menu.EditNestedDataflowMenuAction
diff --git a/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI b/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI
new file mode 100644
index 0000000..5cb0543
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.dataflow.servicedescriptions.DataflowActivityIcon
\ No newline at end of file
diff --git a/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler b/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler
new file mode 100644
index 0000000..a334e66
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.dataflow.filemanager.NestedDataflowPersistenceHandler
\ No newline at end of file
diff --git a/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory b/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory
new file mode 100644
index 0000000..39d7ec2
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.dataflow.views.DataflowActivityViewFactory
\ No newline at end of file
diff --git a/taverna-dataflow-activity-ui/src/main/resources/META-INF/spring/dataflow-activity-ui-context-osgi.xml b/taverna-dataflow-activity-ui/src/main/resources/META-INF/spring/dataflow-activity-ui-context-osgi.xml
new file mode 100644
index 0000000..e664429
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/resources/META-INF/spring/dataflow-activity-ui-context-osgi.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:beans="http://www.springframework.org/schema/beans"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd
+                      http://www.springframework.org/schema/osgi
+                      http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+	<service ref="DataflowActivityIcon" interface="net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI" />
+
+	<service ref="DataflowTemplateService" interface="net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider" />
+
+	<service ref="ReplaceNestedWorkflowMenuAction" auto-export="interfaces" />
+	<service ref="AddNestedWorkflowMenuAction" auto-export="interfaces" />
+	<service ref="ImportWorkflowMenuAction" auto-export="interfaces" />
+	<service ref="MergeWorkflowMenuAction" auto-export="interfaces" />
+	<service ref="EditNestedDataflowMenuAction" auto-export="interfaces" />
+
+	<!-- <service ref="NestedDataflowPersistenceHandler" interface="net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler" /> -->
+
+	<service ref="DataflowActivityViewFactory" interface="net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory" />
+
+	<reference id="editManager" interface="net.sf.taverna.t2.workbench.edits.EditManager" />
+	<reference id="fileManager" interface="net.sf.taverna.t2.workbench.file.FileManager" />
+	<reference id="menuManager" interface="net.sf.taverna.t2.ui.menu.MenuManager" />
+	<reference id="edits" interface="net.sf.taverna.t2.workflowmodel.Edits" />
+	<reference id="activityIconManager" interface="net.sf.taverna.t2.workbench.activityicons.ActivityIconManager" />
+	<reference id="colourManager" interface="net.sf.taverna.t2.workbench.configuration.colour.ColourManager" />
+	<reference id="serviceDescriptionRegistry" interface="net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry" />
+	<reference id="workbenchConfiguration" interface="net.sf.taverna.t2.workbench.configuration.workbench.WorkbenchConfiguration" />
+	<reference id="selectionManager" interface="net.sf.taverna.t2.workbench.selection.SelectionManager" />
+
+</beans:beans>
diff --git a/taverna-dataflow-activity-ui/src/main/resources/META-INF/spring/dataflow-activity-ui-context.xml b/taverna-dataflow-activity-ui/src/main/resources/META-INF/spring/dataflow-activity-ui-context.xml
new file mode 100644
index 0000000..f72abd2
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/resources/META-INF/spring/dataflow-activity-ui-context.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<bean id="DataflowActivityIcon" class="net.sf.taverna.t2.activities.dataflow.servicedescriptions.DataflowActivityIcon" />
+
+	<bean id="DataflowTemplateService" class="net.sf.taverna.t2.activities.dataflow.servicedescriptions.DataflowTemplateService" />
+
+	<bean id="ReplaceNestedWorkflowMenuAction" class="net.sf.taverna.t2.workbench.file.importworkflow.menu.ReplaceNestedWorkflowMenuAction">
+			<property name="editManager" ref="editManager" />
+			<property name="fileManager" ref="fileManager" />
+			<property name="menuManager" ref="menuManager" />
+			<property name="activityIconManager" ref="activityIconManager" />
+			<property name="colourManager" ref="colourManager" />
+			<property name="serviceDescriptionRegistry" ref="serviceDescriptionRegistry" />
+			<property name="workbenchConfiguration" ref="workbenchConfiguration" />
+			<property name="selectionManager" ref="selectionManager" />
+	</bean>
+	<bean id="AddNestedWorkflowMenuAction" class="net.sf.taverna.t2.workbench.file.importworkflow.menu.AddNestedWorkflowMenuAction">
+			<property name="editManager" ref="editManager" />
+			<property name="fileManager" ref="fileManager" />
+			<property name="menuManager" ref="menuManager" />
+			<property name="colourManager" ref="colourManager" />
+			<property name="workbenchConfiguration" ref="workbenchConfiguration" />
+			<property name="selectionManager" ref="selectionManager" />
+	</bean>
+	<bean id="ImportWorkflowMenuAction" class="net.sf.taverna.t2.workbench.file.importworkflow.menu.ImportWorkflowMenuAction">
+			<property name="editManager" ref="editManager" />
+			<property name="fileManager" ref="fileManager" />
+			<property name="menuManager" ref="menuManager" />
+			<property name="colourManager" ref="colourManager" />
+			<property name="workbenchConfiguration" ref="workbenchConfiguration" />
+			<property name="selectionManager" ref="selectionManager" />
+	</bean>
+	<bean id="MergeWorkflowMenuAction" class="net.sf.taverna.t2.workbench.file.importworkflow.menu.MergeWorkflowMenuAction">
+			<property name="editManager" ref="editManager" />
+			<property name="fileManager" ref="fileManager" />
+			<property name="menuManager" ref="menuManager" />
+			<property name="colourManager" ref="colourManager" />
+			<property name="workbenchConfiguration" ref="workbenchConfiguration" />
+			<property name="selectionManager" ref="selectionManager" />
+	</bean>
+	<bean id="EditNestedDataflowMenuAction" class="net.sf.taverna.t2.activities.dataflow.menu.EditNestedDataflowMenuAction">
+			<property name="selectionManager" ref="selectionManager" />
+	</bean>
+
+	<!-- <bean id="NestedDataflowPersistenceHandler" class="net.sf.taverna.t2.activities.dataflow.filemanager.NestedDataflowPersistenceHandler">
+			<property name="editManager" ref="editManager" />
+			<property name="fileManager" ref="fileManager" />
+	</bean> -->
+
+	<bean id="DataflowActivityViewFactory" class="net.sf.taverna.t2.activities.dataflow.views.DataflowActivityViewFactory">
+			<property name="editManager" ref="editManager" />
+			<property name="fileManager" ref="fileManager" />
+			<property name="menuManager" ref="menuManager" />
+			<property name="activityIconManager" ref="activityIconManager" />
+			<property name="colourManager" ref="colourManager" />
+			<property name="serviceDescriptionRegistry" ref="serviceDescriptionRegistry" />
+			<property name="workbenchConfiguration" ref="workbenchConfiguration" />
+			<property name="selectionManager" ref="selectionManager" />
+	</bean>
+
+</beans>
diff --git a/taverna-dataflow-activity-ui/src/main/resources/dataflow.png b/taverna-dataflow-activity-ui/src/main/resources/dataflow.png
new file mode 100644
index 0000000..71b188c
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/main/resources/dataflow.png
Binary files differ
diff --git a/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/AbstractTestHelper.java b/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/AbstractTestHelper.java
new file mode 100644
index 0000000..7a4d2f6
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/AbstractTestHelper.java
@@ -0,0 +1,266 @@
+package net.sf.taverna.t2.workbench.file.importworkflow;

+

+import static org.junit.Assert.assertEquals;

+import static org.junit.Assert.assertNotNull;

+import static org.junit.Assert.assertTrue;

+

+import java.io.InputStream;

+import java.util.HashSet;

+import java.util.List;

+import java.util.Set;

+

+import org.junit.Before;

+

+import uk.org.taverna.scufl2.api.common.Scufl2Tools;

+import uk.org.taverna.scufl2.api.container.WorkflowBundle;

+import uk.org.taverna.scufl2.api.core.BlockingControlLink;

+import uk.org.taverna.scufl2.api.core.ControlLink;

+import uk.org.taverna.scufl2.api.core.DataLink;

+import uk.org.taverna.scufl2.api.core.Processor;

+import uk.org.taverna.scufl2.api.core.Workflow;

+import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;

+import uk.org.taverna.scufl2.api.port.InputWorkflowPort;

+import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;

+import uk.org.taverna.scufl2.api.port.ProcessorPort;

+import uk.org.taverna.scufl2.api.port.ReceiverPort;

+import uk.org.taverna.scufl2.api.port.SenderPort;

+

+public abstract class AbstractTestHelper {

+

+	private static final String Q_T2FLOW = "/q.t2flow";

+

+	private static final String ABC_T2FLOW = "/abc.t2flow";

+

+	private static final String P_T2FLOW = "/p.t2flow";

+

+	private WorkflowBundleIO workflowBundleIO = new WorkflowBundleIO();

+

+	protected Scufl2Tools scufl2Tools = new Scufl2Tools();

+

+	protected Workflow abc;

+

+	protected Workflow p;

+

+	protected Workflow q;

+

+	protected void assertHasConditionals(Workflow dataflow,

+			String... expectedConditionalDef) {

+		Set<String> expectedConditionals = new HashSet<String>();

+		for (String expected : expectedConditionalDef) {

+			expectedConditionals.add(expected);

+		}

+

+		Set<String> foundConditionals = new HashSet<String>();

+

+		for (ControlLink c : dataflow.getControlLinks()) {

+			if (c instanceof BlockingControlLink) {

+			BlockingControlLink bcl = (BlockingControlLink) c;

+			foundConditionals.add(bcl.getUntilFinished().getName() + ";"

+					+ bcl.getBlock().getName());

+			}

+		}

+

+		Set<String> extras = new HashSet<String>(foundConditionals);

+		extras.removeAll(expectedConditionals);

+		assertTrue("Unexpected conditional  " + extras, extras.isEmpty());

+

+		Set<String> missing = new HashSet<String>(expectedConditionals);

+		missing.removeAll(foundConditionals);

+		assertTrue("Could not find conditional  " + missing, missing.isEmpty());

+	}

+

+	protected void assertHasDatalinks(Workflow dataflow,

+			String... expectedLinkDef) {

+		Set<String> expectedLinks = new HashSet<String>();

+		for (String expected : expectedLinkDef) {

+			expectedLinks.add(expected);

+		}

+

+		Set<String> foundLinks = new HashSet<String>();

+

+		for (DataLink link : dataflow.getDataLinks()) {

+			StringBuilder linkRef = new StringBuilder();

+			SenderPort source = link.getReceivesFrom();

+			if (source instanceof ProcessorPort) {

+				linkRef.append(((ProcessorPort) source).getParent()

+						.getName());

+				linkRef.append('.');

+			}

+			linkRef.append(source.getName());

+

+			linkRef.append("->");

+

+			ReceiverPort sink = link.getSendsTo();

+			if (sink instanceof ProcessorPort) {

+				linkRef.append(((ProcessorPort) sink).getParent()

+						.getName());

+				linkRef.append('.');

+			}

+			linkRef.append(sink.getName());

+

+			String linkStr = linkRef.toString();

+			foundLinks.add(linkStr);

+		}

+

+		Set<String> extras = new HashSet<String>(foundLinks);

+		extras.removeAll(expectedLinks);

+		assertTrue("Unexpected links  " + extras, extras.isEmpty());

+

+		Set<String> missing = new HashSet<String>(expectedLinks);

+		missing.removeAll(foundLinks);

+		assertTrue("Could not find links  " + missing, missing.isEmpty());

+	}

+

+	protected void assertHasInputPorts(Workflow dataflow,

+			String... expectedInputPorts) {

+		Set<String> expectedNames = new HashSet<String>();

+		for (String expected : expectedInputPorts) {

+			expectedNames.add(expected);

+		}

+		Set<String> foundNames = new HashSet<String>();

+		for (InputWorkflowPort port : dataflow.getInputPorts()) {

+			String name = port.getName();

+			foundNames.add(name);

+		}

+

+		Set<String> extras = new HashSet<String>(foundNames);

+		extras.removeAll(expectedNames);

+		assertTrue("Unexpected input port  " + extras, extras.isEmpty());

+

+		Set<String> missing = new HashSet<String>(expectedNames);

+		missing.removeAll(foundNames);

+		assertTrue("Could not find input port  " + missing, missing.isEmpty());

+

+	}

+

+	protected void assertHasOutputPorts(Workflow dataflow,

+			String... expectedOutputPorts) {

+		Set<String> expectedNames = new HashSet<String>();

+		for (String expected : expectedOutputPorts) {

+			expectedNames.add(expected);

+		}

+		Set<String> foundNames = new HashSet<String>();

+		for (OutputWorkflowPort port : dataflow.getOutputPorts()) {

+			String name = port.getName();

+			foundNames.add(name);

+		}

+

+		Set<String> extras = new HashSet<String>(foundNames);

+		extras.removeAll(expectedNames);

+		assertTrue("Unexpected output port  " + extras, extras.isEmpty());

+

+		Set<String> missing = new HashSet<String>(expectedNames);

+		missing.removeAll(foundNames);

+		assertTrue("Could not find output port  " + missing, missing.isEmpty());

+	}

+

+	protected void assertHasProcessors(Workflow dataflow,

+			String... expectedProcessors) {

+		Set<String> expectedNames = new HashSet<String>();

+		for (String expected : expectedProcessors) {

+			expectedNames.add(expected);

+		}

+		Set<String> foundNames = new HashSet<String>();

+

+		for (Processor proc : dataflow.getProcessors()) {

+			String processorName = proc.getName();

+			foundNames.add(processorName);

+		}

+

+		Set<String> extras = new HashSet<String>(foundNames);

+		extras.removeAll(expectedNames);

+		assertTrue("Unexpected processor  " + extras, extras.isEmpty());

+

+		Set<String> missing = new HashSet<String>(expectedNames);

+		missing.removeAll(foundNames);

+		assertTrue("Could not find processor  " + missing, missing.isEmpty());

+	}

+

+	protected void checkAbc() throws Exception {

+		assertHasProcessors(abc, "A", "B", "C");

+		assertHasInputPorts(abc, "in1", "in2");

+		assertHasOutputPorts(abc, "a", "b", "c");

+		assertHasDatalinks(abc, "in2->B.inputlist", "in1->A.string1",

+				"in2->A.string2", "Merge0:Merge0_output->C.inputlist",

+				"A.output->a", "B.outputlist->b",

+				"B.outputlist->Merge0:outputlistToMerge0_input0",

+				"A.output->Merge0:outputToMerge0_input0", "C.outputlist->c");

+		assertHasConditionals(abc, "A;B");

+	}

+

+	protected void checkP() throws Exception {

+		assertHasProcessors(p, "P");

+		assertHasInputPorts(p, "i");

+		assertHasOutputPorts(p, "o");

+		assertHasDatalinks(p, "i->P.inputlist", "P.outputlist->o");

+		assertHasConditionals(p);

+

+	}

+

+	protected void checkQ() throws Exception {

+		assertHasProcessors(q, "Q");

+		assertHasInputPorts(q, "p");

+		assertHasOutputPorts(q, "p", "q");

+		assertHasDatalinks(q, "p->Q.inputlist", "Q.outputlist->q", "p->p");

+		assertHasConditionals(q);

+

+		List<DataLink> datalinksTo = scufl2Tools.datalinksTo(findOutputPort(q, "p"));

+		assertEquals(1, datalinksTo.size());

+		SenderPort source = datalinksTo.get(0).getReceivesFrom();

+		assertEquals("out port P not linked to input P", source, findInputPort(q, "p"));

+

+	}

+

+	protected Workflow loadAbc() throws Exception {

+		return openWorkflow(getClass().getResourceAsStream(ABC_T2FLOW));

+	}

+

+	protected Workflow loadP() throws Exception {

+		return openWorkflow(getClass().getResourceAsStream(P_T2FLOW));

+	}

+

+	protected Workflow loadQ() throws Exception {

+		return openWorkflow(getClass().getResourceAsStream(Q_T2FLOW));

+	}

+

+	@Before

+	public void loadWorkflows() throws Exception {

+		abc = loadAbc();

+		p = loadP();

+		q = loadQ();

+	}

+

+	protected Workflow openWorkflow(InputStream workflowXMLstream) throws Exception {

+		assertNotNull(workflowXMLstream);

+		WorkflowBundle workflowBundle = workflowBundleIO.readBundle(workflowXMLstream, "application/vnd.taverna.t2flow+xml");

+		return workflowBundle.getMainWorkflow();

+	}

+

+	protected InputWorkflowPort findInputPort(Workflow wf, String name) {

+		for (InputWorkflowPort inp : wf.getInputPorts()) {

+			if (inp.getName().equals(name)) {

+				return inp;

+			}

+		}

+		throw new IllegalArgumentException("Unknown input port: " + name);

+	}

+

+	protected OutputWorkflowPort findOutputPort(Workflow wf, String name) {

+		for (OutputWorkflowPort outp : wf.getOutputPorts()) {

+			if (outp.getName().equals(name)) {

+				return outp;

+			}

+		}

+		throw new IllegalArgumentException("Unknown output port: " + name);

+	}

+

+	protected Processor findProcessor(Workflow wf, String name) {

+		for (Processor proc : wf.getProcessors()) {

+			if (proc.getName().equals(name)) {

+				return proc;

+			}

+		}

+		throw new IllegalArgumentException("Unknown processor: " + name);

+	}

+

+}

diff --git a/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/TestPortMerge.java b/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/TestPortMerge.java
new file mode 100644
index 0000000..9141693
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/TestPortMerge.java
@@ -0,0 +1,38 @@
+package net.sf.taverna.t2.workbench.file.importworkflow;

+

+import static org.junit.Assert.assertEquals;

+import static org.junit.Assert.assertSame;

+

+import java.util.List;

+

+import org.junit.Ignore;

+import org.junit.Test;

+

+import uk.org.taverna.scufl2.api.core.DataLink;

+import uk.org.taverna.scufl2.api.core.Workflow;

+import uk.org.taverna.scufl2.api.port.SenderPort;

+

+@Ignore

+public class TestPortMerge extends AbstractTestHelper {

+

+	@Test

+	public void mergeQintoP() throws Exception {

+		DataflowMerger merger = new DataflowMerger(p);

+		merger.getMergeEdit(q).doEdit();

+		Workflow merged = p;

+		checkQ();

+

+		assertHasProcessors(merged, "P", "Q");

+		assertHasInputPorts(merged, "i", "p");

+		assertHasOutputPorts(merged, "o", "p", "q");

+		assertHasDatalinks(merged, "i->P.inputlist", "P.outputlist->o", "p->Q.inputlist",

+				"Q.outputlist->q", "p->p");

+

+		List<DataLink> datalinksTo = scufl2Tools.datalinksTo(findOutputPort(merged, "p"));

+		assertEquals(1, datalinksTo.size());

+		SenderPort source = datalinksTo.get(0).getReceivesFrom();

+		assertSame("out port P not linked to input P", source, findInputPort(merged, "p"));

+

+	}

+

+}

diff --git a/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/TestRename.java b/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/TestRename.java
new file mode 100644
index 0000000..c235c98
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/TestRename.java
@@ -0,0 +1,58 @@
+package net.sf.taverna.t2.workbench.file.importworkflow;

+

+import org.junit.Ignore;

+import org.junit.Test;

+

+import uk.org.taverna.scufl2.api.core.Workflow;

+

+@Ignore

+public class TestRename extends AbstractTestHelper {

+

+	@Test

+	public void mergePintoP() throws Exception {

+		DataflowMerger merger = new DataflowMerger(p);

+		merger.getMergeEdit(p).doEdit();

+		Workflow merged = p;

+

+		assertHasProcessors(merged, "P", "P_2");

+		assertHasInputPorts(merged, "i", "i_2");

+		assertHasOutputPorts(merged, "o", "o_2");

+		assertHasDatalinks(merged, "i->P.inputlist", "P.outputlist->o",

+				"i_2->P_2.inputlist", "P_2.outputlist->o_2");

+	}

+

+	@Test

+	public void mergePintoPintoP() throws Exception {

+		// Don't put p in constructor, or we would get exponential merging!

+		Workflow merged = new Workflow();

+		DataflowMerger merger = new DataflowMerger(merged);

+		merger.getMergeEdit(p).doEdit();

+		merger.getMergeEdit(p).doEdit();

+		merger.getMergeEdit(p).doEdit();

+

+		assertHasProcessors(merged, "P", "P_2", "P_3");

+		assertHasInputPorts(merged, "i", "i_2", "i_3");

+		assertHasOutputPorts(merged, "o", "o_2", "o_3");

+		assertHasDatalinks(merged, "i->P.inputlist", "P.outputlist->o",

+				"i_2->P_2.inputlist", "P_2.outputlist->o_2",

+				"i_3->P_3.inputlist", "P_3.outputlist->o_3");

+	}

+

+	@Test

+	public void mergePintoPWithPrefix() throws Exception {

+		// Don't put p in constructor, or we would get exponential merging!

+		Workflow merged = new Workflow();

+		DataflowMerger merger = new DataflowMerger(merged);

+		merger.getMergeEdit(p).doEdit();

+		merger.getMergeEdit(p, "fish_").doEdit();

+		merger.getMergeEdit(p, "soup_").doEdit();

+

+		assertHasProcessors(merged, "P", "fish_P", "soup_P");

+		assertHasInputPorts(merged, "i", "fish_i", "soup_i");

+		assertHasOutputPorts(merged, "o", "fish_o", "soup_o");

+		assertHasDatalinks(merged, "i->P.inputlist", "P.outputlist->o",

+				"fish_i->fish_P.inputlist", "fish_P.outputlist->fish_o",

+				"soup_i->soup_P.inputlist", "soup_P.outputlist->soup_o");

+	}

+

+}

diff --git a/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/TestSimpleMerge.java b/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/TestSimpleMerge.java
new file mode 100644
index 0000000..811678e
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/TestSimpleMerge.java
@@ -0,0 +1,98 @@
+package net.sf.taverna.t2.workbench.file.importworkflow;

+

+import static org.junit.Assert.assertEquals;

+import static org.junit.Assert.assertNotSame;

+import static org.junit.Assert.assertSame;

+

+import java.util.List;

+

+import org.junit.Ignore;

+import org.junit.Test;

+

+import uk.org.taverna.scufl2.api.core.DataLink;

+import uk.org.taverna.scufl2.api.core.Processor;

+import uk.org.taverna.scufl2.api.core.Workflow;

+import uk.org.taverna.scufl2.api.port.InputProcessorPort;

+import uk.org.taverna.scufl2.api.port.InputWorkflowPort;

+import uk.org.taverna.scufl2.api.port.SenderPort;

+

+@Ignore

+public class TestSimpleMerge extends AbstractTestHelper {

+

+	private void checkMergedAbcP(Workflow merged) {

+		// Check that it has everything from both

+		assertHasProcessors(merged, "A", "B", "C", "P");

+		assertHasInputPorts(merged, "in1", "in2", "i");

+		assertHasOutputPorts(merged, "a", "b", "c", "o");

+		assertHasDatalinks(merged, "in2->B.inputlist", "in1->A.string1",

+				"in2->A.string2", "Merge0:Merge0_output->C.inputlist",

+				"A.output->a", "B.outputlist->b",

+				"B.outputlist->Merge0:outputlistToMerge0_input0",

+				"A.output->Merge0:outputToMerge0_input0", "C.outputlist->c",

+				"i->P.inputlist", "P.outputlist->o");

+		assertHasConditionals(merged, "A;B");

+	}

+

+	private void checkCopiedFromP(Workflow merged) {

+		Processor newProcP = findProcessor(merged, "P");

+		Processor originalProcP = findProcessor(p, "P");

+		assertNotSame("Did not copy processor P", newProcP, originalProcP);

+

+		InputProcessorPort inp = newProcP.getInputPorts().first();

+		InputWorkflowPort newInI = findInputPort(merged, "i");

+		assertEquals(0, newInI.getDepth().intValue());

+

+		InputWorkflowPort originalInI = findInputPort(p, "i");

+		assertNotSame("Did not copy port 'i'", originalInI, newInI);

+

+		List<DataLink> datalinksTo = scufl2Tools.datalinksTo(inp);

+		assertEquals(1, datalinksTo.size());

+		SenderPort source = datalinksTo.get(0).getReceivesFrom();

+

+		assertSame("Not linked to new port", source, newInI);

+		assertNotSame("Still linked to old port", source, originalInI);

+	}

+

+

+	@Test

+	public void mergeAbcAndPIntoNew() throws Exception {

+		Workflow merged = new Workflow();

+		DataflowMerger merger = new DataflowMerger(merged);

+		merger.getMergeEdit(abc).doEdit();

+

+		assertNotSame(abc, merged);

+		merger.getMergeEdit(p).doEdit();

+

+

+		// Assert abc and p were not modified

+		checkAbc();

+		checkP();

+

+		checkMergedAbcP(merged);

+		checkCopiedFromP(merged);

+	}

+

+	@Test

+	public void mergePintoAbc() throws Exception {

+		DataflowMerger merger = new DataflowMerger(abc);

+		Workflow merged = abc;

+

+		merger.getMergeEdit(p).doEdit();

+		checkMergedAbcP(merged);

+		checkCopiedFromP(merged);

+		// Assert P did not change

+		checkP();

+	}

+

+	@Test

+	public void mergeAbcintoP() throws Exception {

+		Workflow merged = p;

+		DataflowMerger merger = new DataflowMerger(merged);

+		merger.getMergeEdit(abc).doEdit();

+

+		checkMergedAbcP(merged);

+		// Assert ABC did not change

+		checkAbc();

+	}

+

+}

diff --git a/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/TestTestHelper.java b/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/TestTestHelper.java
new file mode 100644
index 0000000..2165a67
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/TestTestHelper.java
@@ -0,0 +1,24 @@
+package net.sf.taverna.t2.workbench.file.importworkflow;

+

+import org.junit.Ignore;

+import org.junit.Test;

+

+@Ignore

+public class TestTestHelper extends AbstractTestHelper {

+

+	@Test

+	public void checkAbc() throws Exception {

+		super.checkAbc();

+	}

+

+	@Test

+	public void checkP() throws Exception {

+		super.checkP();

+	}

+

+	@Test

+	public void checkQ() throws Exception {

+		super.checkQ();

+	}

+

+}

diff --git a/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/gui/ImportWizardLauncher.java b/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/gui/ImportWizardLauncher.java
new file mode 100644
index 0000000..b45a774
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/test/java/net/sf/taverna/t2/workbench/file/importworkflow/gui/ImportWizardLauncher.java
@@ -0,0 +1,24 @@
+package net.sf.taverna.t2.workbench.file.importworkflow.gui;

+

+import javax.swing.UIManager;

+

+import net.sf.taverna.t2.workbench.edits.EditManager;

+import net.sf.taverna.t2.workbench.edits.impl.EditManagerImpl;

+import net.sf.taverna.t2.workbench.file.FileManager;

+import net.sf.taverna.t2.workbench.file.impl.FileManagerImpl;

+

+

+public class ImportWizardLauncher {

+

+	public static void main(String[] args) throws Exception {

+

+		UIManager.setLookAndFeel(UIManager

+				.getSystemLookAndFeelClassName());

+

+		EditManager editManager = new EditManagerImpl();

+		FileManager fileManager = new FileManagerImpl(editManager);

+

+		ImportWorkflowWizard s = new ImportWorkflowWizard(null, editManager, fileManager, null, null, null, null);

+		s.setVisible(true);

+	}

+}

diff --git a/taverna-dataflow-activity-ui/src/test/resources/abc.t2flow b/taverna-dataflow-activity-ui/src/test/resources/abc.t2flow
new file mode 100644
index 0000000..a30cdc6
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/test/resources/abc.t2flow
@@ -0,0 +1,116 @@
+<workflow xmlns="http://taverna.sf.net/2008/xml/t2flow" version="1" producedBy="taverna-2.1-beta-2"><dataflow id="55a3691f-127a-4fd3-b51c-a7ed27f6ec88" role="top"><name>Workflow2</name><inputPorts><port><name>in1</name><depth>0</depth><granularDepth>0</granularDepth><annotations /></port><port><name>in2</name><depth>1</depth><granularDepth>1</granularDepth><annotations /></port></inputPorts><outputPorts><port><name>a</name></port><port><name>b</name></port><port><name>c</name></port></outputPorts><processors><processor><name>B</name><inputPorts><port><name>inputlist</name><depth>1</depth></port></inputPorts><outputPorts><port><name>outputlist</name><depth>1</depth><granularDepth>1</granularDepth></port></outputPorts><annotations /><activities><activity><raven><group>net.sf.taverna.t2.activities</group><artifact>localworker-activity</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap><map from="inputlist" to="inputlist" /></inputMap><outputMap><map from="outputlist" to="outputlist" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>outputlist = inputlist;</script>

+  <dependencies />

+  <classLoaderSharing>workflow</classLoaderSharing>

+  <localDependencies />

+  <artifactDependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>[B</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>inputlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>outputlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean><annotations /></activity></activities><dispatchStack><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Parallelize</class><configBean encoding="xstream"><net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ParallelizeConfig xmlns="">

+  <maxJobs>1</maxJobs>

+</net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ParallelizeConfig></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ErrorBounce</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Failover</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Retry</class><configBean encoding="xstream"><net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.RetryConfig xmlns="">

+  <backoffFactor>1.0</backoffFactor>

+  <initialDelay>1000</initialDelay>

+  <maxDelay>5000</maxDelay>

+  <maxRetries>0</maxRetries>

+</net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.RetryConfig></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Invoke</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer></dispatchStack><iterationStrategyStack><iteration><strategy><cross><port name="inputlist" depth="1" /></cross></strategy></iteration></iterationStrategyStack></processor><processor><name>A</name><inputPorts><port><name>string1</name><depth>0</depth></port><port><name>string2</name><depth>0</depth></port></inputPorts><outputPorts><port><name>output</name><depth>0</depth><granularDepth>0</granularDepth></port></outputPorts><annotations /><activities><activity><raven><group>net.sf.taverna.t2.activities</group><artifact>localworker-activity</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap><map from="string2" to="string2" /><map from="string1" to="string1" /></inputMap><outputMap><map from="output" to="output" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>output = string1 + string2;</script>

+  <dependencies />

+  <classLoaderSharing>workflow</classLoaderSharing>

+  <localDependencies />

+  <artifactDependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>string1</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>string2</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>output</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean><annotations /></activity></activities><dispatchStack><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Parallelize</class><configBean encoding="xstream"><net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ParallelizeConfig xmlns="">

+  <maxJobs>1</maxJobs>

+</net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ParallelizeConfig></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ErrorBounce</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Failover</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Retry</class><configBean encoding="xstream"><net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.RetryConfig xmlns="">

+  <backoffFactor>1.0</backoffFactor>

+  <initialDelay>1000</initialDelay>

+  <maxDelay>5000</maxDelay>

+  <maxRetries>0</maxRetries>

+</net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.RetryConfig></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Invoke</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer></dispatchStack><iterationStrategyStack><iteration><strategy><cross><port name="string1" depth="0" /><port name="string2" depth="0" /></cross></strategy></iteration></iterationStrategyStack></processor><processor><name>C</name><inputPorts><port><name>inputlist</name><depth>1</depth></port></inputPorts><outputPorts><port><name>outputlist</name><depth>1</depth><granularDepth>1</granularDepth></port></outputPorts><annotations /><activities><activity><raven><group>net.sf.taverna.t2.activities</group><artifact>localworker-activity</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap><map from="inputlist" to="inputlist" /></inputMap><outputMap><map from="outputlist" to="outputlist" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>outputlist = inputlist;</script>

+  <dependencies />

+  <classLoaderSharing>workflow</classLoaderSharing>

+  <localDependencies />

+  <artifactDependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>[B</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>inputlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>outputlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean><annotations /></activity></activities><dispatchStack><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Parallelize</class><configBean encoding="xstream"><net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ParallelizeConfig xmlns="">

+  <maxJobs>1</maxJobs>

+</net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ParallelizeConfig></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ErrorBounce</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Failover</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Retry</class><configBean encoding="xstream"><net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.RetryConfig xmlns="">

+  <backoffFactor>1.0</backoffFactor>

+  <initialDelay>1000</initialDelay>

+  <maxDelay>5000</maxDelay>

+  <maxRetries>0</maxRetries>

+</net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.RetryConfig></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Invoke</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer></dispatchStack><iterationStrategyStack><iteration><strategy><cross><port name="inputlist" depth="1" /></cross></strategy></iteration></iterationStrategyStack></processor></processors><conditions><condition control="A" target="B" /></conditions><datalinks><datalink><sink type="processor"><processor>B</processor><port>inputlist</port></sink><source type="dataflow"><port>in2</port></source></datalink><datalink><sink type="processor"><processor>A</processor><port>string1</port></sink><source type="dataflow"><port>in1</port></source></datalink><datalink><sink type="processor"><processor>A</processor><port>string2</port></sink><source type="dataflow"><port>in2</port></source></datalink><datalink><sink type="merge"><processor>C</processor><port>inputlist</port></sink><source type="processor"><processor>B</processor><port>outputlist</port></source></datalink><datalink><sink type="merge"><processor>C</processor><port>inputlist</port></sink><source type="processor"><processor>A</processor><port>output</port></source></datalink><datalink><sink type="dataflow"><port>a</port></sink><source type="processor"><processor>A</processor><port>output</port></source></datalink><datalink><sink type="dataflow"><port>b</port></sink><source type="processor"><processor>B</processor><port>outputlist</port></source></datalink><datalink><sink type="dataflow"><port>c</port></sink><source type="processor"><processor>C</processor><port>outputlist</port></source></datalink></datalinks><annotations /></dataflow></workflow>
\ No newline at end of file
diff --git a/taverna-dataflow-activity-ui/src/test/resources/p.t2flow b/taverna-dataflow-activity-ui/src/test/resources/p.t2flow
new file mode 100644
index 0000000..d4e191c
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/test/resources/p.t2flow
@@ -0,0 +1,36 @@
+<workflow xmlns="http://taverna.sf.net/2008/xml/t2flow" version="1" producedBy="taverna-2.1-beta-2"><dataflow id="a158f691-3561-424f-bec1-e6359b6b486f" role="top"><name>Workflow7</name><inputPorts><port><name>i</name><depth>0</depth><granularDepth>0</granularDepth><annotations /></port></inputPorts><outputPorts><port><name>o</name></port></outputPorts><processors><processor><name>P</name><inputPorts><port><name>inputlist</name><depth>1</depth></port></inputPorts><outputPorts><port><name>outputlist</name><depth>1</depth><granularDepth>1</granularDepth></port></outputPorts><annotations /><activities><activity><raven><group>net.sf.taverna.t2.activities</group><artifact>localworker-activity</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap><map from="inputlist" to="inputlist" /></inputMap><outputMap><map from="outputlist" to="outputlist" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>outputlist = inputlist;</script>

+  <dependencies />

+  <classLoaderSharing>workflow</classLoaderSharing>

+  <localDependencies />

+  <artifactDependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>[B</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>inputlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>outputlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean><annotations /></activity></activities><dispatchStack><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Parallelize</class><configBean encoding="xstream"><net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ParallelizeConfig xmlns="">

+  <maxJobs>1</maxJobs>

+</net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ParallelizeConfig></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ErrorBounce</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Failover</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Retry</class><configBean encoding="xstream"><net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.RetryConfig xmlns="">

+  <backoffFactor>1.0</backoffFactor>

+  <initialDelay>1000</initialDelay>

+  <maxDelay>5000</maxDelay>

+  <maxRetries>0</maxRetries>

+</net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.RetryConfig></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Invoke</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer></dispatchStack><iterationStrategyStack><iteration><strategy><cross><port name="inputlist" depth="1" /></cross></strategy></iteration></iterationStrategyStack></processor></processors><conditions /><datalinks><datalink><sink type="processor"><processor>P</processor><port>inputlist</port></sink><source type="dataflow"><port>i</port></source></datalink><datalink><sink type="dataflow"><port>o</port></sink><source type="processor"><processor>P</processor><port>outputlist</port></source></datalink></datalinks><annotations /></dataflow></workflow>
\ No newline at end of file
diff --git a/taverna-dataflow-activity-ui/src/test/resources/q.t2flow b/taverna-dataflow-activity-ui/src/test/resources/q.t2flow
new file mode 100644
index 0000000..03a3cd2
--- /dev/null
+++ b/taverna-dataflow-activity-ui/src/test/resources/q.t2flow
@@ -0,0 +1,36 @@
+<workflow xmlns="http://taverna.sf.net/2008/xml/t2flow" version="1" producedBy="taverna-2.1-beta-2"><dataflow id="0833816b-d18b-41b4-b2f7-dae317023444" role="top"><name>Workflow2</name><inputPorts><port><name>p</name><depth>1</depth><granularDepth>1</granularDepth><annotations /></port></inputPorts><outputPorts><port><name>q</name></port><port><name>p</name></port></outputPorts><processors><processor><name>Q</name><inputPorts><port><name>inputlist</name><depth>1</depth></port></inputPorts><outputPorts><port><name>outputlist</name><depth>1</depth><granularDepth>1</granularDepth></port></outputPorts><annotations /><activities><activity><raven><group>net.sf.taverna.t2.activities</group><artifact>localworker-activity</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap><map from="inputlist" to="inputlist" /></inputMap><outputMap><map from="outputlist" to="outputlist" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>outputlist = inputlist;</script>

+  <dependencies />

+  <classLoaderSharing>workflow</classLoaderSharing>

+  <localDependencies />

+  <artifactDependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>[B</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>inputlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>outputlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean><annotations /></activity></activities><dispatchStack><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Parallelize</class><configBean encoding="xstream"><net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ParallelizeConfig xmlns="">

+  <maxJobs>1</maxJobs>

+</net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ParallelizeConfig></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ErrorBounce</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Failover</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Retry</class><configBean encoding="xstream"><net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.RetryConfig xmlns="">

+  <backoffFactor>1.0</backoffFactor>

+  <initialDelay>1000</initialDelay>

+  <maxDelay>5000</maxDelay>

+  <maxRetries>0</maxRetries>

+</net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.RetryConfig></configBean></dispatchLayer><dispatchLayer><raven><group>net.sf.taverna.t2.core</group><artifact>workflowmodel-impl</artifact><version>0.8</version></raven><class>net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Invoke</class><configBean encoding="xstream"><null xmlns="" /></configBean></dispatchLayer></dispatchStack><iterationStrategyStack><iteration><strategy><cross><port name="inputlist" depth="1" /></cross></strategy></iteration></iterationStrategyStack></processor></processors><conditions /><datalinks><datalink><sink type="processor"><processor>Q</processor><port>inputlist</port></sink><source type="dataflow"><port>p</port></source></datalink><datalink><sink type="dataflow"><port>q</port></sink><source type="processor"><processor>Q</processor><port>outputlist</port></source></datalink><datalink><sink type="dataflow"><port>p</port></sink><source type="dataflow"><port>p</port></source></datalink></datalinks><annotations /></dataflow></workflow>
\ No newline at end of file