You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/03/20 15:22:52 UTC

[38/51] [abbrv] [partial] incubator-taverna-workbench git commit: taverna-workbench-* -> taverna-*

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-design-ui/src/main/java/net/sf/taverna/t2/workbench/design/ui/DataflowInputPortPanel.java
----------------------------------------------------------------------
diff --git a/taverna-design-ui/src/main/java/net/sf/taverna/t2/workbench/design/ui/DataflowInputPortPanel.java b/taverna-design-ui/src/main/java/net/sf/taverna/t2/workbench/design/ui/DataflowInputPortPanel.java
new file mode 100644
index 0000000..e578ef2
--- /dev/null
+++ b/taverna-design-ui/src/main/java/net/sf/taverna/t2/workbench/design/ui/DataflowInputPortPanel.java
@@ -0,0 +1,203 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.design.ui;
+
+import static java.awt.GridBagConstraints.HORIZONTAL;
+import static java.awt.GridBagConstraints.NONE;
+import static java.awt.GridBagConstraints.NORTHWEST;
+import static java.awt.GridBagConstraints.WEST;
+import static java.awt.event.ItemEvent.SELECTED;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * UI for creating/editing dataflow input ports.
+ * 
+ * @author David Withers
+ */
+public class DataflowInputPortPanel extends JPanel {
+	private static final long serialVersionUID = 2650486705615513458L;
+
+	private JTextField portNameField;
+	private JRadioButton singleValueButton;
+	private JRadioButton listValueButton;
+	private JSpinner listDepthSpinner;
+
+	public DataflowInputPortPanel() {
+		super(new GridBagLayout());
+
+		portNameField = new JTextField();
+		singleValueButton = new JRadioButton("Single value");
+		listValueButton = new JRadioButton("List of depth ");
+		listDepthSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 100, 1));
+
+		setBorder(new EmptyBorder(10, 10, 10, 10));
+
+		GridBagConstraints constraints = new GridBagConstraints();
+
+		constraints.anchor = WEST;
+		constraints.gridx = 0;
+		constraints.gridy = 0;
+		constraints.ipadx = 10;
+		add(new JLabel("Name:"), constraints);
+
+		constraints.gridx = 1;
+		constraints.gridwidth = 2;
+		constraints.ipadx = 0;
+		constraints.weightx = 1d;
+		constraints.fill = HORIZONTAL;
+		add(portNameField, constraints);
+
+		constraints.gridx = 0;
+		constraints.gridy = 1;
+		constraints.gridwidth = 1;
+		constraints.weightx = 0d;
+		constraints.fill = NONE;
+		constraints.ipadx = 10;
+		constraints.insets = new Insets(10, 0, 0, 0);
+		add(new JLabel("Type:"), constraints);
+
+		ButtonGroup buttonGroup = new ButtonGroup();
+		buttonGroup.add(singleValueButton);
+		buttonGroup.add(listValueButton);
+
+		final JLabel helpLabel = new JLabel(
+				"Depth 1 is a list, 2 is a list of lists, etc.");
+		helpLabel.setFont(helpLabel.getFont().deriveFont(11f));
+
+		singleValueButton.addItemListener(new ItemListener() {
+			@Override
+			public void itemStateChanged(ItemEvent e) {
+				boolean selected = (e.getStateChange() == SELECTED);
+				listDepthSpinner.setEnabled(!selected);
+				helpLabel.setEnabled(!selected);
+			}
+		});
+
+		constraints.gridx = 1;
+		constraints.gridwidth = 2;
+		constraints.ipadx = 0;
+		add(singleValueButton, constraints);
+		constraints.gridy = 2;
+		constraints.gridwidth = 1;
+		constraints.insets = new Insets(0, 0, 0, 0);
+		add(listValueButton, constraints);
+		constraints.gridx = 2;
+		add(listDepthSpinner, constraints);
+		constraints.gridx = 1;
+		constraints.gridy = 3;
+		constraints.gridwidth = 2;
+		constraints.weighty = 1d;
+		constraints.anchor = NORTHWEST;
+		constraints.insets = new Insets(0, 20, 0, 0);
+		add(helpLabel, constraints);
+	}
+
+	/**
+	 * Returns the portNameField.
+	 * 
+	 * @return the portNameField
+	 */
+	public JTextField getPortNameField() {
+		return portNameField;
+	}
+
+	/**
+	 * Returns the singleValueButton.
+	 * 
+	 * @return the singleValueButton
+	 */
+	public JRadioButton getSingleValueButton() {
+		return singleValueButton;
+	}
+
+	/**
+	 * Returns the listValueButton.
+	 * 
+	 * @return the listValueButton
+	 */
+	public JRadioButton getListValueButton() {
+		return listValueButton;
+	}
+
+	/**
+	 * Returns the port name.
+	 * 
+	 * @return the port name
+	 */
+	public String getPortName() {
+		return portNameField.getText();
+	}
+
+	/**
+	 * Sets the port name.
+	 * 
+	 * @param name
+	 *            the name of the port
+	 */
+	public void setPortName(String name) {
+		portNameField.setText(name);
+		// Select the text
+		if (!name.isEmpty()) {
+			portNameField.setSelectionStart(0);
+			portNameField.setSelectionEnd(name.length());
+		}
+	}
+
+	/**
+	 * Returns the port depth.
+	 * 
+	 * @return the port depth
+	 */
+	public int getPortDepth() {
+		if (singleValueButton.isSelected())
+			return 0;
+		return (Integer) listDepthSpinner.getValue();
+	}
+
+	/**
+	 * Sets the port depth.
+	 * 
+	 * @param depth
+	 *            the depth of the port
+	 */
+	public void setPortDepth(int depth) {
+		if (depth == 0) {
+			singleValueButton.setSelected(true);
+		} else {
+			listValueButton.setSelected(true);
+			listDepthSpinner.setValue(depth);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-design-ui/src/main/java/net/sf/taverna/t2/workbench/design/ui/DataflowOutputPortPanel.java
----------------------------------------------------------------------
diff --git a/taverna-design-ui/src/main/java/net/sf/taverna/t2/workbench/design/ui/DataflowOutputPortPanel.java b/taverna-design-ui/src/main/java/net/sf/taverna/t2/workbench/design/ui/DataflowOutputPortPanel.java
new file mode 100644
index 0000000..59ac0f7
--- /dev/null
+++ b/taverna-design-ui/src/main/java/net/sf/taverna/t2/workbench/design/ui/DataflowOutputPortPanel.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.design.ui;
+
+import static java.awt.GridBagConstraints.HORIZONTAL;
+import static java.awt.GridBagConstraints.VERTICAL;
+import static java.awt.GridBagConstraints.WEST;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * UI for creating/editing dataflow output ports.
+ * 
+ * @author David Withers
+ */
+public class DataflowOutputPortPanel extends JPanel {
+	private static final long serialVersionUID = -2542858679939965553L;
+
+	private JTextField portNameField;
+
+	public DataflowOutputPortPanel() {
+		super(new GridBagLayout());
+
+		portNameField = new JTextField();
+ 
+		setBorder(new EmptyBorder(10, 10, 10, 10));
+		
+		GridBagConstraints constraints = new GridBagConstraints();
+
+		constraints.anchor = WEST;
+		constraints.gridx = 0;
+		constraints.gridy = 0;
+		constraints.ipadx = 10;
+		add(new JLabel("Name:"), constraints);
+
+		constraints.gridx = 1;
+		constraints.gridwidth = 2;
+		constraints.ipadx = 0;
+		constraints.weightx = 1d;
+		constraints.fill = HORIZONTAL;
+		add(portNameField, constraints);
+
+		constraints.gridx = 0;
+		constraints.gridy = 1;
+		constraints.fill = VERTICAL;
+		constraints.weighty = 1d;
+		add(new JPanel(), constraints);
+	}
+	
+	/**
+	 * Returns the portNameField.
+	 *
+	 * @return the portNameField
+	 */
+	public JTextField getPortNameField() {
+		return portNameField;
+	}
+
+	/**
+	 * Returns the port name.
+	 *
+	 * @return the port name
+	 */
+	public String getPortName() {
+		return portNameField.getText();
+	}
+	
+	/**
+	 * Sets the port name.
+	 *
+	 * @param name the name of the port
+	 */
+	public void setPortName(String name) {
+		portNameField.setText(name);
+		// Select the text
+		if (!name.isEmpty()) {
+			portNameField.setSelectionStart(0);
+			portNameField.setSelectionEnd(name.length());
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-design-ui/src/main/java/net/sf/taverna/t2/workbench/design/ui/ProcessorPanel.java
----------------------------------------------------------------------
diff --git a/taverna-design-ui/src/main/java/net/sf/taverna/t2/workbench/design/ui/ProcessorPanel.java b/taverna-design-ui/src/main/java/net/sf/taverna/t2/workbench/design/ui/ProcessorPanel.java
new file mode 100644
index 0000000..4528727
--- /dev/null
+++ b/taverna-design-ui/src/main/java/net/sf/taverna/t2/workbench/design/ui/ProcessorPanel.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.design.ui;
+
+import static java.awt.GridBagConstraints.HORIZONTAL;
+import static java.awt.GridBagConstraints.VERTICAL;
+import static java.awt.GridBagConstraints.WEST;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * UI for editing processors.
+ * 
+ * @author David Withers
+ */
+public class ProcessorPanel extends JPanel {
+	private static final long serialVersionUID = 260705376633425003L;
+
+	private JTextField processorNameField;
+
+	public ProcessorPanel() {
+		super(new GridBagLayout());
+
+		processorNameField = new JTextField();
+
+		setBorder(new EmptyBorder(10, 10, 10, 10));
+
+		GridBagConstraints constraints = new GridBagConstraints();
+
+		constraints.anchor = WEST;
+		constraints.gridx = 0;
+		constraints.gridy = 0;
+		constraints.ipadx = 10;
+		add(new JLabel("Name:"), constraints);
+
+		constraints.gridx = 1;
+		constraints.gridwidth = 2;
+		constraints.ipadx = 0;
+		constraints.weightx = 1d;
+		constraints.fill = HORIZONTAL;
+		add(processorNameField, constraints);
+
+		constraints.gridx = 0;
+		constraints.gridy = 1;
+		constraints.fill = VERTICAL;
+		constraints.weighty = 1d;
+		add(new JPanel(), constraints);
+	}
+
+	/**
+	 * Returns the processorNameField.
+	 * 
+	 * @return the processorNameField
+	 */
+	public JTextField getProcessorNameField() {
+		return processorNameField;
+	}
+
+	/**
+	 * Returns the processor name.
+	 * 
+	 * @return the processor name
+	 */
+	public String getProcessorName() {
+		return processorNameField.getText();
+	}
+
+	/**
+	 * Sets the processor name.
+	 * 
+	 * @param name
+	 *            the name of the processor
+	 */
+	public void setProcessorName(String name) {
+		processorNameField.setText(name);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-edits-api/pom.xml b/taverna-edits-api/pom.xml
new file mode 100644
index 0000000..3ca3a59
--- /dev/null
+++ b/taverna-edits-api/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<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>org.apache.taverna.workbench</groupId>
+		<artifactId>taverna-workbench</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-edits-api</artifactId>
+	<packaging>bundle</packaging>
+	<name>Apache Edits API</name>
+	<description>API for doing workflow edits and undo.</description>
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-api</artifactId>
+			<version>${taverna.language.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-observer</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-databind</artifactId>
+			<version>${jackson.version}</version>
+		</dependency>
+	</dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/CompoundEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/CompoundEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/CompoundEdit.java
new file mode 100644
index 0000000..58c7add
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/CompoundEdit.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.edits;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.org.taverna.scufl2.api.common.WorkflowBean;
+
+/**
+ * Implementation of Edit which contains an ordered list of child edits. Child
+ * edits are applied collectively and in order, any failure in any child edit
+ * causes an undo of previously applied children and a propogation of the edit
+ * exception.
+ * 
+ * @author Tom Oinn
+ */
+public class CompoundEdit implements Edit<WorkflowBean> {
+	private final transient List<Edit<?>> childEdits;
+	private transient boolean applied = false;
+
+	/**
+	 * Create a new compound edit with no existing Edit objects.
+	 * 
+	 */
+	public CompoundEdit() {
+		this.childEdits = new ArrayList<>();
+	}
+
+	/**
+	 * Create a new compound edit with the specified edits as children.
+	 */
+	public CompoundEdit(List<Edit<?>> edits) {
+		this.childEdits = edits;
+	}
+
+	/**
+	 * Get the list of edits.
+	 * @return a live-editable list.
+	 */
+	public List<Edit<?>> getChildEdits() {
+		return childEdits;
+	}
+
+	/**
+	 * Attempts to call the doEdit method of all child edits. If any of those
+	 * children throws an EditException any successful edits are rolled back and
+	 * the exception is rethrown as the cause of a new EditException from the
+	 * CompoundEdit
+	 */
+	@Override
+	public synchronized WorkflowBean doEdit() throws EditException {
+		if (isApplied())
+			throw new EditException("Cannot apply an edit more than once!");
+		List<Edit<?>> doneEdits = new ArrayList<>();
+		try {
+			for (Edit<?> edit : childEdits) {
+				edit.doEdit();
+				/*
+				 * Insert the done edit at position 0 in the list so we can
+				 * iterate over the list in the normal order if we need to
+				 * rollback, this ensures that the most recent edit is first.
+				 */
+				doneEdits.add(0, edit);
+			}
+			applied = true;
+		} catch (EditException ee) {
+			for (Edit<?> undoMe : doneEdits)
+				undoMe.undo();
+			applied = false;
+			throw new EditException("Failed child of compound edit", ee);
+		}
+		return null;
+	}
+
+	/**
+	 * There is no explicit subject for a compound edit, so this method always
+	 * returns null.
+	 */
+	@Override
+	public Object getSubject() {
+		return null;
+	}
+
+	/**
+	 * Rolls back all child edits in reverse order
+	 */
+	@Override
+	public synchronized void undo() {
+		for (int i = childEdits.size() - 1; i >= 0; i--)
+			// Undo child edits in reverse order
+			childEdits.get(i).undo();
+		applied = false;
+	}
+
+	@Override
+	public boolean isApplied() {
+		return applied;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/Edit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/Edit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/Edit.java
new file mode 100644
index 0000000..fad211e
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/Edit.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.edits;
+
+import uk.org.taverna.scufl2.api.common.WorkflowBean;
+
+/**
+ * The workflow object model exposed by this API is read only. Properties of the
+ * model can only be changed through implementations of this interface, this
+ * ensures a consistant approach to grouped edits (transactions) and undo / redo
+ * support within the UI. It also potentially allows for capture of editing
+ * provenance where a workflow is repurposed or created from an aggregate of
+ * several others.
+ * 
+ * @author Tom Oinn
+ */
+public interface Edit<TargetType extends WorkflowBean> {
+	/**
+	 * Perform the edit
+	 * 
+	 * @throws EditException
+	 *             if the edit fails. If an edit throws EditException it should
+	 *             try to ensure the subject is unaltered. Where this is
+	 *             impossible consider breaking edits down into a compound edit.
+	 */
+	TargetType doEdit() throws EditException;
+
+	/**
+	 * Undo the edit, reverting the subject to the state it was in prior to the
+	 * edit
+	 */
+	void undo();
+
+	/**
+	 * Return the object to which this edit applies
+	 * 
+	 * @return
+	 */
+	Object getSubject();
+
+	/**
+	 * Has the edit been applied yet?
+	 * 
+	 * @return true if and only if the edit has been successfully applied to the
+	 *         subject
+	 */
+	boolean isApplied();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/EditException.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/EditException.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/EditException.java
new file mode 100644
index 0000000..3c61d84
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/EditException.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.edits;
+
+/**
+ * Superclass of all exceptions thrown when altering the workflow model through
+ * the edit manager.
+ * 
+ * @author Tom Oinn
+ */
+@SuppressWarnings("serial")
+public class EditException extends Exception {
+	public EditException(String string) {
+		super(string);
+	}
+
+	public EditException(String string, Throwable cause) {
+		super(string, cause);
+	}
+
+	public EditException(Throwable t) {
+		super(t);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/EditManager.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/EditManager.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/EditManager.java
new file mode 100644
index 0000000..ce8b917
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/EditManager.java
@@ -0,0 +1,222 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.edits;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.workbench.edits.EditManager.EditManagerEvent;
+
+/**
+ * Manager that can handle {@link Edit edits} for a {@link WorkflowBundle}.
+ * <p>
+ * Edits to a workflow that are to be undoable or redoable should be created by
+ * using {@link EditManager#getEdits()} to get an {@link Edits} object. Using
+ * this to create {@link Edit}s, instead of calling {@link Edit#doEdit()}, use
+ * {@link EditManager#doDataflowEdit(WorkflowBundle, Edit)} to associate the
+ * edit with the specified Dataflow.
+ * <p>
+ * It is possible to undo a series of edits done on a particular dataflow in
+ * this way by using {@link #undoDataflowEdit(WorkflowBundle)}. If one or more
+ * undoes have been performed, they can be redone step by step using
+ * {@link #redoDataflowEdit(WorkflowBundle)}. Note that it is no longer possible
+ * to call {@link #redoDataflowEdit(WorkflowBundle)} after a
+ * {@link #doDataflowEdit(WorkflowBundle, Edit)}.
+ * <p>
+ * The EditManager is {@link Observable}. If you
+ * {@linkplain Observable#addObserver(net.sf.taverna.t2.lang.observer.Observer)
+ * add an observer} you can be notified on {@linkplain DataflowEditEvent edits},
+ * {@linkplain DataFlowUndoEvent undoes} and {@linkplain DataFlowRedoEvent
+ * redoes}.
+ * 
+ * @author Stian Soiland-Reyes
+ */
+public interface EditManager extends Observable<EditManagerEvent> {
+	/**
+	 * <code>true</code> if {@link #redoDataflowEdit(WorkflowBundle)} on the
+	 * given dataflow would redo the last undone edit. If there are no previous
+	 * edits, return <code>false</code>.
+	 * 
+	 * @param dataflow
+	 *            {@link WorkflowBundle} which last affecting edit is to be
+	 *            undone
+	 * @return <code>true</code if and only if
+	 *         {@link #redoDataflowEdit(WorkflowBundle)} would undo
+	 */
+	boolean canRedoDataflowEdit(WorkflowBundle dataflow);
+
+	/**
+	 * <code>true</code> if {@link #undoDataflowEdit(WorkflowBundle)} on the
+	 * given dataflow would undo the last edit. If there are no previous edits,
+	 * return <code>false</code>.
+	 * 
+	 * @param dataflow
+	 *            {@link WorkflowBundle} which last affecting edit is to be
+	 *            undone
+	 * @return <code>true</code if {@link #undoDataflowEdit(WorkflowBundle)}
+	 *         would undo
+	 */
+	boolean canUndoDataflowEdit(WorkflowBundle dataflow);
+
+	/**
+	 * Do an {@link Edit} affecting the given {@link WorkflowBundle}.
+	 * <p>
+	 * The edit is {@link Edit#doEdit() performed} and the edit can later be
+	 * undone using {@link EditManager#undoDataflowEdit(WorkflowBundle)}.
+	 * <p>
+	 * Note that any events previously undone with
+	 * {@link EditManager#undoDataflowEdit(WorkflowBundle)} for the given
+	 * dataflow can no longer be
+	 * {@link EditManager#redoDataflowEdit(WorkflowBundle) redone} after calling
+	 * this method.
+	 * 
+	 * @see EditManager#undoDataflowEdit(WorkflowBundle)
+	 * @param dataflow
+	 *            {@link WorkflowBundle} this edit is affecting
+	 * @param edit
+	 *            {@link Edit} that should be done using {@link Edit#doEdit()}.
+	 * @throws EditException
+	 *             If {@link Edit#doEdit()} fails
+	 */
+	void doDataflowEdit(WorkflowBundle dataflow, Edit<?> edit)
+			throws EditException;
+
+	/**
+	 * Redo the last {@link Edit} that was undone using
+	 * {@link #undoDataflowEdit(WorkflowBundle)}.
+	 * <p>
+	 * Note that the {@link EditManager} might only be able to redo a reasonable
+	 * number of steps.
+	 * <p>
+	 * It is not possible to use {@link #redoDataflowEdit(WorkflowBundle)} after
+	 * a {@link #doDataflowEdit(WorkflowBundle, Edit)} affecting the same
+	 * {@link WorkflowBundle}, or if no edits have been undone yet. No action
+	 * would be taken in these cases.
+	 * 
+	 * @param dataflow
+	 *            {@link WorkflowBundle} which last affecting edit is to be
+	 *            redone
+	 * @throws EditException
+	 *             If {@link Edit#doEdit()} fails
+	 */
+	void redoDataflowEdit(WorkflowBundle dataflow) throws EditException;
+
+	/**
+	 * Undo the last {@link Edit} affecting the given {@link WorkflowBundle}.
+	 * <p>
+	 * This can be called in succession until there are no more known undoes.
+	 * Note that the {@link EditManager} might only be able to undo a reasonable
+	 * number of steps.
+	 * <p>
+	 * The last edit must have been performed using
+	 * {@link EditManager#doDataflowEdit(WorkflowBundle, Edit)} or
+	 * {@link EditManager#redoDataflowEdit(WorkflowBundle)}. The undo is done
+	 * using {@link Edit#undo()}. If no edits have been performed for the
+	 * dataflow yet, no action is taken.
+	 * <p>
+	 * Undoes can be redone using {@link #redoDataflowEdit(WorkflowBundle)}.
+	 * 
+	 * @param dataflow
+	 *            {@link WorkflowBundle} which last affecting edit is to be
+	 *            undone
+	 */
+	void undoDataflowEdit(WorkflowBundle dataflow);
+
+	/**
+	 * An event about an {@link Edit} on a {@link WorkflowBundle}, accessible
+	 * through {@link AbstractDataflowEditEvent#getEdit()} and
+	 * {@link AbstractDataflowEditEvent#getDataFlow()}.
+	 */
+	public static abstract class AbstractDataflowEditEvent implements
+			EditManagerEvent {
+		private final WorkflowBundle dataFlow;
+		private final Edit<?> edit;
+
+		public AbstractDataflowEditEvent(WorkflowBundle dataFlow, Edit<?> edit) {
+			if (dataFlow == null || edit == null)
+				throw new NullPointerException(
+						"Dataflow and/or Edit can't be null");
+			this.dataFlow = dataFlow;
+			this.edit = edit;
+		}
+
+		/**
+		 * The {@link WorkflowBundle} this event affected.
+		 * 
+		 * @return A {@link WorkflowBundle}
+		 */
+		public WorkflowBundle getDataFlow() {
+			return dataFlow;
+		}
+
+		/**
+		 * The {@link Edit} that was performed, undoed or redone on the
+		 * {@link #getDataFlow() dataflow}.
+		 * 
+		 * @return An {@link Edit}
+		 */
+		@Override
+		public Edit<?> getEdit() {
+			return edit;
+		}
+	}
+
+	/**
+	 * An event sent when an {@link Edit} has been performed on a
+	 * {@link WorkflowBundle}.
+	 * 
+	 */
+	public static class DataflowEditEvent extends AbstractDataflowEditEvent {
+		public DataflowEditEvent(WorkflowBundle dataFlow, Edit<?> edit) {
+			super(dataFlow, edit);
+		}
+	}
+
+	/**
+	 * An event sent when a previously undone {@link Edit} has been redone on a
+	 * {@link WorkflowBundle}.
+	 * 
+	 */
+	public static class DataFlowRedoEvent extends AbstractDataflowEditEvent {
+		public DataFlowRedoEvent(WorkflowBundle dataFlow, Edit<?> edit) {
+			super(dataFlow, edit);
+		}
+	}
+
+	/**
+	 * An event sent when an {@link Edit} has been undone on a
+	 * {@link WorkflowBundle}.
+	 * 
+	 */
+	public static class DataFlowUndoEvent extends AbstractDataflowEditEvent {
+		public DataFlowUndoEvent(WorkflowBundle dataFlow, Edit<?> edit) {
+			super(dataFlow, edit);
+		}
+	}
+
+	/**
+	 * An event given to {@link Observer}s registered with
+	 * {@link Observable#addObserver(Observer)}.
+	 */
+	public interface EditManagerEvent {
+		public Edit<?> getEdit();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/package-info.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/package-info.java
new file mode 100644
index 0000000..c1df7c9
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workbench/edits/package-info.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+/**
+ * A {@link net.sf.taverna.t2.workbench.edits.EditManager} that can manage
+ * {@link net.sf.taverna.t2.workflowmodel.Edit}s performed from the UI.
+ * <p>
+ * To perform an edit that is to be undoable, use
+ * {@link EditManager#doDataflowEdit(net.sf.taverna.t2.workflowmodel.Dataflow, net.sf.taverna.t2.workflowmodel.Edit)}
+ * instead of {@link net.sf.taverna.t2.workflowmodel.Edit#doEdit()}. Such edits
+ * can be
+ * {@link EditManager#undoDataflowEdit(net.sf.taverna.t2.workflowmodel.Dataflow) undone}
+ * and
+ * {@link EditManager#redoDataflowEdit(net.sf.taverna.t2.workflowmodel.Dataflow) redone}.
+ * </p>
+ * <p>
+ * Edits are organised by {@link net.sf.taverna.t2.workflowmodel.Dataflow} so
+ * that if a user changes the active workflow in the Workbench and does "Undo" -
+ * that would undo the last undo done related to that workflow.
+ * </p>
+ * <p>
+ * The {@link net.sf.taverna.t2.workbench.edits.impl} implementation of the
+ * EditManager is discovered by {@link net.sf.taverna.t2.workbench.edits.EditManager#getInstance()}. The
+ * implementation also includes {@link net.sf.taverna.t2.ui.menu.MenuComponent}s
+ * for Undo and Redo.
+ * </p>
+ * 
+ * @author Stian Soiland-Reyes
+ * 
+ */
+package net.sf.taverna.t2.workbench.edits;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AbstractEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AbstractEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AbstractEdit.java
new file mode 100644
index 0000000..e6c8e68
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AbstractEdit.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (C) 2007-2008 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.workflow.edits;
+
+import net.sf.taverna.t2.workbench.edits.Edit;
+import net.sf.taverna.t2.workbench.edits.EditException;
+import uk.org.taverna.scufl2.api.common.Scufl2Tools;
+import uk.org.taverna.scufl2.api.common.WorkflowBean;
+
+/**
+ * An abstract {@link Edit} implementation that checks if an edit has been
+ * applied or not.
+ *
+ * @author Stian Soiland-Reyes
+ *
+ * @param <Subject>
+ *            Subject of this edit
+ */
+public abstract class AbstractEdit<Subject extends WorkflowBean> implements
+		Edit<Subject> {
+	private boolean applied = false;
+	private final Subject subject;
+	protected final Scufl2Tools scufl2Tools = new Scufl2Tools();
+
+	/**
+	 * Construct an AbstractEdit.
+	 *
+	 * @param subjectType
+	 *            The expected implementation type of the subject. The edit will
+	 *            not go through unless the subject is an instance of this type.
+	 *            If the edit don't care about the implementation type, provide
+	 *            the official SubjectInterface instead.
+	 * @param subject
+	 *            The subject of this edit
+	 */
+	public AbstractEdit(Subject subject) {
+		if (subject == null && !isNullSubjectAllowed())
+			throw new IllegalArgumentException(
+					"Cannot construct an edit with null subject");
+		this.subject = subject;
+	}
+
+	protected boolean isNullSubjectAllowed() {
+		return false;
+	}
+
+	@Override
+	public final Subject doEdit() throws EditException {
+		if (applied)
+			throw new EditException("Edit has already been applied!");
+		try {
+			synchronized (subject) {
+				doEditAction(subject);
+				applied = true;
+				return this.subject;
+			}
+		} catch (EditException ee) {
+			applied = false;
+			throw ee;
+		}
+	}
+
+	/**
+	 * Do the actual edit here
+	 *
+	 * @param subject
+	 *            The instance to which the edit applies
+	 * @throws EditException
+	 */
+	protected abstract void doEditAction(Subject subject)
+			throws EditException;
+
+	/**
+	 * Undo any edit effects here
+	 *
+	 * @param subject
+	 *            The instance to which the edit applies
+	 */
+	protected abstract void undoEditAction(Subject subject);
+
+	@Override
+	public final Subject getSubject() {
+		return subject;
+	}
+
+	@Override
+	public final boolean isApplied() {
+		return applied;
+	}
+
+	@Override
+	public final void undo() {
+		if (!applied)
+			throw new RuntimeException(
+					"Attempt to undo edit that was never applied");
+		synchronized (subject) {
+			undoEditAction(subject);
+			applied = false;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddActivityEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddActivityEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddActivityEdit.java
new file mode 100644
index 0000000..c6ffa7c
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddActivityEdit.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (C) 2012 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.workflow.edits;
+
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.core.Processor;
+import uk.org.taverna.scufl2.api.profiles.ProcessorBinding;
+
+/**
+ * Creates a ProcessorBinding binding for the Activity and Processor and adds the binding to the
+ * Profile containing the Activity.
+ *
+ * @author David Withers
+ */
+public class AddActivityEdit extends AbstractEdit<Processor> {
+	private Activity activity;
+	private ProcessorBinding addedProcessorBinding;
+
+	public AddActivityEdit(Processor processor, Activity activity) {
+		super(processor);
+		this.activity = activity;
+	}
+
+	@Override
+	protected void doEditAction(Processor processor) {
+		ProcessorBinding binding = new ProcessorBinding();
+		binding.setBoundProcessor(processor);
+		binding.setBoundActivity(activity);
+		binding.setParent(activity.getParent());
+		addedProcessorBinding = binding;
+	}
+
+	@Override
+	protected void undoEditAction(Processor processor) {
+		addedProcessorBinding.setParent(null);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddActivityInputPortMappingEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddActivityInputPortMappingEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddActivityInputPortMappingEdit.java
new file mode 100644
index 0000000..9a7e8b7
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddActivityInputPortMappingEdit.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * 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.workflow.edits;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.port.InputActivityPort;
+import uk.org.taverna.scufl2.api.port.InputProcessorPort;
+import uk.org.taverna.scufl2.api.profiles.ProcessorBinding;
+import uk.org.taverna.scufl2.api.profiles.ProcessorInputPortBinding;
+
+public class AddActivityInputPortMappingEdit extends AbstractEdit<Activity> {
+	private final InputProcessorPort inputProcessorPort;
+	private final InputActivityPort inputActivityPort;
+	private List<ProcessorInputPortBinding> portBindings;
+
+	public AddActivityInputPortMappingEdit(Activity activity,
+			InputProcessorPort inputProcessorPort,
+			InputActivityPort inputActivityPort) {
+		super(activity);
+		this.inputProcessorPort = inputProcessorPort;
+		this.inputActivityPort = inputActivityPort;
+	}
+
+	@Override
+	protected void doEditAction(Activity activity) {
+		portBindings = new ArrayList<>();
+		for (ProcessorBinding binding : scufl2Tools
+				.processorBindingsToActivity(activity))
+			portBindings.add(new ProcessorInputPortBinding(binding,
+					inputProcessorPort, inputActivityPort));
+	}
+
+	@Override
+	protected void undoEditAction(Activity activity) {
+		for (ProcessorInputPortBinding binding : portBindings)
+			binding.setParent(null);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddActivityOutputPortMappingEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddActivityOutputPortMappingEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddActivityOutputPortMappingEdit.java
new file mode 100644
index 0000000..edafe8e
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddActivityOutputPortMappingEdit.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * 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.workflow.edits;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.port.OutputActivityPort;
+import uk.org.taverna.scufl2.api.port.OutputProcessorPort;
+import uk.org.taverna.scufl2.api.profiles.ProcessorBinding;
+import uk.org.taverna.scufl2.api.profiles.ProcessorOutputPortBinding;
+
+public class AddActivityOutputPortMappingEdit extends AbstractEdit<Activity> {
+	private final OutputProcessorPort outputProcessorPort;
+	private final OutputActivityPort outputActivityPort;
+	private List<ProcessorOutputPortBinding> portBindings;
+
+	public AddActivityOutputPortMappingEdit(Activity activity,
+			OutputProcessorPort outputProcessorPort,
+			OutputActivityPort outputActivityPort) {
+		super(activity);
+		this.outputProcessorPort = outputProcessorPort;
+		this.outputActivityPort = outputActivityPort;
+	}
+
+	@Override
+	protected void doEditAction(Activity activity) {
+		portBindings = new ArrayList<>();
+		for (ProcessorBinding binding : scufl2Tools
+				.processorBindingsToActivity(activity))
+			portBindings.add(new ProcessorOutputPortBinding(binding,
+					outputActivityPort, outputProcessorPort));
+	}
+
+	@Override
+	protected void undoEditAction(Activity activity) {
+		for (ProcessorOutputPortBinding binding : portBindings)
+			binding.setParent(null);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddChildEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddChildEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddChildEdit.java
new file mode 100644
index 0000000..abd8d9f
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddChildEdit.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (C) 2012 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.workflow.edits;
+
+import uk.org.taverna.scufl2.api.common.Child;
+import uk.org.taverna.scufl2.api.common.WorkflowBean;
+
+/**
+ * Adds a child to a parent.
+ *
+ * @author David Withers
+ */
+public class AddChildEdit<T extends WorkflowBean> extends AbstractEdit<T> {
+	private Child<T> child;
+
+	public AddChildEdit(T parent, Child<T> child) {
+		super(parent);
+		this.child = child;
+	}
+
+	@Override
+	protected void doEditAction(T parent) {
+		child.setParent(parent);
+	}
+
+	@Override
+	protected void undoEditAction(T parent) {
+		child.setParent(null);
+	}
+
+	public Child<T> getChild() {
+		return child;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddDataLinkEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddDataLinkEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddDataLinkEdit.java
new file mode 100644
index 0000000..10ff290
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddDataLinkEdit.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (C) 2012 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.workflow.edits;
+
+import java.util.List;
+
+import uk.org.taverna.scufl2.api.core.DataLink;
+import uk.org.taverna.scufl2.api.core.Workflow;
+import uk.org.taverna.scufl2.api.iterationstrategy.CrossProduct;
+import uk.org.taverna.scufl2.api.iterationstrategy.DotProduct;
+import uk.org.taverna.scufl2.api.iterationstrategy.IterationStrategyParent;
+import uk.org.taverna.scufl2.api.iterationstrategy.IterationStrategyTopNode;
+import uk.org.taverna.scufl2.api.iterationstrategy.PortNode;
+import uk.org.taverna.scufl2.api.port.InputProcessorPort;
+import uk.org.taverna.scufl2.api.port.ReceiverPort;
+
+/**
+ * Adds a DataLink to a Workflow.
+ * <p>
+ * Handles setting the merge position of all dataLinks with the same receiver port.
+ * <p>
+ * Modifies the processor's iteration strategy or when the first DataLink is added.
+ *
+ * @author David Withers
+ */
+public class AddDataLinkEdit extends AbstractEdit<Workflow> {
+	private DataLink dataLink;
+	private PortNode portNode;
+
+	public AddDataLinkEdit(Workflow workflow, DataLink dataLink) {
+		super(workflow);
+		this.dataLink = dataLink;
+	}
+
+	@Override
+	protected void doEditAction(Workflow workflow) {
+		ReceiverPort sink = dataLink.getSendsTo();
+		List<DataLink> datalinksTo = scufl2Tools.datalinksTo(sink);
+		if (datalinksTo.size() > 0) {
+			if (datalinksTo.size() == 1)
+				datalinksTo.get(0).setMergePosition(0);
+			dataLink.setMergePosition(datalinksTo.size());
+		} else {
+			dataLink.setMergePosition(null);
+			if (sink instanceof InputProcessorPort) {
+				InputProcessorPort inputProcessorPort = (InputProcessorPort) sink;
+				for (IterationStrategyTopNode node : inputProcessorPort.getParent().getIterationStrategyStack()) {
+					portNode = new PortNode(node, inputProcessorPort);
+					portNode.setDesiredDepth(inputProcessorPort.getDepth());
+					break;
+				}
+			}
+		}
+		dataLink.setParent(workflow);
+	}
+
+	@Override
+	protected void undoEditAction(Workflow workflow) {
+		dataLink.setParent(null);
+		ReceiverPort sink = dataLink.getSendsTo();
+		List<DataLink> datalinksTo = scufl2Tools.datalinksTo(sink);
+		if (datalinksTo.size() == 1)
+			datalinksTo.get(0).setMergePosition(null);
+		else if (datalinksTo.isEmpty()&&portNode != null) {
+			IterationStrategyParent parent = portNode.getParent();
+			if (parent instanceof DotProduct)
+				((DotProduct) parent).remove(portNode);
+			else if (parent instanceof CrossProduct)
+				((CrossProduct) parent).remove(portNode);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddIterationStrategyEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddIterationStrategyEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddIterationStrategyEdit.java
new file mode 100644
index 0000000..8677352
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddIterationStrategyEdit.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (C) 2011 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.workflow.edits;
+
+import uk.org.taverna.scufl2.api.iterationstrategy.IterationStrategyStack;
+import uk.org.taverna.scufl2.api.iterationstrategy.IterationStrategyTopNode;
+
+/**
+ * Adds an IterationStrategyTopNode to an IterationStrategyStack.
+ *
+ * @author David Withers
+ */
+public class AddIterationStrategyEdit extends AbstractEdit<IterationStrategyStack> {
+	private final IterationStrategyTopNode iterationStrategyTopNode;
+
+	public AddIterationStrategyEdit(IterationStrategyStack iterationStrategyStack,
+			IterationStrategyTopNode iterationStrategyTopNode) {
+		super(iterationStrategyStack);
+		this.iterationStrategyTopNode = iterationStrategyTopNode;
+	}
+
+	@Override
+	public void doEditAction(IterationStrategyStack iterationStrategyStack) {
+		iterationStrategyStack.add(iterationStrategyTopNode);
+	}
+
+	@Override
+	public void undoEditAction(IterationStrategyStack iterationStrategyStack) {
+		iterationStrategyStack.remove(iterationStrategyTopNode);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddIterationStrategyInputPortEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddIterationStrategyInputPortEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddIterationStrategyInputPortEdit.java
new file mode 100644
index 0000000..bb51fc6
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddIterationStrategyInputPortEdit.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (C) 2011 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.workflow.edits;
+
+import uk.org.taverna.scufl2.api.iterationstrategy.IterationStrategyStack;
+import uk.org.taverna.scufl2.api.iterationstrategy.PortNode;
+
+/**
+ * Adds an iteration strategy input port node to an iteration strategy.
+ * 
+ * @author David Withers
+ */
+public class AddIterationStrategyInputPortEdit extends
+		AbstractEdit<IterationStrategyStack> {
+	private final PortNode portNode;
+
+	public AddIterationStrategyInputPortEdit(
+			IterationStrategyStack iterationStrategy, PortNode portNode) {
+		super(iterationStrategy);
+		this.portNode = portNode;
+	}
+
+	@Override
+	public void doEditAction(IterationStrategyStack iterationStrategy) {
+		portNode.setParent(iterationStrategy.get(0));
+	}
+
+	@Override
+	public void undoEditAction(IterationStrategyStack iterationStrategy) {
+		portNode.setParent(null);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddProcessorEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddProcessorEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddProcessorEdit.java
new file mode 100644
index 0000000..04cf73b
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddProcessorEdit.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * 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.workflow.edits;
+
+import uk.org.taverna.scufl2.api.core.Processor;
+import uk.org.taverna.scufl2.api.core.Workflow;
+
+/**
+ * Adds a Processor to a Workflow.
+ *
+ * @author Stuart Owen
+ * @author David Withers
+ */
+public class AddProcessorEdit extends AddChildEdit<Workflow> {
+	private Processor processor;
+
+	public AddProcessorEdit(Workflow workflow, Processor processor) {
+		super(workflow, processor);
+		this.processor = processor;
+	}
+
+	@Override
+	protected void doEditAction(Workflow workflow) {
+		getSubject().getProcessors().addWithUniqueName(processor);
+		super.doEditAction(workflow);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddProcessorInputPortEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddProcessorInputPortEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddProcessorInputPortEdit.java
new file mode 100644
index 0000000..f722ddc
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddProcessorInputPortEdit.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * 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.workflow.edits;
+
+import uk.org.taverna.scufl2.api.core.Processor;
+import uk.org.taverna.scufl2.api.port.InputProcessorPort;
+
+/**
+ * Adds an input port to a processor.
+ *
+ * @author Tom Oinn
+ * @author David Withers
+ */
+public class AddProcessorInputPortEdit extends AddChildEdit<Processor> {
+	private final InputProcessorPort port;
+
+	public AddProcessorInputPortEdit(Processor processor, InputProcessorPort port) {
+		super(processor, port);
+		this.port = port;
+	}
+
+	@Override
+	protected void doEditAction(Processor processor) {
+		processor.getInputPorts().addWithUniqueName(port);
+		super.doEditAction(processor);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddProcessorOutputPortEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddProcessorOutputPortEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddProcessorOutputPortEdit.java
new file mode 100644
index 0000000..eec51b1
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddProcessorOutputPortEdit.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * 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.workflow.edits;
+
+import uk.org.taverna.scufl2.api.core.Processor;
+import uk.org.taverna.scufl2.api.port.OutputProcessorPort;
+
+/**
+ * Adds an output port to a processor.
+ * 
+ * @author Tom Oinn
+ * @author David Withers
+ */
+public class AddProcessorOutputPortEdit extends AddChildEdit<Processor> {
+	private final OutputProcessorPort port;
+
+	public AddProcessorOutputPortEdit(Processor processor,
+			OutputProcessorPort port) {
+		super(processor, port);
+		this.port = port;
+	}
+
+	@Override
+	protected void doEditAction(Processor processor) {
+		processor.getOutputPorts().addWithUniqueName(port);
+		super.doEditAction(processor);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddWorkflowInputPortEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddWorkflowInputPortEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddWorkflowInputPortEdit.java
new file mode 100644
index 0000000..91a9153
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddWorkflowInputPortEdit.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * 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.workflow.edits;
+
+import static uk.org.taverna.scufl2.api.common.Scufl2Tools.NESTED_WORKFLOW;
+
+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.workbench.edits.EditException;
+import uk.org.taverna.scufl2.api.activity.Activity;
+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.port.InputActivityPort;
+import uk.org.taverna.scufl2.api.port.InputProcessorPort;
+import uk.org.taverna.scufl2.api.port.InputWorkflowPort;
+import uk.org.taverna.scufl2.api.profiles.ProcessorBinding;
+import uk.org.taverna.scufl2.api.profiles.ProcessorInputPortBinding;
+import uk.org.taverna.scufl2.api.profiles.Profile;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * Adds an input port to a workflow.
+ * 
+ * @author David Withers
+ */
+public class AddWorkflowInputPortEdit extends AbstractEdit<Workflow> {
+	private final InputWorkflowPort port;
+	private final CompoundEdit nestedPortEdit = new CompoundEdit();
+
+	public AddWorkflowInputPortEdit(Workflow workflow, InputWorkflowPort port) {
+		super(workflow);
+		this.port = port;
+		WorkflowBundle workflowBundle = workflow.getParent();
+		if (workflowBundle != null)
+			for (Profile profile : workflowBundle.getProfiles())
+				for (Activity activity : profile.getActivities())
+					if (activity.getType().equals(NESTED_WORKFLOW))
+						for (Configuration c : scufl2Tools.configurationsFor(
+								activity, profile))
+							defineEditsForOneConfiguration(workflow, port,
+									workflowBundle, activity, c);
+	}
+
+	private void defineEditsForOneConfiguration(Workflow workflow,
+			InputWorkflowPort port, WorkflowBundle workflowBundle,
+			Activity activity, Configuration c) {
+		List<Edit<?>> edits = nestedPortEdit.getChildEdits();
+		JsonNode nested = c.getJson().get("nestedWorkflow");
+		Workflow nestedWorkflow = workflowBundle.getWorkflows().getByName(
+				nested.asText());
+
+		if (nestedWorkflow == workflow) {
+			InputActivityPort activityPort = new InputActivityPort();
+			activityPort.setName(port.getName());
+			activityPort.setDepth(port.getDepth());
+			edits.add(new AddChildEdit<>(activity, activityPort));
+
+			for (ProcessorBinding binding : scufl2Tools
+					.processorBindingsToActivity(activity)) {
+				Processor processor = binding.getBoundProcessor();
+				InputProcessorPort processorPort = new InputProcessorPort();
+				processorPort.setName(port.getName());
+				processorPort.setDepth(port.getDepth());
+				edits.add(new AddProcessorInputPortEdit(processor,
+						processorPort));
+
+				ProcessorInputPortBinding portBinding = new ProcessorInputPortBinding();
+				portBinding.setBoundProcessorPort(processorPort);
+				portBinding.setBoundActivityPort(activityPort);
+				edits.add(new AddChildEdit<>(binding, portBinding));
+			}
+		}
+	}
+
+	@Override
+	protected void doEditAction(Workflow workflow) throws EditException {
+		workflow.getInputPorts().addWithUniqueName(port);
+		port.setParent(workflow);
+		nestedPortEdit.doEdit();
+	}
+
+	@Override
+	protected void undoEditAction(Workflow workflow) {
+		port.setParent(null);
+		nestedPortEdit.undo();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddWorkflowOutputPortEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddWorkflowOutputPortEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddWorkflowOutputPortEdit.java
new file mode 100644
index 0000000..7e505f1
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/AddWorkflowOutputPortEdit.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * 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.workflow.edits;
+
+import static uk.org.taverna.scufl2.api.common.Scufl2Tools.NESTED_WORKFLOW;
+
+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.workbench.edits.EditException;
+import uk.org.taverna.scufl2.api.activity.Activity;
+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.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.ProcessorOutputPortBinding;
+import uk.org.taverna.scufl2.api.profiles.Profile;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * Adds an output port to a workflow.
+ *
+ * @author David Withers
+ */
+public class AddWorkflowOutputPortEdit extends AbstractEdit<Workflow> {
+	private final OutputWorkflowPort port;
+	private final CompoundEdit nestedPortEdit = new CompoundEdit();
+
+	public AddWorkflowOutputPortEdit(Workflow workflow, OutputWorkflowPort port) {
+		super(workflow);
+		this.port = port;
+		WorkflowBundle workflowBundle = workflow.getParent();
+		if (workflowBundle != null)
+			for (Profile profile : workflowBundle.getProfiles())
+				for (Activity activity : profile.getActivities())
+					if (activity.getType().equals(NESTED_WORKFLOW))
+						for (Configuration c : scufl2Tools.configurationsFor(
+								activity, profile))
+							defineEditsForOneConfiguration(workflow, port,
+									workflowBundle, activity, c);
+	}
+
+	private void defineEditsForOneConfiguration(Workflow workflow,
+			OutputWorkflowPort port, WorkflowBundle workflowBundle,
+			Activity activity, Configuration c) {
+		List<Edit<?>> edits = nestedPortEdit.getChildEdits();
+		JsonNode nested = c.getJson().get("nestedWorkflow");
+		Workflow nestedWorkflow = workflowBundle.getWorkflows().getByName(
+				nested.asText());
+		if (nestedWorkflow == workflow) {
+			OutputActivityPort activityPort = new OutputActivityPort();
+			activityPort.setName(port.getName());
+			activityPort.setDepth(0);
+			activityPort.setGranularDepth(0);
+			edits.add(new AddChildEdit<>(activity, activityPort));
+
+			for (ProcessorBinding binding : scufl2Tools
+					.processorBindingsToActivity(activity)) {
+				Processor processor = binding.getBoundProcessor();
+				OutputProcessorPort processorPort = new OutputProcessorPort();
+				processorPort.setName(port.getName());
+				processorPort.setDepth(0);
+				processorPort.setGranularDepth(0);
+				edits.add(new AddProcessorOutputPortEdit(processor,
+						processorPort));
+
+				ProcessorOutputPortBinding portBinding = new ProcessorOutputPortBinding();
+				portBinding.setBoundProcessorPort(processorPort);
+				portBinding.setBoundActivityPort(activityPort);
+				edits.add(new AddChildEdit<>(binding, portBinding));
+			}
+		}
+	}
+
+	@Override
+	protected void doEditAction(Workflow workflow) throws EditException {
+		workflow.getOutputPorts().addWithUniqueName(port);
+		port.setParent(workflow);
+		nestedPortEdit.doEdit();
+	}
+
+	@Override
+	protected void undoEditAction(Workflow workflow) {
+		port.setParent(null);
+		nestedPortEdit.undo();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/ChangeDepthEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/ChangeDepthEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/ChangeDepthEdit.java
new file mode 100644
index 0000000..071b653
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/ChangeDepthEdit.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (C) 2012 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.workflow.edits;
+
+import static uk.org.taverna.scufl2.api.common.Scufl2Tools.NESTED_WORKFLOW;
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.configurations.Configuration;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.core.Workflow;
+import uk.org.taverna.scufl2.api.port.ActivityPort;
+import uk.org.taverna.scufl2.api.port.DepthPort;
+import uk.org.taverna.scufl2.api.port.InputProcessorPort;
+import uk.org.taverna.scufl2.api.port.InputWorkflowPort;
+import uk.org.taverna.scufl2.api.profiles.ProcessorBinding;
+import uk.org.taverna.scufl2.api.profiles.ProcessorInputPortBinding;
+import uk.org.taverna.scufl2.api.profiles.Profile;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * Changes the depth of a port.
+ *
+ * @author David Withers
+ */
+public class ChangeDepthEdit<T extends DepthPort> extends AbstractEdit<T> {
+	private Integer newDepth, oldDepth;
+
+	public ChangeDepthEdit(T depthPort, Integer newDepth) {
+		super(depthPort);
+		this.newDepth = newDepth;
+		oldDepth = depthPort.getDepth();
+	}
+
+	@Override
+	protected void doEditAction(T depthPort) {
+		depthPort.setDepth(newDepth);
+		if (depthPort instanceof InputWorkflowPort)
+			checkNestedPortDepths((InputWorkflowPort) depthPort, newDepth);
+	}
+
+	@Override
+	protected void undoEditAction(T depthPort) {
+		depthPort.setDepth(oldDepth);
+		if (depthPort instanceof InputWorkflowPort)
+			checkNestedPortDepths((InputWorkflowPort) depthPort, oldDepth);
+	}
+
+	private void checkNestedPortDepths(InputWorkflowPort workflowPort,
+			Integer depth) {
+		Workflow workflow = workflowPort.getParent();
+		if (workflow != null) {
+			WorkflowBundle workflowBundle = workflow.getParent();
+			if (workflowBundle != null)
+				for (Profile profile : workflowBundle.getProfiles())
+					for (Activity activity : profile.getActivities())
+						if (activity.getType().equals(NESTED_WORKFLOW))
+							for (Configuration c : scufl2Tools
+									.configurationsFor(activity, profile))
+								checkOneConfiguration(workflowPort, depth,
+										workflow, workflowBundle, activity, c);
+		}
+	}
+
+	private void checkOneConfiguration(InputWorkflowPort workflowPort,
+			Integer depth, Workflow workflow, WorkflowBundle workflowBundle,
+			Activity activity, Configuration c) {
+		JsonNode nested = c.getJson().get("nestedWorkflow");
+		Workflow nestedWorkflow = workflowBundle.getWorkflows().getByName(
+				nested.asText());
+		if (nestedWorkflow != workflow)
+			return;
+
+		ActivityPort activityPort = activity.getInputPorts().getByName(
+				workflowPort.getName());
+		activityPort.setDepth(depth);
+		for (ProcessorBinding binding : scufl2Tools
+				.processorBindingsToActivity(activity))
+			for (ProcessorInputPortBinding portBinding : binding
+					.getInputPortBindings())
+				if (portBinding.getBoundActivityPort() == activityPort) {
+					InputProcessorPort processorPort = portBinding
+							.getBoundProcessorPort();
+					processorPort.setDepth(depth);
+				}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/ChangeGranularDepthEdit.java
----------------------------------------------------------------------
diff --git a/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/ChangeGranularDepthEdit.java b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/ChangeGranularDepthEdit.java
new file mode 100644
index 0000000..e9f1b54
--- /dev/null
+++ b/taverna-edits-api/src/main/java/net/sf/taverna/t2/workflow/edits/ChangeGranularDepthEdit.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (C) 2012 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.workflow.edits;
+
+import uk.org.taverna.scufl2.api.port.GranularDepthPort;
+
+/**
+ * Changes the granular depth of a port.
+ * 
+ * @author David Withers
+ */
+public class ChangeGranularDepthEdit<T extends GranularDepthPort> extends
+		AbstractEdit<T> {
+	private Integer newGranularDepth, oldGranularDepth;
+
+	public ChangeGranularDepthEdit(T granularDepthPort, Integer newGranularDepth) {
+		super(granularDepthPort);
+		this.newGranularDepth = newGranularDepth;
+		oldGranularDepth = granularDepthPort.getGranularDepth();
+	}
+
+	@Override
+	protected void doEditAction(T granularDepthPort) {
+		granularDepthPort.setGranularDepth(newGranularDepth);
+	}
+
+	@Override
+	protected void undoEditAction(T granularDepthPort) {
+		granularDepthPort.setGranularDepth(oldGranularDepth);
+	}
+}