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