http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/AbstractUndoAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/AbstractUndoAction.java
 
b/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/AbstractUndoAction.java
new file mode 100644
index 0000000..0f024a1
--- /dev/null
+++ 
b/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/AbstractUndoAction.java
@@ -0,0 +1,165 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.edits.impl.menu;
+
+import static java.awt.Toolkit.getDefaultToolkit;
+import static java.awt.event.KeyEvent.VK_Y;
+import static java.awt.event.KeyEvent.VK_Z;
+import static javax.swing.KeyStroke.getKeyStroke;
+import static org.apache.taverna.workbench.icons.WorkbenchIcons.redoIcon;
+import static org.apache.taverna.workbench.icons.WorkbenchIcons.undoIcon;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+import org.apache.taverna.lang.observer.SwingAwareObserver;
+import org.apache.taverna.workbench.edits.EditManager;
+import 
org.apache.taverna.workbench.edits.EditManager.AbstractDataflowEditEvent;
+import org.apache.taverna.workbench.edits.EditManager.EditManagerEvent;
+import org.apache.taverna.workbench.selection.SelectionManager;
+import org.apache.taverna.workbench.selection.events.PerspectiveSelectionEvent;
+import org.apache.taverna.workbench.selection.events.SelectionManagerEvent;
+import 
org.apache.taverna.workbench.selection.events.WorkflowBundleSelectionEvent;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * @author David Withers
+ */
+@SuppressWarnings("serial")
+public abstract class AbstractUndoAction extends AbstractAction {
+       protected EditManager editManager;
+       private SelectionManager selectionManager;
+
+       public AbstractUndoAction(String label, EditManager editManager) {
+               super(label);
+               this.editManager = editManager;
+               if (label.equals("Undo")) {
+                       this.putValue(SMALL_ICON, undoIcon);
+                       this.putValue(SHORT_DESCRIPTION, "Undo an action");
+                       putValue(
+                                       ACCELERATOR_KEY,
+                                       getKeyStroke(VK_Z, getDefaultToolkit()
+                                                       
.getMenuShortcutKeyMask()));
+               } else if (label.equals("Redo")) {
+                       this.putValue(SMALL_ICON, redoIcon);
+                       this.putValue(SHORT_DESCRIPTION, "Redo an action");
+                       putValue(
+                                       ACCELERATOR_KEY,
+                                       getKeyStroke(VK_Y, getDefaultToolkit()
+                                                       
.getMenuShortcutKeyMask()));
+               }
+               editManager.addObserver(new EditManagerObserver());
+               updateStatus();
+       }
+
+       @Override
+       public void actionPerformed(ActionEvent e) {
+               WorkflowBundle workflowBundle = getCurrentDataflow();
+               if (workflowBundle != null)
+                       performUndoOrRedo(workflowBundle);
+       }
+
+       /**
+        * Check if action should be enabled or disabled and update its status.
+        */
+       public void updateStatus() {
+               WorkflowBundle workflowBundle = getCurrentDataflow();
+               if (workflowBundle == null)
+                       setEnabled(false);
+               setEnabled(isActive(workflowBundle));
+       }
+
+       /**
+        * Retrieve the current dataflow from the {@link ModelMap}, or
+        * <code>null</code> if no workflow is active.
+        * 
+        * @return The current {@link Dataflow}
+        */
+       protected WorkflowBundle getCurrentDataflow() {
+               if (selectionManager == null)
+                       return null;
+               return selectionManager.getSelectedWorkflowBundle();
+       }
+
+       /**
+        * Return <code>true</code> if the action should be enabled when the 
given
+        * {@link Dataflow} is the current, ie. if it's undoable or redoable.
+        * 
+        * @param dataflow
+        *            Current {@link Dataflow}
+        * @return <code>true</code> if the action should be enabled.
+        */
+       protected abstract boolean isActive(WorkflowBundle workflowBundle);
+
+       /**
+        * Called by {@link #actionPerformed(ActionEvent)} when the current 
dataflow
+        * is not <code>null</code>.
+        * 
+        * @param dataflow
+        *            {@link Dataflow} on which to undo or redo
+        */
+       protected abstract void performUndoOrRedo(WorkflowBundle 
workflowBundle);
+
+       public void setSelectionManager(SelectionManager selectionManager) {
+               this.selectionManager = selectionManager;
+               if (selectionManager != null)
+                       selectionManager.addObserver(new 
SelectionManagerObserver());
+       }
+
+       /**
+        * Update the status if there's been an edit done on the current 
workflow.
+        * 
+        */
+       protected class EditManagerObserver implements 
Observer<EditManagerEvent> {
+               @Override
+               public void notify(Observable<EditManagerEvent> sender,
+                               EditManagerEvent message) throws Exception {
+                       if (!(message instanceof AbstractDataflowEditEvent))
+                               return;
+                       AbstractDataflowEditEvent dataflowEdit = 
(AbstractDataflowEditEvent) message;
+                       if 
(dataflowEdit.getDataFlow().equals(dataflowEdit.getDataFlow()))
+                               // It's an edit that could effect our 
undoability
+                               updateStatus();
+               }
+       }
+
+       private final class SelectionManagerObserver extends
+                       SwingAwareObserver<SelectionManagerEvent> {
+               private static final String DESIGN_PERSPECTIVE_ID = 
"net.sf.taverna.t2.ui.perspectives.design.DesignPerspective";
+
+               @Override
+               public void notifySwing(Observable<SelectionManagerEvent> 
sender,
+                               SelectionManagerEvent message) {
+                       if (message instanceof WorkflowBundleSelectionEvent)
+                               updateStatus();
+                       else if (message instanceof PerspectiveSelectionEvent) {
+                               PerspectiveSelectionEvent 
perspectiveSelectionEvent = (PerspectiveSelectionEvent) message;
+                               if 
(DESIGN_PERSPECTIVE_ID.equals(perspectiveSelectionEvent
+                                               
.getSelectedPerspective().getID()))
+                                       updateStatus();
+                               else
+                                       setEnabled(false);
+                       }
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/RedoMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/RedoMenuAction.java
 
b/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/RedoMenuAction.java
new file mode 100644
index 0000000..3696458
--- /dev/null
+++ 
b/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/RedoMenuAction.java
@@ -0,0 +1,85 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.edits.impl.menu;
+
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static 
org.apache.taverna.workbench.edits.impl.menu.UndoMenuSection.UNDO_SECTION_URI;
+
+import javax.swing.Action;
+
+import org.apache.taverna.ui.menu.AbstractMenuAction;
+import org.apache.taverna.workbench.edits.Edit;
+import org.apache.taverna.workbench.edits.EditException;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.selection.SelectionManager;
+
+import org.apache.log4j.Logger;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * Redo the previous {@link Edit} done on the current workflow using the
+ * {@link EditManager}.
+ *
+ * @author Stian Soiland-Reyes
+ */
+public class RedoMenuAction extends AbstractMenuAction {
+       private static Logger logger = Logger.getLogger(RedoMenuAction.class);
+       private final EditManager editManager;
+       private SelectionManager selectionManager;
+       private AbstractUndoAction undoAction;
+
+       public RedoMenuAction(EditManager editManager) {
+               super(UNDO_SECTION_URI, 20);
+               this.editManager = editManager;
+       }
+
+       @SuppressWarnings("serial")
+       @Override
+       protected Action createAction() {
+               undoAction = new AbstractUndoAction("Redo", editManager) {
+                       @Override
+                       protected boolean isActive(WorkflowBundle 
workflowBundle) {
+                               return 
editManager.canRedoDataflowEdit(workflowBundle);
+                       }
+
+                       @Override
+                       protected void performUndoOrRedo(WorkflowBundle 
workflowBundle) {
+                               try {
+                                       
editManager.redoDataflowEdit(workflowBundle);
+                               } catch (EditException | RuntimeException e) {
+                                       logger.warn("Could not redo for " + 
workflowBundle, e);
+                                       showMessageDialog(null, "Could not redo 
for workflow "
+                                                       + workflowBundle + 
":\n" + e, "Could not redo",
+                                                       ERROR_MESSAGE);
+                               }
+                       }
+               };
+               undoAction.setSelectionManager(selectionManager);
+               return undoAction;
+       }
+
+       public void setSelectionManager(SelectionManager selectionManager) {
+               this.selectionManager = selectionManager;
+               if (undoAction != null)
+                       undoAction.setSelectionManager(selectionManager);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/UndoMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/UndoMenuAction.java
 
b/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/UndoMenuAction.java
new file mode 100644
index 0000000..7db7c6c
--- /dev/null
+++ 
b/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/UndoMenuAction.java
@@ -0,0 +1,85 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.edits.impl.menu;
+
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static 
org.apache.taverna.workbench.edits.impl.menu.UndoMenuSection.UNDO_SECTION_URI;
+
+import javax.swing.Action;
+
+import org.apache.taverna.ui.menu.AbstractMenuAction;
+import org.apache.taverna.workbench.edits.Edit;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.selection.SelectionManager;
+
+import org.apache.log4j.Logger;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * Undo the last {@link Edit} done on the current workflow using the
+ * {@link EditManager}.
+ * 
+ * @author Stian Soiland-Reyes
+ * 
+ */
+public class UndoMenuAction extends AbstractMenuAction {
+       private static Logger logger = Logger.getLogger(UndoMenuAction.class);
+       private final EditManager editManager;
+       private SelectionManager selectionManager;
+       private AbstractUndoAction undoAction;
+
+       public UndoMenuAction(EditManager editManager) {
+               super(UNDO_SECTION_URI, 10);
+               this.editManager = editManager;
+       }
+
+       @SuppressWarnings("serial")
+       @Override
+       protected Action createAction() {
+               undoAction = new AbstractUndoAction("Undo", editManager) {
+                       @Override
+                       protected boolean isActive(WorkflowBundle 
workflowBundle) {
+                               return 
editManager.canUndoDataflowEdit(workflowBundle);
+                       }
+
+                       @Override
+                       protected void performUndoOrRedo(WorkflowBundle 
workflowBundle) {
+                               try {
+                                       
editManager.undoDataflowEdit(workflowBundle);
+                               } catch (RuntimeException e) {
+                                       logger.warn("Could not undo for " + 
workflowBundle, e);
+                                       showMessageDialog(null, "Could not undo 
for workflow "
+                                                       + workflowBundle + 
":\n" + e, "Could not undo",
+                                                       ERROR_MESSAGE);
+                               }
+                       }
+               };
+               undoAction.setSelectionManager(selectionManager);
+               return undoAction;
+       }
+
+       public void setSelectionManager(SelectionManager selectionManager) {
+               this.selectionManager = selectionManager;
+               if (undoAction != null)
+                       undoAction.setSelectionManager(selectionManager);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/UndoMenuSection.java
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/UndoMenuSection.java
 
b/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/UndoMenuSection.java
new file mode 100644
index 0000000..dfed909
--- /dev/null
+++ 
b/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/menu/UndoMenuSection.java
@@ -0,0 +1,41 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.edits.impl.menu;
+
+import java.net.URI;
+
+import org.apache.taverna.ui.menu.AbstractMenuSection;
+
+/**
+ * A section of the Edit menu that contains {@link UndoMenuSection undo} and
+ * {@link RedoMenuAction redo}.
+ * 
+ * @author Stian Soiland-Reyes
+ */
+public class UndoMenuSection extends AbstractMenuSection {
+       public static final URI UNDO_SECTION_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/edits#undoSection";);
+       public static final URI EDIT_MENU_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#edit";);
+
+       public UndoMenuSection() {
+               super(EDIT_MENU_URI, 10, UNDO_SECTION_URI);
+       }
+}

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

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/toolbar/RedoToolbarAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/toolbar/RedoToolbarAction.java
 
b/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/toolbar/RedoToolbarAction.java
new file mode 100644
index 0000000..d95adb7
--- /dev/null
+++ 
b/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/toolbar/RedoToolbarAction.java
@@ -0,0 +1,45 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.edits.impl.toolbar;
+
+import static 
org.apache.taverna.workbench.edits.impl.toolbar.EditToolbarSection.EDIT_TOOLBAR_SECTION;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import org.apache.taverna.ui.menu.AbstractMenuAction;
+import org.apache.taverna.workbench.edits.impl.menu.RedoMenuAction;
+
+public class RedoToolbarAction extends AbstractMenuAction {
+       private static final URI EDIT_TOOLBAR_REDO_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#editToolbarRedo";);
+       private final RedoMenuAction redoMenuAction;
+
+       public RedoToolbarAction(RedoMenuAction redoMenuAction) {
+               super(EDIT_TOOLBAR_SECTION, 20, EDIT_TOOLBAR_REDO_URI);
+               this.redoMenuAction = redoMenuAction;
+       }
+
+       @Override
+       protected Action createAction() {
+               return redoMenuAction.getAction();
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/toolbar/UndoToolbarAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/toolbar/UndoToolbarAction.java
 
b/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/toolbar/UndoToolbarAction.java
new file mode 100644
index 0000000..2d9bcae
--- /dev/null
+++ 
b/taverna-edits-impl/src/main/java/org/apache/taverna/workbench/edits/impl/toolbar/UndoToolbarAction.java
@@ -0,0 +1,45 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.edits.impl.toolbar;
+
+import static 
org.apache.taverna.workbench.edits.impl.toolbar.EditToolbarSection.EDIT_TOOLBAR_SECTION;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import org.apache.taverna.ui.menu.AbstractMenuAction;
+import org.apache.taverna.workbench.edits.impl.menu.UndoMenuAction;
+
+public class UndoToolbarAction extends AbstractMenuAction {
+       private static final URI EDIT_TOOLBAR_UNDO_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#editToolbarUndo";);
+       private final UndoMenuAction undoMenuAction;
+
+       public UndoToolbarAction(UndoMenuAction undoMenuAction) {
+               super(EDIT_TOOLBAR_SECTION, 10, EDIT_TOOLBAR_UNDO_URI);
+               this.undoMenuAction = undoMenuAction;
+       }
+
+       @Override
+       protected Action createAction() {
+               return undoMenuAction.getAction();
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
 
b/taverna-edits-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
deleted file mode 100644
index 6938308..0000000
--- 
a/taverna-edits-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
+++ /dev/null
@@ -1,6 +0,0 @@
-net.sf.taverna.t2.workbench.edits.impl.menu.UndoMenuSection
-net.sf.taverna.t2.workbench.edits.impl.menu.UndoMenuAction
-net.sf.taverna.t2.workbench.edits.impl.menu.RedoMenuAction
-net.sf.taverna.t2.workbench.edits.impl.toolbar.EditToolbarSection
-net.sf.taverna.t2.workbench.edits.impl.toolbar.UndoToolbarAction
-net.sf.taverna.t2.workbench.edits.impl.toolbar.RedoToolbarAction

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.edits.EditManager
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.edits.EditManager
 
b/taverna-edits-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.edits.EditManager
deleted file mode 100644
index 92ee088..0000000
--- 
a/taverna-edits-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.edits.EditManager
+++ /dev/null
@@ -1 +0,0 @@
-net.sf.taverna.t2.workbench.edits.impl.EditManagerImpl

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/main/resources/META-INF/services/org.apache.taverna.ui.menu.MenuComponent
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/main/resources/META-INF/services/org.apache.taverna.ui.menu.MenuComponent
 
b/taverna-edits-impl/src/main/resources/META-INF/services/org.apache.taverna.ui.menu.MenuComponent
new file mode 100644
index 0000000..1019470
--- /dev/null
+++ 
b/taverna-edits-impl/src/main/resources/META-INF/services/org.apache.taverna.ui.menu.MenuComponent
@@ -0,0 +1,6 @@
+org.apache.taverna.workbench.edits.impl.menu.UndoMenuSection
+org.apache.taverna.workbench.edits.impl.menu.UndoMenuAction
+org.apache.taverna.workbench.edits.impl.menu.RedoMenuAction
+org.apache.taverna.workbench.edits.impl.toolbar.EditToolbarSection
+org.apache.taverna.workbench.edits.impl.toolbar.UndoToolbarAction
+org.apache.taverna.workbench.edits.impl.toolbar.RedoToolbarAction

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/main/resources/META-INF/services/org.apache.taverna.workbench.edits.EditManager
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/main/resources/META-INF/services/org.apache.taverna.workbench.edits.EditManager
 
b/taverna-edits-impl/src/main/resources/META-INF/services/org.apache.taverna.workbench.edits.EditManager
new file mode 100644
index 0000000..bd7f2d8
--- /dev/null
+++ 
b/taverna-edits-impl/src/main/resources/META-INF/services/org.apache.taverna.workbench.edits.EditManager
@@ -0,0 +1 @@
+org.apache.taverna.workbench.edits.impl.EditManagerImpl

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/main/resources/META-INF/spring/edits-impl-context-osgi.xml
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/main/resources/META-INF/spring/edits-impl-context-osgi.xml
 
b/taverna-edits-impl/src/main/resources/META-INF/spring/edits-impl-context-osgi.xml
index 8eb7041..195b18e 100644
--- 
a/taverna-edits-impl/src/main/resources/META-INF/spring/edits-impl-context-osgi.xml
+++ 
b/taverna-edits-impl/src/main/resources/META-INF/spring/edits-impl-context-osgi.xml
@@ -13,8 +13,8 @@
        <service ref="UndoToolbarAction" auto-export="interfaces" />
        <service ref="RedoToolbarAction" auto-export="interfaces" />
 
-       <service ref="EditManagerImpl" 
interface="net.sf.taverna.t2.workbench.edits.EditManager" />
+       <service ref="EditManagerImpl" 
interface="org.apache.taverna.workbench.edits.EditManager" />
 
-       <reference id="selectionManager" 
interface="net.sf.taverna.t2.workbench.selection.SelectionManager" 
cardinality="0..1" />
+       <reference id="selectionManager" 
interface="org.apache.taverna.workbench.selection.SelectionManager" 
cardinality="0..1" />
 
 </beans:beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/main/resources/META-INF/spring/edits-impl-context.xml
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/main/resources/META-INF/spring/edits-impl-context.xml 
b/taverna-edits-impl/src/main/resources/META-INF/spring/edits-impl-context.xml
index 33f0b7b..bba1db8 100644
--- 
a/taverna-edits-impl/src/main/resources/META-INF/spring/edits-impl-context.xml
+++ 
b/taverna-edits-impl/src/main/resources/META-INF/spring/edits-impl-context.xml
@@ -3,31 +3,31 @@
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                       
http://www.springframework.org/schema/beans/spring-beans.xsd";>
 
-       <bean id="UndoMenuSection" 
class="net.sf.taverna.t2.workbench.edits.impl.menu.UndoMenuSection" />
-       <bean id="UndoMenuAction" 
class="net.sf.taverna.t2.workbench.edits.impl.menu.UndoMenuAction">
+       <bean id="UndoMenuSection" 
class="org.apache.taverna.workbench.edits.impl.menu.UndoMenuSection" />
+       <bean id="UndoMenuAction" 
class="org.apache.taverna.workbench.edits.impl.menu.UndoMenuAction">
                <constructor-arg name="editManager">
                        <ref local="EditManagerImpl" />
                </constructor-arg>
                <property name="selectionManager" ref="selectionManager" />
        </bean>
-       <bean id="RedoMenuAction" 
class="net.sf.taverna.t2.workbench.edits.impl.menu.RedoMenuAction">
+       <bean id="RedoMenuAction" 
class="org.apache.taverna.workbench.edits.impl.menu.RedoMenuAction">
                <constructor-arg name="editManager">
                        <ref local="EditManagerImpl" />
                </constructor-arg>
                <property name="selectionManager" ref="selectionManager" />
        </bean>
-       <bean id="EditToolbarSection" 
class="net.sf.taverna.t2.workbench.edits.impl.toolbar.EditToolbarSection" />
-       <bean id="UndoToolbarAction" 
class="net.sf.taverna.t2.workbench.edits.impl.toolbar.UndoToolbarAction">
+       <bean id="EditToolbarSection" 
class="org.apache.taverna.workbench.edits.impl.toolbar.EditToolbarSection" />
+       <bean id="UndoToolbarAction" 
class="org.apache.taverna.workbench.edits.impl.toolbar.UndoToolbarAction">
                <constructor-arg>
                        <ref local="UndoMenuAction" />
                </constructor-arg>
        </bean>
-       <bean id="RedoToolbarAction" 
class="net.sf.taverna.t2.workbench.edits.impl.toolbar.RedoToolbarAction">
+       <bean id="RedoToolbarAction" 
class="org.apache.taverna.workbench.edits.impl.toolbar.RedoToolbarAction">
                <constructor-arg>
                        <ref local="RedoMenuAction" />
                </constructor-arg>
        </bean>
 
-       <bean id="EditManagerImpl" 
class="net.sf.taverna.t2.workbench.edits.impl.EditManagerImpl" />
+       <bean id="EditManagerImpl" 
class="org.apache.taverna.workbench.edits.impl.EditManagerImpl" />
 
 </beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/test/java/net/sf/taverna/t2/workbench/edits/impl/TestEditManagerImpl.java
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/test/java/net/sf/taverna/t2/workbench/edits/impl/TestEditManagerImpl.java
 
b/taverna-edits-impl/src/test/java/net/sf/taverna/t2/workbench/edits/impl/TestEditManagerImpl.java
deleted file mode 100644
index 27334b0..0000000
--- 
a/taverna-edits-impl/src/test/java/net/sf/taverna/t2/workbench/edits/impl/TestEditManagerImpl.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*******************************************************************************
- * 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.impl;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-import org.apache.taverna.lang.observer.Observable;
-import org.apache.taverna.lang.observer.Observer;
-import net.sf.taverna.t2.workbench.edits.Edit;
-import net.sf.taverna.t2.workbench.edits.EditManager;
-import net.sf.taverna.t2.workbench.edits.EditManager.DataFlowRedoEvent;
-import net.sf.taverna.t2.workbench.edits.EditManager.DataFlowUndoEvent;
-import net.sf.taverna.t2.workbench.edits.EditManager.DataflowEditEvent;
-import net.sf.taverna.t2.workbench.edits.EditManager.EditManagerEvent;
-import net.sf.taverna.t2.workflow.edits.AddProcessorEdit;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import org.apache.taverna.scufl2.api.container.WorkflowBundle;
-import org.apache.taverna.scufl2.api.core.Processor;
-import org.apache.taverna.scufl2.api.core.Workflow;
-
-public class TestEditManagerImpl {
-
-       private Workflow dataflow;
-
-       private EditManagerObserver editManagerObserver = new 
EditManagerObserver();
-
-       private Processor processor;
-
-       @Test
-       public void addProcessor() throws Exception {
-               EditManager editManager = new EditManagerImpl();
-               editManager.addObserver(editManagerObserver);
-
-               Edit<Workflow> edit = new AddProcessorEdit(dataflow, processor);
-               assertFalse("Edit was already applied", edit.isApplied());
-               assertTrue("Did already add processor", dataflow.getProcessors()
-                               .isEmpty());
-
-               editManager.doDataflowEdit(dataflow.getParent(), edit);
-               assertTrue("Edit was not applied", edit.isApplied());
-               assertEquals("Did not add processor", processor, 
dataflow.getProcessors().first());
-
-               // Should have received the edit event
-               assertEquals("Incorrect number of events", 1,
-                               editManagerObserver.events.size());
-               EditManagerEvent event = editManagerObserver.events.get(0);
-               assertTrue("Event was not a DataflowEditEvent",
-                               event instanceof DataflowEditEvent);
-               DataflowEditEvent dataEditEvent = (DataflowEditEvent) event;
-               assertEquals("Event did not have correct workflow", dataflow,
-                               
dataEditEvent.getDataFlow().getWorkflows().first());
-               assertEquals("Event did not have correct edit", edit, 
dataEditEvent
-                               .getEdit());
-
-       }
-
-       @Test
-       public void undoAddProcessor() throws Exception {
-               EditManager editManager = new EditManagerImpl();
-               editManager.addObserver(editManagerObserver);
-
-               Edit<Workflow> edit = new AddProcessorEdit(dataflow, processor);
-               editManager.doDataflowEdit(dataflow.getParent(), edit);
-
-               assertFalse("Did not add processor", 
dataflow.getProcessors().isEmpty());
-               editManager.undoDataflowEdit(dataflow.getParent());
-               assertTrue("Did not undo add processor", 
dataflow.getProcessors()
-                               .isEmpty());
-
-               // Should have received the undo event
-               assertEquals("Incorrect number of events", 2,
-                               editManagerObserver.events.size());
-               EditManagerEvent event = editManagerObserver.events.get(1);
-               assertTrue("Event was not a DataflowEditEvent",
-                               event instanceof DataFlowUndoEvent);
-               DataFlowUndoEvent dataEditEvent = (DataFlowUndoEvent) event;
-               assertEquals("Event did not have correct workflow", dataflow,
-                               
dataEditEvent.getDataFlow().getWorkflows().first());
-               assertEquals("Event did not have correct edit", edit, 
dataEditEvent
-                               .getEdit());
-               assertFalse("Edit was still applied", edit.isApplied());
-       }
-
-       @Test
-       public void multipleUndoesRedoes() throws Exception {
-               EditManager editManager = new EditManagerImpl();
-               editManager.addObserver(editManagerObserver);
-
-               Workflow dataflowA = createDataflow();
-               Workflow dataflowB = createDataflow();
-               Workflow dataflowC = createDataflow();
-
-               Processor processorA1 = createProcessor();
-               Processor processorA2 = createProcessor();
-               Processor processorA3 = createProcessor();
-               Processor processorB1 = createProcessor();
-               Processor processorC1 = createProcessor();
-
-               Edit<Workflow> edit = new AddProcessorEdit(dataflowA, 
processorA1);
-               editManager.doDataflowEdit(dataflowA.getParent(), edit);
-
-               edit = new AddProcessorEdit(dataflowB, processorB1);
-               editManager.doDataflowEdit(dataflowB.getParent(), edit);
-
-               edit = new AddProcessorEdit(dataflowA, processorA2);
-               editManager.doDataflowEdit(dataflowA.getParent(), edit);
-
-               edit = new AddProcessorEdit(dataflowC, processorC1);
-               editManager.doDataflowEdit(dataflowC.getParent(), edit);
-
-               edit = new AddProcessorEdit(dataflowA, processorA3);
-               editManager.doDataflowEdit(dataflowA.getParent(), edit);
-
-
-
-               assertFalse("Did not add processors", 
dataflowA.getProcessors().isEmpty());
-               assertEquals(3, dataflowA.getProcessors().size());
-               editManager.undoDataflowEdit(dataflowA.getParent());
-               assertEquals(2, dataflowA.getProcessors().size());
-               editManager.undoDataflowEdit(dataflowA.getParent());
-               assertEquals(1, dataflowA.getProcessors().size());
-               editManager.undoDataflowEdit(dataflowA.getParent());
-               assertEquals(0, dataflowA.getProcessors().size());
-
-               assertEquals(1, dataflowB.getProcessors().size());
-               assertEquals(1, dataflowC.getProcessors().size());
-
-               
assertTrue(editManager.canUndoDataflowEdit(dataflowC.getParent()));
-               editManager.undoDataflowEdit(dataflowC.getParent());
-               
assertFalse(editManager.canUndoDataflowEdit(dataflowC.getParent()));
-               editManager.undoDataflowEdit(dataflowC.getParent()); // extra 
one
-               
assertFalse(editManager.canUndoDataflowEdit(dataflowC.getParent()));
-
-
-               assertEquals(1, dataflowB.getProcessors().size());
-               assertEquals(0, dataflowC.getProcessors().size());
-
-               editManager.undoDataflowEdit(dataflowB.getParent());
-               assertEquals(0, dataflowA.getProcessors().size());
-               assertEquals(0, dataflowB.getProcessors().size());
-               assertEquals(0, dataflowC.getProcessors().size());
-
-               editManager.redoDataflowEdit(dataflowA.getParent());
-               assertEquals(1, dataflowA.getProcessors().size());
-
-               editManager.redoDataflowEdit(dataflowA.getParent());
-               assertEquals(2, dataflowA.getProcessors().size());
-
-               editManager.redoDataflowEdit(dataflowA.getParent());
-               assertEquals(3, dataflowA.getProcessors().size());
-
-               // does not affect it
-               editManager.redoDataflowEdit(dataflowA.getParent());
-               assertEquals(3, dataflowA.getProcessors().size());
-               assertEquals(0, dataflowB.getProcessors().size());
-               assertEquals(0, dataflowC.getProcessors().size());
-       }
-
-       @Test
-       public void emptyUndoDoesNotFail() throws Exception {
-               EditManager editManager = new EditManagerImpl();
-               editManager.addObserver(editManagerObserver);
-               editManager.undoDataflowEdit(dataflow.getParent());
-       }
-
-       @Test
-       public void extraUndoesDoesNotFail() throws Exception {
-               EditManager editManager = new EditManagerImpl();
-               editManager.addObserver(editManagerObserver);
-
-               Edit<Workflow> edit = new AddProcessorEdit(dataflow, processor);
-               editManager.doDataflowEdit(dataflow.getParent(), edit);
-
-               assertFalse("Did not add processor", 
dataflow.getProcessors().isEmpty());
-               editManager.undoDataflowEdit(dataflow.getParent());
-               assertTrue("Did not undo add processor", 
dataflow.getProcessors()
-                               .isEmpty());
-               editManager.undoDataflowEdit(dataflow.getParent());
-       }
-
-       @Before
-       public void makeDataflow() {
-               dataflow = createDataflow();
-       }
-
-       protected Workflow createDataflow() {
-               WorkflowBundle workflowBundle = new WorkflowBundle();
-               Workflow workflow = new Workflow();
-               workflow.setParent(workflowBundle);
-               return workflow;
-       }
-
-       protected Processor createProcessor() {
-               Processor processor = new Processor();
-               processor.setName("proc-" + UUID.randomUUID());
-               return processor;
-       }
-
-       @Before
-       public void makeProcessor() {
-               processor = createProcessor();
-       }
-
-       private class EditManagerObserver implements Observer<EditManagerEvent> 
{
-
-               public List<EditManagerEvent> events = new ArrayList<>();
-
-               @Override
-               public void notify(Observable<EditManagerEvent> sender,
-                               EditManagerEvent message) throws Exception {
-                       events.add(message);
-                       if (message instanceof DataflowEditEvent) {
-                               DataflowEditEvent dataflowEdit = 
(DataflowEditEvent) message;
-                               assertTrue("Edit was not applied on edit 
event", dataflowEdit
-                                               .getEdit().isApplied());
-                       } else if (message instanceof DataFlowUndoEvent) {
-                               DataFlowUndoEvent dataflowUndo = 
(DataFlowUndoEvent) message;
-                               assertFalse("Edit was applied on undo event", 
dataflowUndo
-                                               .getEdit().isApplied());
-                       } else if (message instanceof DataFlowRedoEvent) {
-                               DataFlowRedoEvent dataflowEdit = 
(DataFlowRedoEvent) message;
-                               assertTrue("Edit was not applied on edit 
event", dataflowEdit
-                                               .getEdit().isApplied());
-                       } else {
-                               fail("Unknown event: " + message);
-                       }
-               }
-       }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-edits-impl/src/test/java/org/apache/taverna/workbench/edits/impl/TestEditManagerImpl.java
----------------------------------------------------------------------
diff --git 
a/taverna-edits-impl/src/test/java/org/apache/taverna/workbench/edits/impl/TestEditManagerImpl.java
 
b/taverna-edits-impl/src/test/java/org/apache/taverna/workbench/edits/impl/TestEditManagerImpl.java
new file mode 100644
index 0000000..aed29cb
--- /dev/null
+++ 
b/taverna-edits-impl/src/test/java/org/apache/taverna/workbench/edits/impl/TestEditManagerImpl.java
@@ -0,0 +1,257 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.edits.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+import org.apache.taverna.workbench.edits.Edit;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.edits.EditManager.DataFlowRedoEvent;
+import org.apache.taverna.workbench.edits.EditManager.DataFlowUndoEvent;
+import org.apache.taverna.workbench.edits.EditManager.DataflowEditEvent;
+import org.apache.taverna.workbench.edits.EditManager.EditManagerEvent;
+import org.apache.taverna.workflow.edits.AddProcessorEdit;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.Workflow;
+
+public class TestEditManagerImpl {
+
+       private Workflow dataflow;
+
+       private EditManagerObserver editManagerObserver = new 
EditManagerObserver();
+
+       private Processor processor;
+
+       @Test
+       public void addProcessor() throws Exception {
+               EditManager editManager = new EditManagerImpl();
+               editManager.addObserver(editManagerObserver);
+
+               Edit<Workflow> edit = new AddProcessorEdit(dataflow, processor);
+               assertFalse("Edit was already applied", edit.isApplied());
+               assertTrue("Did already add processor", dataflow.getProcessors()
+                               .isEmpty());
+
+               editManager.doDataflowEdit(dataflow.getParent(), edit);
+               assertTrue("Edit was not applied", edit.isApplied());
+               assertEquals("Did not add processor", processor, 
dataflow.getProcessors().first());
+
+               // Should have received the edit event
+               assertEquals("Incorrect number of events", 1,
+                               editManagerObserver.events.size());
+               EditManagerEvent event = editManagerObserver.events.get(0);
+               assertTrue("Event was not a DataflowEditEvent",
+                               event instanceof DataflowEditEvent);
+               DataflowEditEvent dataEditEvent = (DataflowEditEvent) event;
+               assertEquals("Event did not have correct workflow", dataflow,
+                               
dataEditEvent.getDataFlow().getWorkflows().first());
+               assertEquals("Event did not have correct edit", edit, 
dataEditEvent
+                               .getEdit());
+
+       }
+
+       @Test
+       public void undoAddProcessor() throws Exception {
+               EditManager editManager = new EditManagerImpl();
+               editManager.addObserver(editManagerObserver);
+
+               Edit<Workflow> edit = new AddProcessorEdit(dataflow, processor);
+               editManager.doDataflowEdit(dataflow.getParent(), edit);
+
+               assertFalse("Did not add processor", 
dataflow.getProcessors().isEmpty());
+               editManager.undoDataflowEdit(dataflow.getParent());
+               assertTrue("Did not undo add processor", 
dataflow.getProcessors()
+                               .isEmpty());
+
+               // Should have received the undo event
+               assertEquals("Incorrect number of events", 2,
+                               editManagerObserver.events.size());
+               EditManagerEvent event = editManagerObserver.events.get(1);
+               assertTrue("Event was not a DataflowEditEvent",
+                               event instanceof DataFlowUndoEvent);
+               DataFlowUndoEvent dataEditEvent = (DataFlowUndoEvent) event;
+               assertEquals("Event did not have correct workflow", dataflow,
+                               
dataEditEvent.getDataFlow().getWorkflows().first());
+               assertEquals("Event did not have correct edit", edit, 
dataEditEvent
+                               .getEdit());
+               assertFalse("Edit was still applied", edit.isApplied());
+       }
+
+       @Test
+       public void multipleUndoesRedoes() throws Exception {
+               EditManager editManager = new EditManagerImpl();
+               editManager.addObserver(editManagerObserver);
+
+               Workflow dataflowA = createDataflow();
+               Workflow dataflowB = createDataflow();
+               Workflow dataflowC = createDataflow();
+
+               Processor processorA1 = createProcessor();
+               Processor processorA2 = createProcessor();
+               Processor processorA3 = createProcessor();
+               Processor processorB1 = createProcessor();
+               Processor processorC1 = createProcessor();
+
+               Edit<Workflow> edit = new AddProcessorEdit(dataflowA, 
processorA1);
+               editManager.doDataflowEdit(dataflowA.getParent(), edit);
+
+               edit = new AddProcessorEdit(dataflowB, processorB1);
+               editManager.doDataflowEdit(dataflowB.getParent(), edit);
+
+               edit = new AddProcessorEdit(dataflowA, processorA2);
+               editManager.doDataflowEdit(dataflowA.getParent(), edit);
+
+               edit = new AddProcessorEdit(dataflowC, processorC1);
+               editManager.doDataflowEdit(dataflowC.getParent(), edit);
+
+               edit = new AddProcessorEdit(dataflowA, processorA3);
+               editManager.doDataflowEdit(dataflowA.getParent(), edit);
+
+
+
+               assertFalse("Did not add processors", 
dataflowA.getProcessors().isEmpty());
+               assertEquals(3, dataflowA.getProcessors().size());
+               editManager.undoDataflowEdit(dataflowA.getParent());
+               assertEquals(2, dataflowA.getProcessors().size());
+               editManager.undoDataflowEdit(dataflowA.getParent());
+               assertEquals(1, dataflowA.getProcessors().size());
+               editManager.undoDataflowEdit(dataflowA.getParent());
+               assertEquals(0, dataflowA.getProcessors().size());
+
+               assertEquals(1, dataflowB.getProcessors().size());
+               assertEquals(1, dataflowC.getProcessors().size());
+
+               
assertTrue(editManager.canUndoDataflowEdit(dataflowC.getParent()));
+               editManager.undoDataflowEdit(dataflowC.getParent());
+               
assertFalse(editManager.canUndoDataflowEdit(dataflowC.getParent()));
+               editManager.undoDataflowEdit(dataflowC.getParent()); // extra 
one
+               
assertFalse(editManager.canUndoDataflowEdit(dataflowC.getParent()));
+
+
+               assertEquals(1, dataflowB.getProcessors().size());
+               assertEquals(0, dataflowC.getProcessors().size());
+
+               editManager.undoDataflowEdit(dataflowB.getParent());
+               assertEquals(0, dataflowA.getProcessors().size());
+               assertEquals(0, dataflowB.getProcessors().size());
+               assertEquals(0, dataflowC.getProcessors().size());
+
+               editManager.redoDataflowEdit(dataflowA.getParent());
+               assertEquals(1, dataflowA.getProcessors().size());
+
+               editManager.redoDataflowEdit(dataflowA.getParent());
+               assertEquals(2, dataflowA.getProcessors().size());
+
+               editManager.redoDataflowEdit(dataflowA.getParent());
+               assertEquals(3, dataflowA.getProcessors().size());
+
+               // does not affect it
+               editManager.redoDataflowEdit(dataflowA.getParent());
+               assertEquals(3, dataflowA.getProcessors().size());
+               assertEquals(0, dataflowB.getProcessors().size());
+               assertEquals(0, dataflowC.getProcessors().size());
+       }
+
+       @Test
+       public void emptyUndoDoesNotFail() throws Exception {
+               EditManager editManager = new EditManagerImpl();
+               editManager.addObserver(editManagerObserver);
+               editManager.undoDataflowEdit(dataflow.getParent());
+       }
+
+       @Test
+       public void extraUndoesDoesNotFail() throws Exception {
+               EditManager editManager = new EditManagerImpl();
+               editManager.addObserver(editManagerObserver);
+
+               Edit<Workflow> edit = new AddProcessorEdit(dataflow, processor);
+               editManager.doDataflowEdit(dataflow.getParent(), edit);
+
+               assertFalse("Did not add processor", 
dataflow.getProcessors().isEmpty());
+               editManager.undoDataflowEdit(dataflow.getParent());
+               assertTrue("Did not undo add processor", 
dataflow.getProcessors()
+                               .isEmpty());
+               editManager.undoDataflowEdit(dataflow.getParent());
+       }
+
+       @Before
+       public void makeDataflow() {
+               dataflow = createDataflow();
+       }
+
+       protected Workflow createDataflow() {
+               WorkflowBundle workflowBundle = new WorkflowBundle();
+               Workflow workflow = new Workflow();
+               workflow.setParent(workflowBundle);
+               return workflow;
+       }
+
+       protected Processor createProcessor() {
+               Processor processor = new Processor();
+               processor.setName("proc-" + UUID.randomUUID());
+               return processor;
+       }
+
+       @Before
+       public void makeProcessor() {
+               processor = createProcessor();
+       }
+
+       private class EditManagerObserver implements Observer<EditManagerEvent> 
{
+
+               public List<EditManagerEvent> events = new ArrayList<>();
+
+               @Override
+               public void notify(Observable<EditManagerEvent> sender,
+                               EditManagerEvent message) throws Exception {
+                       events.add(message);
+                       if (message instanceof DataflowEditEvent) {
+                               DataflowEditEvent dataflowEdit = 
(DataflowEditEvent) message;
+                               assertTrue("Edit was not applied on edit 
event", dataflowEdit
+                                               .getEdit().isApplied());
+                       } else if (message instanceof DataFlowUndoEvent) {
+                               DataFlowUndoEvent dataflowUndo = 
(DataFlowUndoEvent) message;
+                               assertFalse("Edit was applied on undo event", 
dataflowUndo
+                                               .getEdit().isApplied());
+                       } else if (message instanceof DataFlowRedoEvent) {
+                               DataFlowRedoEvent dataflowEdit = 
(DataFlowRedoEvent) message;
+                               assertTrue("Edit was not applied on edit 
event", dataflowEdit
+                                               .getEdit().isApplied());
+                       } else {
+                               fail("Unknown event: " + message);
+                       }
+               }
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-file-api/src/main/java/net/sf/taverna/t2/workbench/file/AbstractDataflowPersistenceHandler.java
----------------------------------------------------------------------
diff --git 
a/taverna-file-api/src/main/java/net/sf/taverna/t2/workbench/file/AbstractDataflowPersistenceHandler.java
 
b/taverna-file-api/src/main/java/net/sf/taverna/t2/workbench/file/AbstractDataflowPersistenceHandler.java
deleted file mode 100644
index a5e606b..0000000
--- 
a/taverna-file-api/src/main/java/net/sf/taverna/t2/workbench/file/AbstractDataflowPersistenceHandler.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*******************************************************************************
- * 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.file;
-
-import java.util.Collections;
-import java.util.List;
-
-import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
-import net.sf.taverna.t2.workbench.file.exceptions.SaveException;
-import org.apache.taverna.scufl2.api.container.WorkflowBundle;
-
-public abstract class AbstractDataflowPersistenceHandler implements
-               DataflowPersistenceHandler {
-       @Override
-       public List<FileType> getOpenFileTypes() {
-               return Collections.emptyList();
-       }
-
-       @Override
-       public List<FileType> getSaveFileTypes() {
-               return Collections.emptyList();
-       }
-
-       @Override
-       public List<Class<?>> getOpenSourceTypes() {
-               return Collections.emptyList();
-       }
-
-       @Override
-       public List<Class<?>> getSaveDestinationTypes() {
-               return Collections.emptyList();
-       }
-
-       @Override
-       public DataflowInfo openDataflow(FileType fileType, Object source)
-                       throws OpenException {
-               throw new UnsupportedOperationException();
-       }
-
-       @Override
-       public DataflowInfo saveDataflow(WorkflowBundle workflowBundle, 
FileType fileType,
-                       Object destination) throws SaveException {
-               throw new UnsupportedOperationException();
-       }
-
-       @Override
-       public boolean wouldOverwriteDataflow(WorkflowBundle workflowBundle, 
FileType fileType,
-                       Object destination, DataflowInfo lastDataflowInfo) {
-               throw new UnsupportedOperationException();
-       }
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-file-api/src/main/java/net/sf/taverna/t2/workbench/file/DataflowInfo.java
----------------------------------------------------------------------
diff --git 
a/taverna-file-api/src/main/java/net/sf/taverna/t2/workbench/file/DataflowInfo.java
 
b/taverna-file-api/src/main/java/net/sf/taverna/t2/workbench/file/DataflowInfo.java
deleted file mode 100644
index 469d13b..0000000
--- 
a/taverna-file-api/src/main/java/net/sf/taverna/t2/workbench/file/DataflowInfo.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*******************************************************************************
- * 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.file;
-
-import java.util.Date;
-
-import org.apache.taverna.scufl2.api.container.WorkflowBundle;
-
-/**
- * Information about a WorkflowBundle that has been opened by the
- * {@link FileManager}.
- * <p>
- * This class, or a subclass of it, is used by
- * {@link DataflowPersistenceHandler}s to keep information about where a
- * {@link WorkflowBundle} came from or where it was saved to.
- * 
- * @author Stian Soiland-Reyes
- */
-public class DataflowInfo {
-       private final FileType fileType;
-       private final WorkflowBundle worflowBundle;
-       private final Date lastModified;
-       private final Object canonicalSource;
-
-       public DataflowInfo(FileType fileType, Object canonicalSource,
-                       WorkflowBundle worflowBundle, Date lastModified) {
-               this.fileType = fileType;
-               this.canonicalSource = canonicalSource;
-               this.worflowBundle = worflowBundle;
-               this.lastModified = lastModified;
-       }
-
-       public DataflowInfo(FileType fileType, Object canonicalSource,
-                       WorkflowBundle worflowBundle) {
-               this(fileType, canonicalSource, worflowBundle, null);
-       }
-
-       /**
-        * Return the canonical source of where the WorkflowBundle was opened 
from
-        * or saved to.
-        * <p>
-        * This is not necessarily the source provided to
-        * {@link FileManager#openDataflow(FileType, Object)} or
-        * {@link FileManager#saveDataflow(WorkflowBundle, FileType, Object, 
boolean)}
-        * , but it's canonical version.
-        * <p>
-        * For instance, if a WorkflowBundle was opened from a
-        * File("relative/something.wfbundle) this canonical source would 
resolve
-        * the relative path.
-        * 
-        * @return
-        */
-       public Object getCanonicalSource() {
-               return canonicalSource;
-       }
-
-       /**
-        * Return the WorkflowBundle that is open.
-        * 
-        * @return The open WorkflowBundle
-        */
-       public WorkflowBundle getDataflow() {
-               return worflowBundle;
-       }
-
-       /**
-        * Get the last modified {@link Date} of the source at the time when it 
was
-        * opened/saved.
-        * <p>
-        * It is important that this value is checked on creation time, and not 
on
-        * demand.
-        * 
-        * @return The {@link Date} of the source/destination's last modified
-        *         timestamp, or <code>null</code> if unknown.
-        */
-       public Date getLastModified() {
-               return lastModified;
-       }
-
-       /**
-        * The {@link FileType} of this {@link WorkflowBundle} serialisation 
used
-        * for opening/saving.
-        * 
-        * @return The {@link FileType}, for instance
-        *         {@link 
net.sf.taverna.t2.workbench.file.impl.WorkflowBundleFileType}
-        */
-       public FileType getFileType() {
-               return fileType;
-       }
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-file-api/src/main/java/net/sf/taverna/t2/workbench/file/DataflowPersistenceHandler.java
----------------------------------------------------------------------
diff --git 
a/taverna-file-api/src/main/java/net/sf/taverna/t2/workbench/file/DataflowPersistenceHandler.java
 
b/taverna-file-api/src/main/java/net/sf/taverna/t2/workbench/file/DataflowPersistenceHandler.java
deleted file mode 100644
index 4b9234a..0000000
--- 
a/taverna-file-api/src/main/java/net/sf/taverna/t2/workbench/file/DataflowPersistenceHandler.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*******************************************************************************
- * 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.file;
-
-import java.io.File;
-import java.net.URL;
-import java.util.Collection;
-
-import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
-import net.sf.taverna.t2.workbench.file.exceptions.SaveException;
-import org.apache.taverna.scufl2.api.container.WorkflowBundle;
-
-/**
- * A handler for opening or saving {@link WorkflowBundle} from the
- * {@link FileManager}.
- * 
- * @author Stian Soiland-Reyes
- */
-public interface DataflowPersistenceHandler {
-       /**
-        * A collection of supported file types for
-        * {@link #openDataflow(FileType, Object)}, or an empty collection if
-        * opening is not supported by this handler.
-        * 
-        * @return A collection of supported {@link FileType}s for opening.
-        */
-       Collection<FileType> getOpenFileTypes();
-
-       /**
-        * A collection of supported source classes for
-        * {@link #openDataflow(FileType, Object)}, or an empty collection if
-        * opening is not supported by this handler.
-        * <p>
-        * For example, a handler that supports sources opened from a {@link 
File}
-        * and {@link URL} could return
-        * <code>Arrays.asList(File.class, URL.class)</code>
-        * 
-        * @return A collection of supported {@link Class}es of the open source
-        *         types.
-        */
-       Collection<Class<?>> getOpenSourceTypes();
-
-       /**
-        * A collection of supported destination classes for
-        * {@link #saveDataflow(Dataflow, FileType, Object)}, or an empty 
collection
-        * if saving is not supported by this handler.
-        * <p>
-        * For example, a handler that supports saving to destinations that are
-        * instances of a {@link File} could return
-        * <code>Arrays.asList(File.class)</code>
-        * 
-        * @return A collection of supported {{@link Class}es of the save
-        *         destination types.
-        */
-       Collection<Class<?>> getSaveDestinationTypes();
-
-       /**
-        * A collection of supported file types for
-        * {@link #saveDataflow(WorkflowBundle, FileType, Object)}, or an empty
-        * collection if saving is not supported by this handler.
-        * 
-        * @return A collection of supported {@link FileType}s for saving.
-        */
-       Collection<FileType> getSaveFileTypes();
-
-       /**
-        * Open a dataflow from a source containing a dataflow of the given
-        * {@link FileType}.
-        * <p>
-        * The {@link FileType} will be equal to one of the types from
-        * {@link #getOpenFileTypes()}, and the source class will be one that is
-        * assignable to one of the classes from {@link #getOpenSourceTypes()}.
-        * 
-        * @param fileType
-        *            {@link FileType} determining which serialisation method 
has
-        *            been used
-        * @param source
-        *            Source for reading the WorkflowBundle
-        * @return {@link DataflowInfo} describing the opened WorkflowBundle,
-        *         including the WorkflowBundle itself
-        * @throws OpenException
-        *             If the WorkflowBundle could not be read, parsed or 
opened for
-        *             any reason.
-        */
-       DataflowInfo openDataflow(FileType fileType, Object source)
-                       throws OpenException;
-
-       /**
-        * Save a WorkflowBundle to a destination of the given {@link FileType}.
-        * <p>
-        * The {@link FileType} will be equal to one of the types from
-        * {@link #getSaveFileTypes()}, and the destination class will be one 
that
-        * is assignable to one of the classes from
-        * {@link #getSaveDestinationTypes()}.
-        * 
-        * @param dataflow
-        *            {@link WorkflowBundle} to be saved
-        * @param fileType
-        *            {@link FileType} determining which serialisation method 
to use
-        * @param destination
-        *            Destination for writing the WorkflowBundle
-        * @return {@link DataflowInfo} describing the saved WorkflowBundle,
-        *         including the WorkflowBundle itself
-        * @throws OpenException
-        *             If the WorkflowBundle could not be read, parsed or 
opened for
-        *             any reason.
-        */
-       DataflowInfo saveDataflow(WorkflowBundle dataflow, FileType fileType,
-                       Object destination) throws SaveException;
-
-       /**
-        * Return <code>true</code> if a call to
-        * {@link #saveDataflow(WorkflowBundle, FileType, Object)} would 
overwrite
-        * the destination, and the destination is different from last
-        * {@link #openDataflow(FileType, Object)} or
-        * {@link #saveDataflow(WorkflowBundle, FileType, Object)} of the given
-        * dataflow.
-        * 
-        * @param dataflow
-        *            {@link WorkflowBundle} that is to be saved
-        * @param fileType
-        *            {@link FileType} for saving WorkflowBundle
-        * @param destination
-        *            destination for writing WorkflowBundle
-        * @param lastDataflowInfo
-        *            last provided {@link DataflowInfo} returned by
-        *            {@link #openDataflow(FileType, Object)} or
-        *            {@link #saveDataflow(WorkflowBundle, FileType, Object)}. 
(but
-        *            not necessarily from this handler)
-        * @return <code>true</code> if the save would overwrite
-        */
-       boolean wouldOverwriteDataflow(WorkflowBundle dataflow, FileType 
fileType,
-                       Object destination, DataflowInfo lastDataflowInfo);
-}

Reply via email to