http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveMenuAction.java
 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveMenuAction.java
new file mode 100644
index 0000000..eeaecb3
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveMenuAction.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.workbench.file.impl.menu;
+
+import static 
net.sf.taverna.t2.workbench.file.impl.menu.FileSaveMenuSection.FILE_SAVE_SECTION_URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.SaveWorkflowAction;
+
+public class FileSaveMenuAction extends AbstractMenuAction {
+       private final EditManager editManager;
+       private final FileManager fileManager;
+
+       public FileSaveMenuAction(EditManager editManager, FileManager 
fileManager) {
+               super(FILE_SAVE_SECTION_URI, 10);
+               this.editManager = editManager;
+               this.fileManager = fileManager;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new SaveWorkflowAction(editManager, fileManager);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveMenuSection.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveMenuSection.java
 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveMenuSection.java
new file mode 100644
index 0000000..a75a855
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/FileSaveMenuSection.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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.impl.menu;
+
+import java.net.URI;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuSection;
+
+public class FileSaveMenuSection extends AbstractMenuSection {
+       public static final URI FILE_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#file";);
+       public static final URI FILE_SAVE_SECTION_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#fileSaveSection";);
+
+       public FileSaveMenuSection() {
+               super(FILE_URI, 40, FILE_SAVE_SECTION_URI);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/WorkflowsMenu.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/WorkflowsMenu.java
 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/WorkflowsMenu.java
new file mode 100644
index 0000000..e056572
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/menu/WorkflowsMenu.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * 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.impl.menu;
+
+import static java.awt.event.KeyEvent.VK_0;
+import static java.awt.event.KeyEvent.VK_W;
+import static javax.swing.Action.MNEMONIC_KEY;
+import static javax.swing.SwingUtilities.invokeLater;
+import static net.sf.taverna.t2.ui.menu.DefaultMenuBar.DEFAULT_MENU_BAR;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.ButtonGroup;
+import javax.swing.JMenu;
+import javax.swing.JRadioButtonMenuItem;
+
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.ui.menu.AbstractMenuCustom;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.edits.EditManager.AbstractDataflowEditEvent;
+import net.sf.taverna.t2.workbench.edits.EditManager.EditManagerEvent;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.events.AbstractDataflowEvent;
+import net.sf.taverna.t2.workbench.file.events.FileManagerEvent;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+public class WorkflowsMenu extends AbstractMenuCustom {
+       private EditManagerObserver editManagerObserver = new 
EditManagerObserver();
+       private FileManager fileManager;
+       private FileManagerObserver fileManagerObserver = new 
FileManagerObserver();
+
+       private JMenu workflowsMenu;
+
+       public WorkflowsMenu(EditManager editManager, FileManager fileManager) {
+               super(DEFAULT_MENU_BAR, 900);
+               this.fileManager = fileManager;
+               fileManager.addObserver(fileManagerObserver);
+               editManager.addObserver(editManagerObserver);
+       }
+
+       @Override
+       protected Component createCustomComponent() {
+               DummyAction action = new DummyAction("Workflows");
+               action.putValue(MNEMONIC_KEY, VK_W);
+
+               workflowsMenu = new JMenu(action);
+
+               updateWorkflowsMenu();
+               return workflowsMenu;
+       }
+
+       public void updateWorkflowsMenu() {
+               invokeLater(new Runnable() {
+                       @Override
+                       public void run() {
+                               updateWorkflowsMenuUI();
+                       }
+               });
+       }
+
+       protected void updateWorkflowsMenuUI() {
+               workflowsMenu.setEnabled(false);
+               workflowsMenu.removeAll();
+               ButtonGroup workflowsGroup = new ButtonGroup();
+
+               int i = 0;
+               WorkflowBundle currentDataflow = 
fileManager.getCurrentDataflow();
+               for (WorkflowBundle workflowBundle : 
fileManager.getOpenDataflows()) {
+                       String name = 
fileManager.getDataflowName(workflowBundle);
+                       if (fileManager.isDataflowChanged(workflowBundle))
+                               name = "*" + name;
+                       // A counter
+                       name = ++i + " " + name;
+
+                       SwitchWorkflowAction switchWorkflowAction = new 
SwitchWorkflowAction(
+                                       name, workflowBundle);
+                       if (i < 10)
+                               switchWorkflowAction.putValue(MNEMONIC_KEY, new 
Integer(VK_0
+                                               + i));
+
+                       JRadioButtonMenuItem switchWorkflowMenuItem = new 
JRadioButtonMenuItem(
+                                       switchWorkflowAction);
+                       workflowsGroup.add(switchWorkflowMenuItem);
+                       if (workflowBundle.equals(currentDataflow))
+                               switchWorkflowMenuItem.setSelected(true);
+                       workflowsMenu.add(switchWorkflowMenuItem);
+               }
+               if (i == 0)
+                       workflowsMenu.add(new NoWorkflowsOpen());
+               workflowsMenu.setEnabled(true);
+               workflowsMenu.revalidate();
+       }
+
+       private final class EditManagerObserver implements
+                       Observer<EditManagerEvent> {
+               @Override
+               public void notify(Observable<EditManagerEvent> sender,
+                               EditManagerEvent message) throws Exception {
+                       if (message instanceof AbstractDataflowEditEvent)
+                               updateWorkflowsMenu();
+               }
+       }
+
+       private final class FileManagerObserver implements
+                       Observer<FileManagerEvent> {
+               @Override
+               public void notify(Observable<FileManagerEvent> sender,
+                               FileManagerEvent message) throws Exception {
+                       if (message instanceof AbstractDataflowEvent)
+                               updateWorkflowsMenu();
+                       // TODO: Don't rebuild whole menu
+               }
+       }
+
+       @SuppressWarnings("serial")
+       private final class NoWorkflowsOpen extends AbstractAction {
+               private NoWorkflowsOpen() {
+                       super("No workflows open");
+                       setEnabled(false);
+               }
+
+               @Override
+               public void actionPerformed(ActionEvent e) {
+                       // No-op
+               }
+       }
+
+       @SuppressWarnings("serial")
+       private final class SwitchWorkflowAction extends AbstractAction {
+               private final WorkflowBundle workflowBundle;
+
+               private SwitchWorkflowAction(String name, WorkflowBundle 
workflowBundle) {
+                       super(name);
+                       this.workflowBundle = workflowBundle;
+               }
+
+               @Override
+               public void actionPerformed(ActionEvent e) {
+                       fileManager.setCurrentDataflow(workflowBundle);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/CloseToolbarAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/CloseToolbarAction.java
 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/CloseToolbarAction.java
new file mode 100644
index 0000000..68ef3f9
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/CloseToolbarAction.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * 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.impl.toolbar;
+
+import static 
net.sf.taverna.t2.workbench.file.impl.toolbar.FileToolbarMenuSection.FILE_TOOLBAR_SECTION;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.CloseWorkflowAction;
+
+/**
+ * Action to close the current workflow.
+ * 
+ * @author Alex Nenadic
+ */
+public class CloseToolbarAction extends AbstractMenuAction {
+       private static final URI FILE_CLOSE_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#fileToolbarClose";);
+       private final EditManager editManager;
+       private final FileManager fileManager;
+
+       public CloseToolbarAction(EditManager editManager, FileManager 
fileManager) {
+               super(FILE_TOOLBAR_SECTION, 30, FILE_CLOSE_URI);
+               this.editManager = editManager;
+               this.fileManager = fileManager;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new CloseWorkflowAction(editManager, fileManager);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/FileToolbarMenuSection.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/FileToolbarMenuSection.java
 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/FileToolbarMenuSection.java
new file mode 100644
index 0000000..257d590
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/FileToolbarMenuSection.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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.impl.toolbar;
+
+import static net.sf.taverna.t2.ui.menu.DefaultToolBar.DEFAULT_TOOL_BAR;
+
+import java.net.URI;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuSection;
+
+public class FileToolbarMenuSection extends AbstractMenuSection {
+       public static final URI FILE_TOOLBAR_SECTION = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#fileToolbarSection";);
+
+       public FileToolbarMenuSection() {
+               super(DEFAULT_TOOL_BAR, 10, FILE_TOOLBAR_SECTION);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/NewToolbarAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/NewToolbarAction.java
 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/NewToolbarAction.java
new file mode 100644
index 0000000..2c8e922
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/NewToolbarAction.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * 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.impl.toolbar;
+
+import static 
net.sf.taverna.t2.workbench.file.impl.toolbar.FileToolbarMenuSection.FILE_TOOLBAR_SECTION;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.NewWorkflowAction;
+
+public class NewToolbarAction extends AbstractMenuAction {
+       private static final URI FILE_NEW_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#fileToolbarNew";);
+       private final FileManager fileManager;
+
+       public NewToolbarAction(FileManager fileManager) {
+               super(FILE_TOOLBAR_SECTION, 10, FILE_NEW_URI);
+               this.fileManager = fileManager;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new NewWorkflowAction(fileManager);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/OpenToolbarAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/OpenToolbarAction.java
 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/OpenToolbarAction.java
new file mode 100644
index 0000000..ae99509
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/OpenToolbarAction.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * 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.impl.toolbar;
+
+import static 
net.sf.taverna.t2.workbench.file.impl.toolbar.FileToolbarMenuSection.FILE_TOOLBAR_SECTION;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.OpenWorkflowAction;
+
+public class OpenToolbarAction extends AbstractMenuAction {
+       private static final URI FILE_OPEN_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#fileToolbarOpen";);
+       private final FileManager fileManager;
+
+       public OpenToolbarAction(FileManager fileManager) {
+               super(FILE_TOOLBAR_SECTION, 20, FILE_OPEN_URI);
+               this.fileManager = fileManager;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new OpenWorkflowAction(fileManager);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/OpenWorkflowFromURLToolbarAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/OpenWorkflowFromURLToolbarAction.java
 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/OpenWorkflowFromURLToolbarAction.java
new file mode 100644
index 0000000..2554063
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/OpenWorkflowFromURLToolbarAction.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * 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.impl.toolbar;
+
+import static 
net.sf.taverna.t2.workbench.file.impl.toolbar.FileToolbarMenuSection.FILE_TOOLBAR_SECTION;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.OpenWorkflowFromURLAction;
+
+public class OpenWorkflowFromURLToolbarAction extends AbstractMenuAction {
+       private static final URI FILE_OPEN_FROM_URL_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#fileToolbarOpenFromURL";);
+       private final FileManager fileManager;
+
+       public OpenWorkflowFromURLToolbarAction(FileManager fileManager) {
+               super(FILE_TOOLBAR_SECTION, 25, FILE_OPEN_FROM_URL_URI);
+               this.fileManager = fileManager;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new OpenWorkflowFromURLAction(null, fileManager);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/SaveToolbarAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/SaveToolbarAction.java
 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/SaveToolbarAction.java
new file mode 100644
index 0000000..53ba720
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/toolbar/SaveToolbarAction.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * 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.impl.toolbar;
+
+import static 
net.sf.taverna.t2.workbench.file.impl.toolbar.FileToolbarMenuSection.FILE_TOOLBAR_SECTION;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.impl.actions.SaveWorkflowAction;
+
+public class SaveToolbarAction extends AbstractMenuAction {
+       private static final URI FILE_SAVE_URI = URI
+                       
.create("http://taverna.sf.net/2008/t2workbench/menu#fileToolbarSave";);
+       private final EditManager editManager;
+       private final FileManager fileManager;
+
+       public SaveToolbarAction(EditManager editManager, FileManager 
fileManager) {
+               super(FILE_TOOLBAR_SECTION, 40, FILE_SAVE_URI);
+               this.editManager = editManager;
+               this.fileManager = fileManager;
+       }
+
+       @Override
+       protected Action createAction() {
+               return new SaveWorkflowAction(editManager, fileManager);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
 
b/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
new file mode 100644
index 0000000..100915c
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
@@ -0,0 +1,20 @@
+net.sf.taverna.t2.workbench.file.impl.menu.FileCloseMenuAction
+net.sf.taverna.t2.workbench.file.impl.menu.FileNewMenuAction
+net.sf.taverna.t2.workbench.file.impl.menu.FileOpenMenuAction
+net.sf.taverna.t2.workbench.file.impl.menu.FileOpenFromURLMenuAction
+net.sf.taverna.t2.workbench.file.impl.menu.FileOpenMenuSection
+net.sf.taverna.t2.workbench.file.impl.menu.FileOpenRecentMenuAction
+net.sf.taverna.t2.workbench.file.impl.menu.FileSaveMenuSection
+net.sf.taverna.t2.workbench.file.impl.menu.FileSaveMenuAction
+net.sf.taverna.t2.workbench.file.impl.menu.FileSaveAllMenuAction
+net.sf.taverna.t2.workbench.file.impl.menu.FileSaveAsMenuAction
+
+net.sf.taverna.t2.workbench.file.impl.menu.WorkflowsMenu
+net.sf.taverna.t2.workbench.file.impl.menu.FileCloseAllMenuAction
+
+net.sf.taverna.t2.workbench.file.impl.toolbar.FileToolbarMenuSection
+net.sf.taverna.t2.workbench.file.impl.toolbar.NewToolbarAction
+net.sf.taverna.t2.workbench.file.impl.toolbar.OpenToolbarAction
+net.sf.taverna.t2.workbench.file.impl.toolbar.OpenWorkflowFromURLToolbarAction
+net.sf.taverna.t2.workbench.file.impl.toolbar.SaveToolbarAction
+net.sf.taverna.t2.workbench.file.impl.toolbar.CloseToolbarAction

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ShutdownSPI
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ShutdownSPI
 
b/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ShutdownSPI
new file mode 100644
index 0000000..cc53d36
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ShutdownSPI
@@ -0,0 +1 @@
+net.sf.taverna.t2.workbench.file.impl.hooks.CloseWorkflowsOnShutdown

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler
 
b/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler
new file mode 100644
index 0000000..cfd1c7a
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler
@@ -0,0 +1,2 @@
+net.sf.taverna.t2.workbench.file.impl.T2DataflowOpener
+net.sf.taverna.t2.workbench.file.impl.DataflowFromDataflowPersistenceHandler
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.file.FileManager
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.file.FileManager
 
b/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.file.FileManager
new file mode 100644
index 0000000..656feeb
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.file.FileManager
@@ -0,0 +1 @@
+net.sf.taverna.t2.workbench.file.impl.FileManagerImpl
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/resources/META-INF/spring/file-impl-context-osgi.xml
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/resources/META-INF/spring/file-impl-context-osgi.xml
 
b/taverna-workbench-file-impl/src/main/resources/META-INF/spring/file-impl-context-osgi.xml
new file mode 100644
index 0000000..7c6e290
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/resources/META-INF/spring/file-impl-context-osgi.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns:beans="http://www.springframework.org/schema/beans";
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      
http://www.springframework.org/schema/beans/spring-beans.xsd
+                      http://www.springframework.org/schema/osgi
+                      
http://www.springframework.org/schema/osgi/spring-osgi.xsd";>
+
+       <service ref="FileCloseMenuAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="file.close" />
+               </service-properties>
+       </service>
+       <service ref="FileNewMenuAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="file.new" />
+               </service-properties>
+       </service>
+       <service ref="FileOpenMenuAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="file.open" />
+               </service-properties>
+       </service>
+       <service ref="FileOpenFromURLMenuAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="file.open.url" />
+               </service-properties>
+       </service>
+       <service ref="FileOpenMenuSection" auto-export="interfaces" />
+       <service ref="FileOpenRecentMenuAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="file.open.recent" 
/>
+               </service-properties>
+       </service>
+       <service ref="FileSaveMenuSection" auto-export="interfaces" />
+       <service ref="FileSaveMenuAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="file.save" />
+               </service-properties>
+       </service>
+       <service ref="FileSaveAllMenuAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="file.save.all" />
+               </service-properties>
+       </service>
+       <service ref="FileSaveAsMenuAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="file.save.as" />
+               </service-properties>
+       </service>
+       <service ref="WorkflowsMenu" auto-export="interfaces" />
+       <service ref="FileCloseAllMenuAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="file.close.all" />
+               </service-properties>
+       </service>
+       <service ref="FileToolbarMenuSection" auto-export="interfaces" />
+       <service ref="NewToolbarAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="toolbar.new" />
+               </service-properties>
+       </service>
+       <service ref="OpenToolbarAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="toolbar.open" />
+               </service-properties>
+       </service>
+       <service ref="OpenWorkflowFromURLToolbarAction" 
auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="toolbar.open.url" 
/>
+               </service-properties>
+       </service>
+       <service ref="SaveToolbarAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="toolbar.save" />
+               </service-properties>
+       </service>
+       <service ref="CloseToolbarAction" auto-export="interfaces">
+               <service-properties>
+                       <beans:entry key="menu.action" value="toolbar.close" />
+               </service-properties>
+       </service>
+
+       <service ref="T2DataflowOpener" 
interface="net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler" />
+
+       <service ref="WorkflowBundleOpener" 
interface="net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler" />
+       <service ref="WorkflowBundleSaver" 
interface="net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler" />
+
+       <service ref="CloseWorkflowsOnShutdown" 
interface="net.sf.taverna.t2.workbench.ShutdownSPI" />
+
+       <service ref="FileManagerImpl" 
interface="net.sf.taverna.t2.workbench.file.FileManager" />
+
+       <reference id="editManager" 
interface="net.sf.taverna.t2.workbench.edits.EditManager" />
+       <reference id="applicationConfiguration" 
interface="uk.org.taverna.configuration.app.ApplicationConfiguration" />
+       <reference id="workflowBundleIO" 
interface="uk.org.taverna.scufl2.api.io.WorkflowBundleIO" />
+
+       <list id="dataflowPersistenceHandlers" 
interface="net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler" 
cardinality="0..N">
+               <listener ref="DataflowPersistenceHandlerRegistry" 
bind-method="update" unbind-method="update" />
+       </list>
+</beans:beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/main/resources/META-INF/spring/file-impl-context.xml
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/main/resources/META-INF/spring/file-impl-context.xml
 
b/taverna-workbench-file-impl/src/main/resources/META-INF/spring/file-impl-context.xml
new file mode 100644
index 0000000..493df5f
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/main/resources/META-INF/spring/file-impl-context.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      
http://www.springframework.org/schema/beans/spring-beans.xsd";>
+
+       <bean id="FileCloseMenuAction" 
class="net.sf.taverna.t2.workbench.file.impl.menu.FileCloseMenuAction">
+       <constructor-arg ref="editManager" />
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+       <bean id="FileNewMenuAction" 
class="net.sf.taverna.t2.workbench.file.impl.menu.FileNewMenuAction">
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+       <bean id="FileOpenMenuAction" 
class="net.sf.taverna.t2.workbench.file.impl.menu.FileOpenMenuAction">
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+       <bean id="FileOpenFromURLMenuAction" 
class="net.sf.taverna.t2.workbench.file.impl.menu.FileOpenFromURLMenuAction">
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+       <bean id="FileOpenMenuSection" 
class="net.sf.taverna.t2.workbench.file.impl.menu.FileOpenMenuSection" />
+       <bean id="FileOpenRecentMenuAction" 
class="net.sf.taverna.t2.workbench.file.impl.menu.FileOpenRecentMenuAction">
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+               <property name="applicationConfiguration" 
ref="applicationConfiguration"/>
+    </bean>
+       <bean id="FileSaveMenuSection" 
class="net.sf.taverna.t2.workbench.file.impl.menu.FileSaveMenuSection" />
+       <bean id="FileSaveMenuAction" 
class="net.sf.taverna.t2.workbench.file.impl.menu.FileSaveMenuAction">
+       <constructor-arg ref="editManager" />
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+       <bean id="FileSaveAllMenuAction" 
class="net.sf.taverna.t2.workbench.file.impl.menu.FileSaveAllMenuAction">
+       <constructor-arg ref="editManager" />
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+       <bean id="FileSaveAsMenuAction" 
class="net.sf.taverna.t2.workbench.file.impl.menu.FileSaveAsMenuAction">
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+       <bean id="WorkflowsMenu" 
class="net.sf.taverna.t2.workbench.file.impl.menu.WorkflowsMenu">
+           <constructor-arg ref="editManager" />
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+       </bean>
+       <bean id="FileCloseAllMenuAction" 
class="net.sf.taverna.t2.workbench.file.impl.menu.FileCloseAllMenuAction">
+       <constructor-arg ref="editManager" />
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+       <bean id="FileToolbarMenuSection" 
class="net.sf.taverna.t2.workbench.file.impl.toolbar.FileToolbarMenuSection" />
+       <bean id="NewToolbarAction" 
class="net.sf.taverna.t2.workbench.file.impl.toolbar.NewToolbarAction">
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+       <bean id="OpenToolbarAction" 
class="net.sf.taverna.t2.workbench.file.impl.toolbar.OpenToolbarAction">
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+       <bean id="OpenWorkflowFromURLToolbarAction" 
class="net.sf.taverna.t2.workbench.file.impl.toolbar.OpenWorkflowFromURLToolbarAction">
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+       <bean id="SaveToolbarAction" 
class="net.sf.taverna.t2.workbench.file.impl.toolbar.SaveToolbarAction">
+       <constructor-arg ref="editManager" />
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+       <bean id="CloseToolbarAction" 
class="net.sf.taverna.t2.workbench.file.impl.toolbar.CloseToolbarAction">
+       <constructor-arg ref="editManager" />
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+
+       <bean id="T2DataflowOpener" 
class="net.sf.taverna.t2.workbench.file.impl.T2DataflowOpener">
+                       <property name="workflowBundleIO" 
ref="workflowBundleIO"/>
+       </bean>
+
+       <bean id="WorkflowBundleOpener" 
class="net.sf.taverna.t2.workbench.file.impl.WorkflowBundleOpener">
+                       <property name="workflowBundleIO" 
ref="workflowBundleIO"/>
+       </bean>
+       <bean id="WorkflowBundleSaver" 
class="net.sf.taverna.t2.workbench.file.impl.WorkflowBundleSaver">
+                       <property name="workflowBundleIO" 
ref="workflowBundleIO"/>
+       </bean>
+
+       <bean id="CloseWorkflowsOnShutdown" 
class="net.sf.taverna.t2.workbench.file.impl.hooks.CloseWorkflowsOnShutdown">
+       <constructor-arg ref="editManager" />
+       <constructor-arg>
+                       <ref local="FileManagerImpl" />
+               </constructor-arg>
+    </bean>
+
+       <bean id="FileManagerImpl" 
class="net.sf.taverna.t2.workbench.file.impl.FileManagerImpl">
+       <constructor-arg name="editManager" ref="editManager" />
+       <property name="dataflowPersistenceHandlerRegistry">
+               <ref local="DataflowPersistenceHandlerRegistry"/>
+       </property>
+       </bean>
+
+       <bean id="DataflowPersistenceHandlerRegistry" 
class="net.sf.taverna.t2.workbench.file.impl.DataflowPersistenceHandlerRegistry">
+       <property name="dataflowPersistenceHandlers" 
ref="dataflowPersistenceHandlers" />
+       </bean>
+
+
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/test/java/net/sf/taverna/t2/workbench/file/impl/FileManagerTest.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/test/java/net/sf/taverna/t2/workbench/file/impl/FileManagerTest.java
 
b/taverna-workbench-file-impl/src/test/java/net/sf/taverna/t2/workbench/file/impl/FileManagerTest.java
new file mode 100644
index 0000000..691b278
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/test/java/net/sf/taverna/t2/workbench/file/impl/FileManagerTest.java
@@ -0,0 +1,385 @@
+/*******************************************************************************
+ * 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.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.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.impl.EditManagerImpl;
+import net.sf.taverna.t2.workbench.file.DataflowInfo;
+import net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.events.FileManagerEvent;
+import net.sf.taverna.t2.workbench.file.events.SetCurrentDataflowEvent;
+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
+import net.sf.taverna.t2.workbench.file.exceptions.OverwriteException;
+import net.sf.taverna.t2.workflow.edits.AddProcessorEdit;
+import net.sf.taverna.t2.workflow.edits.RenameEdit;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+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.io.WorkflowBundleIO;
+import uk.org.taverna.scufl2.api.io.WorkflowBundleReader;
+import uk.org.taverna.scufl2.api.io.WorkflowBundleWriter;
+import uk.org.taverna.scufl2.rdfxml.RDFXMLReader;
+import uk.org.taverna.scufl2.rdfxml.RDFXMLWriter;
+import uk.org.taverna.scufl2.translator.t2flow.T2FlowReader;
+
+public class FileManagerTest {
+
+       private static final WorkflowBundleFileType WF_BUNDLE_FILE_TYPE = new 
WorkflowBundleFileType();
+       private static final T2FlowFileType T2_FLOW_FILE_TYPE = new 
T2FlowFileType();
+
+       private static final String DUMMY_WORKFLOW_T2FLOW = 
"dummy-workflow.t2flow";
+
+       private FileManagerImpl fileManager;
+       private EditManager editManager;
+
+       private FileManagerObserver fileManagerObserver= new 
FileManagerObserver();;
+
+       @Test
+       public void close() throws Exception {
+               assertTrue("Non-empty set of open dataflows", fileManager
+                               .getOpenDataflows().isEmpty());
+               WorkflowBundle dataflow = openDataflow();
+               assertEquals("Unexpected list of open dataflows", Arrays
+                               .asList(dataflow), 
fileManager.getOpenDataflows());
+               fileManager.closeDataflow(dataflow, true);
+               assertNotSame(dataflow, fileManager.getOpenDataflows().get(0));
+               assertTrue("Did not insert empty dataflow after close", 
fileManager
+                               
.getOpenDataflows().get(0).getMainWorkflow().getProcessors().isEmpty());
+       }
+
+       @Test
+       public void openRemovesEmptyDataflow() throws Exception {
+               WorkflowBundle newDataflow = fileManager.newDataflow();
+               assertEquals("Unexpected list of open dataflows", Arrays
+                               .asList(newDataflow), 
fileManager.getOpenDataflows());
+               WorkflowBundle dataflow = openDataflow();
+               // Should have removed newDataflow
+               assertEquals("Unexpected list of open dataflows", Arrays
+                               .asList(dataflow), 
fileManager.getOpenDataflows());
+       }
+
+       @Test
+       public void isChanged() throws Exception {
+               WorkflowBundle dataflow = openDataflow();
+               assertFalse("Dataflow should not have changed", fileManager
+                               .isDataflowChanged(dataflow));
+
+               // Do a change
+               Processor emptyProcessor = new Processor();
+               Edit<Workflow> addProcessorEdit = new 
AddProcessorEdit(dataflow.getMainWorkflow(),
+                               emptyProcessor);
+               editManager.doDataflowEdit(dataflow, addProcessorEdit);
+               assertTrue("Dataflow should have changed", fileManager
+                               .isDataflowChanged(dataflow));
+
+               // Save it with the change
+               File dataflowFile = File.createTempFile("test", ".t2flow");
+               dataflowFile.deleteOnExit();
+               dataflowFile.delete();
+
+               fileManager.saveDataflow(dataflow, WF_BUNDLE_FILE_TYPE, 
dataflowFile, false);
+               assertFalse("Dataflow should no longer be marked as changed",
+                               fileManager.isDataflowChanged(dataflow));
+       }
+
+       @Ignore("Undo support for ischanged not yet implemented")
+       @Test
+       public void isChangedWithUndo() throws Exception {
+               WorkflowBundle dataflow = openDataflow();
+               // Do a change
+               Processor emptyProcessor = new Processor();
+               Edit<Workflow> addProcessorEdit = new 
AddProcessorEdit(dataflow.getMainWorkflow(),
+                               emptyProcessor);
+               editManager.doDataflowEdit(dataflow, addProcessorEdit);
+               assertTrue("Dataflow should have changed", fileManager
+                               .isDataflowChanged(dataflow));
+               editManager.undoDataflowEdit(dataflow);
+               assertFalse(
+                               "Dataflow should no longer be marked as changed 
after undo",
+                               fileManager.isDataflowChanged(dataflow));
+               editManager.redoDataflowEdit(dataflow);
+               assertTrue("Dataflow should have changed after redo before 
save",
+                               fileManager.isDataflowChanged(dataflow));
+
+               // Save it with the change
+               File dataflowFile = File.createTempFile("test", ".t2flow");
+               dataflowFile.deleteOnExit();
+               dataflowFile.delete();
+               fileManager.saveDataflow(dataflow, WF_BUNDLE_FILE_TYPE, 
dataflowFile, false);
+               assertFalse("Dataflow should no longer be marked as changed",
+                               fileManager.isDataflowChanged(dataflow));
+
+               editManager.undoDataflowEdit(dataflow);
+               assertTrue("Dataflow should have changed after undo", 
fileManager
+                               .isDataflowChanged(dataflow));
+               fileManager.saveDataflow(dataflow, WF_BUNDLE_FILE_TYPE, 
dataflowFile, false);
+               editManager.redoDataflowEdit(dataflow);
+               assertTrue("Dataflow should have changed after redo after save",
+                               fileManager.isDataflowChanged(dataflow));
+       }
+
+       @Test
+       public void isListed() throws Exception {
+               assertTrue("Non-empty set of open data flows", fileManager
+                               .getOpenDataflows().isEmpty());
+               WorkflowBundle dataflow = openDataflow();
+               assertEquals("Unexpected list of open dataflows", Arrays
+                               .asList(dataflow), 
fileManager.getOpenDataflows());
+       }
+
+       /**
+        * Always uses a <strong>new</strong> file manager instead of the 
instance
+        * one from {@link FileManager#getInstance()}.
+        *
+        * @see #getFileManagerInstance()
+        *
+        */
+       @Before
+       public void makeFileManager() {
+               System.setProperty("java.awt.headless", "true");
+               editManager = new EditManagerImpl();
+               fileManager = new FileManagerImpl(editManager);
+               fileManagerObserver = new FileManagerObserver();
+               fileManager.addObserver(fileManagerObserver);
+               WorkflowBundleIO workflowBundleIO = new WorkflowBundleIO();
+               
workflowBundleIO.setReaders(Arrays.<WorkflowBundleReader>asList(new 
RDFXMLReader(), new T2FlowReader()));
+               
workflowBundleIO.setWriters(Arrays.<WorkflowBundleWriter>asList(new 
RDFXMLWriter()));
+               T2DataflowOpener t2DataflowOpener = new T2DataflowOpener();
+               t2DataflowOpener.setWorkflowBundleIO(workflowBundleIO);
+               WorkflowBundleOpener workflowBundleOpener = new 
WorkflowBundleOpener();
+               workflowBundleOpener.setWorkflowBundleIO(workflowBundleIO);
+               WorkflowBundleSaver workflowBundleSaver = new 
WorkflowBundleSaver();
+               workflowBundleSaver.setWorkflowBundleIO(workflowBundleIO);
+               DataflowPersistenceHandlerRegistry 
dataflowPersistenceHandlerRegistry = new DataflowPersistenceHandlerRegistry();
+               
dataflowPersistenceHandlerRegistry.setDataflowPersistenceHandlers(Arrays.asList(
+                               new DataflowPersistenceHandler[] 
{t2DataflowOpener, workflowBundleOpener, workflowBundleSaver}));
+               dataflowPersistenceHandlerRegistry.updateColletions();
+               
fileManager.setDataflowPersistenceHandlerRegistry(dataflowPersistenceHandlerRegistry);
+       }
+
+       @Test
+       public void open() throws Exception {
+               assertTrue("ModelMapObserver already contained messages",
+                               fileManagerObserver.messages.isEmpty());
+               WorkflowBundle dataflow = openDataflow();
+               assertNotNull("Dataflow was not loaded", dataflow);
+               assertEquals("Loaded dataflow was not set as current dataflow",
+                               dataflow, fileManager.getCurrentDataflow());
+               assertFalse("ModelMapObserver did not contain message",
+                               fileManagerObserver.messages.isEmpty());
+               assertEquals("ModelMapObserver contained unexpected messages", 
2,
+                               fileManagerObserver.messages.size());
+               FileManagerEvent event = fileManagerObserver.messages.get(0);
+               assertTrue(event instanceof SetCurrentDataflowEvent);
+               assertEquals(dataflow, ((SetCurrentDataflowEvent) 
event).getDataflow());
+       }
+
+       @Test
+       public void openSilently() throws Exception {
+               assertTrue("ModelMapObserver already contained messages",
+                               fileManagerObserver.messages.isEmpty());
+               URL url = getClass().getResource(DUMMY_WORKFLOW_T2FLOW);
+               DataflowInfo info = 
fileManager.openDataflowSilently(T2_FLOW_FILE_TYPE, url);
+
+               WorkflowBundle dataflow = info.getDataflow();
+               assertNotNull("Dataflow was not loaded", dataflow);
+
+               assertNotSame("Loaded dataflow was set as current dataflow",
+                               dataflow, fileManager.getCurrentDataflow());
+               assertTrue("ModelMapObserver contained unexpected messages",
+                               fileManagerObserver.messages.isEmpty());
+       }
+
+       @Test
+       public void canSaveDataflow() throws Exception {
+               WorkflowBundle savedDataflow = openDataflow();
+               File dataflowFile = File.createTempFile("test", ".t2flow");
+               dataflowFile.deleteOnExit();
+               dataflowFile.delete();
+               fileManager.saveDataflow(savedDataflow, WF_BUNDLE_FILE_TYPE, 
dataflowFile, true);
+               
assertTrue(fileManager.canSaveWithoutDestination(savedDataflow));
+               fileManager.saveDataflow(savedDataflow, true);
+               fileManager.closeDataflow(savedDataflow, true);
+
+               WorkflowBundle otherFlow = 
fileManager.openDataflow(WF_BUNDLE_FILE_TYPE, dataflowFile.toURI()
+                               .toURL());
+               assertTrue(fileManager.canSaveWithoutDestination(otherFlow));
+       }
+
+       @Test
+       public void save() throws Exception {
+               WorkflowBundle savedDataflow = openDataflow();
+               File dataflowFile = File.createTempFile("test", ".t2flow");
+               dataflowFile.deleteOnExit();
+               dataflowFile.delete();
+               assertFalse("File should not exist", dataflowFile.isFile());
+               fileManager.saveDataflow(savedDataflow, WF_BUNDLE_FILE_TYPE, 
dataflowFile, false);
+               assertTrue("File should exist", dataflowFile.isFile());
+               WorkflowBundle loadedDataflow = 
fileManager.openDataflow(WF_BUNDLE_FILE_TYPE, dataflowFile.toURI()
+                               .toURL());
+               assertNotSame("Dataflow was not reopened", savedDataflow,
+                               loadedDataflow);
+               assertEquals("Unexpected number of processors in saved 
dataflow", 1,
+                               
savedDataflow.getMainWorkflow().getProcessors().size());
+               assertEquals("Unexpected number of processors in loaded 
dataflow", 1,
+                               
loadedDataflow.getMainWorkflow().getProcessors().size());
+
+               Processor savedProcessor = 
savedDataflow.getMainWorkflow().getProcessors().first();
+               Processor loadedProcessor = 
loadedDataflow.getMainWorkflow().getProcessors().first();
+               assertEquals("Loaded processor had wrong name", savedProcessor
+                               .getName(), loadedProcessor.getName());
+
+               // TODO convert to scufl2
+//             BeanshellActivity savedActivity = (BeanshellActivity) 
savedProcessor
+//                             .getActivityList().get(0);
+//             BeanshellActivity loadedActivity = (BeanshellActivity) 
loadedProcessor
+//                             .getActivityList().get(0);
+//             String savedScript = 
savedActivity.getConfiguration().getScript();
+//             String loadedScript = 
loadedActivity.getConfiguration().getScript();
+//             assertEquals("Unexpected saved script",
+//                             "String output = input + \"XXX\";", 
savedScript);
+//             assertEquals("Loaded script did not matched saved script", 
savedScript,
+//                             loadedScript);
+       }
+
+       @Test
+       public void saveSilent() throws Exception {
+               assertTrue("ModelMapObserver contained unexpected messages",
+                               fileManagerObserver.messages.isEmpty());
+
+               URL url = getClass().getResource(DUMMY_WORKFLOW_T2FLOW);
+               DataflowInfo info = 
fileManager.openDataflowSilently(T2_FLOW_FILE_TYPE, url);
+               WorkflowBundle dataflow = info.getDataflow();
+               assertTrue("ModelMapObserver contained unexpected messages",
+                               fileManagerObserver.messages.isEmpty());
+
+               File dataflowFile = File.createTempFile("test", ".t2flow");
+               dataflowFile.deleteOnExit();
+               dataflowFile.delete();
+               assertFalse("File should not exist", dataflowFile.isFile());
+
+               fileManager.saveDataflowSilently(dataflow, WF_BUNDLE_FILE_TYPE, 
dataflowFile, false);
+               assertTrue("File should exist", dataflowFile.isFile());
+
+               assertTrue("ModelMapObserver contained unexpected messages",
+                               fileManagerObserver.messages.isEmpty());
+
+       }
+
+       @Test
+       public void saveOverwriteAgain() throws Exception {
+               WorkflowBundle dataflow = openDataflow();
+               File dataflowFile = File.createTempFile("test", ".t2flow");
+               dataflowFile.delete();
+               dataflowFile.deleteOnExit();
+               // File did NOT exist, should not fail
+               fileManager.saveDataflow(dataflow, WF_BUNDLE_FILE_TYPE, 
dataflowFile, true);
+
+               Processor processor = 
dataflow.getMainWorkflow().getProcessors().first();
+               Edit<Processor> renameEdit = new 
RenameEdit<Processor>(processor,
+                               processor.getName() + "-changed");
+               editManager.doDataflowEdit(dataflow, renameEdit);
+
+               // Last save was OURs, so should *not* fail - even if we now use
+               // the specific saveDataflow() method
+               fileManager.saveDataflow(dataflow, WF_BUNDLE_FILE_TYPE, 
dataflowFile, true);
+
+               //Thread.sleep(1500);
+               WorkflowBundle otherFlow = openDataflow();
+               // Saving another flow to same file should still fail
+               try {
+                       fileManager.saveDataflow(otherFlow,WF_BUNDLE_FILE_TYPE, 
dataflowFile, true);
+                       fail("Should have thrown OverwriteException");
+               } catch (OverwriteException ex) {
+                       // Expected
+               }
+       }
+
+       @Test(expected = OverwriteException.class)
+       public void saveOverwriteWarningFails() throws Exception {
+               WorkflowBundle dataflow = openDataflow();
+               File dataflowFile = File.createTempFile("test", ".t2flow");
+               dataflowFile.deleteOnExit();
+               // Should fail as file already exists
+               fileManager.saveDataflow(dataflow, WF_BUNDLE_FILE_TYPE, 
dataflowFile, true);
+       }
+
+       @Test
+       public void saveOverwriteWarningWorks() throws Exception {
+               WorkflowBundle dataflow = openDataflow();
+               File dataflowFile = File.createTempFile("test", ".t2flow");
+               dataflowFile.delete();
+               dataflowFile.deleteOnExit();
+               // File did NOT exist, should not fail
+               fileManager.saveDataflow(dataflow, WF_BUNDLE_FILE_TYPE, 
dataflowFile, true);
+       }
+
+       @After
+       public void stopListeningToModelMap() {
+               fileManager.removeObserver(fileManagerObserver);
+       }
+
+       protected WorkflowBundle openDataflow() throws OpenException {
+               URL url = getClass().getResource(DUMMY_WORKFLOW_T2FLOW);
+               assertNotNull(url);
+               WorkflowBundle dataflow = 
fileManager.openDataflow(T2_FLOW_FILE_TYPE, url);
+               assertNotNull(dataflow);
+               return dataflow;
+       }
+
+       private final class FileManagerObserver implements 
Observer<FileManagerEvent> {
+               protected List<FileManagerEvent> messages = new 
ArrayList<FileManagerEvent>();
+
+               @Override
+               public void notify(Observable<FileManagerEvent> sender, 
FileManagerEvent message) throws Exception {
+                       messages.add(message);
+                       if (message instanceof SetCurrentDataflowEvent) {
+                               assertTrue("Dataflow was not listed as open 
when set current",
+                                               
fileManager.getOpenDataflows().contains(
+                                                               
((SetCurrentDataflowEvent) message).getDataflow()));
+                       }
+               }
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-file-impl/src/test/resources/net/sf/taverna/t2/workbench/file/impl/dummy-workflow.t2flow
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-file-impl/src/test/resources/net/sf/taverna/t2/workbench/file/impl/dummy-workflow.t2flow
 
b/taverna-workbench-file-impl/src/test/resources/net/sf/taverna/t2/workbench/file/impl/dummy-workflow.t2flow
new file mode 100644
index 0000000..b9a1075
--- /dev/null
+++ 
b/taverna-workbench-file-impl/src/test/resources/net/sf/taverna/t2/workbench/file/impl/dummy-workflow.t2flow
@@ -0,0 +1,157 @@
+<workflow xmlns="http://taverna.sf.net/2008/xml/t2flow"; version="1" 
producedBy="test">
+       <dataflow id="ec0991ba-275c-49ed-b1d6-38534180fb7c" role="top">
+               <name>simple_workflow_with_input</name>
+               <inputPorts>
+                       <port>
+                               <name>input</name>
+                               <depth>0</depth>
+                               <granularDepth>0</granularDepth>
+                       </port>
+               </inputPorts>
+               <outputPorts>
+                       <port>
+                               <name>output</name>
+                       </port>
+               </outputPorts>
+               <processors>
+                       <processor>
+                               <name>Concat_XXX</name>
+                               <inputPorts>
+                                       <port>
+                                               <name>input</name>
+                                               <depth>0</depth>
+                                       </port>
+                               </inputPorts>
+                               <outputPorts>
+                                       <port>
+                                               <name>output</name>
+                                               <depth>0</depth>
+                                               <granularDepth>0</granularDepth>
+                                       </port>
+                               </outputPorts>
+                               <annotations />
+                               <activities>
+                                       <activity>
+                                               <class>
+                                                       
net.sf.taverna.t2.activities.beanshell.BeanshellActivity
+                                               </class>
+                                               <inputMap>
+                                                       <map from="input" 
to="input" />
+                                               </inputMap>
+                                               <outputMap>
+                                                       <map from="output" 
to="output" />
+                                               </outputMap>
+                                               <configBean encoding="xstream">
+                                                       
<net.sf.taverna.t2.activities.beanshell.BeanshellActivityConfigurationBean
+                                                               xmlns="">
+                                                               <script>String 
output = input + "XXX";</script>
+                                                               <dependencies />
+                                                               <inputs>
+                                                                       
<net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+                                                                               
<handledReferenceSchemes />
+                                                                               
<translatedElementType>java.lang.String</translatedElementType>
+                                                                               
<allowsLiteralValues>true</allowsLiteralValues>
+                                                                               
<name>input</name>
+                                                                               
<depth>0</depth>
+                                                                               
<mimeTypes>
+                                                                               
        <string>'text/plain'</string>
+                                                                               
</mimeTypes>
+                                                                       
</net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+                                                               </inputs>
+                                                               <outputs>
+                                                                       
<net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+                                                                               
<granularDepth>0</granularDepth>
+                                                                               
<name>output</name>
+                                                                               
<depth>0</depth>
+                                                                               
<mimeTypes>
+                                                                               
        <string>'text/plain'</string>
+                                                                               
</mimeTypes>
+                                                                       
</net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+                                                               </outputs>
+                                                       
</net.sf.taverna.t2.activities.beanshell.BeanshellActivityConfigurationBean>
+                                               </configBean>
+                                       </activity>
+                               </activities>
+                               <dispatchStack>
+                                       <dispatchLayer>
+                                               <class>
+                                                       
net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Parallelize
+                                               </class>
+                                               <configBean encoding="xstream">
+                                                       
<net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ParallelizeConfig
+                                                               xmlns="">
+                                                               
<maxJobs>1</maxJobs>
+                                                       
</net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ParallelizeConfig>
+                                               </configBean>
+                                       </dispatchLayer>
+                                       <dispatchLayer>
+                                               <class>
+                                                       
net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.ErrorBounce
+                                               </class>
+                                               <configBean encoding="xstream">
+                                                       <null xmlns="" />
+                                               </configBean>
+                                       </dispatchLayer>
+                                       <dispatchLayer>
+                                               <class>
+                                                       
net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Failover
+                                               </class>
+                                               <configBean encoding="xstream">
+                                                       <null xmlns="" />
+                                               </configBean>
+                                       </dispatchLayer>
+                                       <dispatchLayer>
+                                               <class>
+                                                       
net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Retry
+                                               </class>
+                                               <configBean encoding="xstream">
+                                                       
<net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.RetryConfig
+                                                               xmlns="">
+                                                               
<backoffFactor>1.0</backoffFactor>
+                                                               
<initialDelay>0</initialDelay>
+                                                               
<maxDelay>0</maxDelay>
+                                                               
<maxRetries>0</maxRetries>
+                                                       
</net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.RetryConfig>
+                                               </configBean>
+                                       </dispatchLayer>
+                                       <dispatchLayer>
+                                               <class>
+                                                       
net.sf.taverna.t2.workflowmodel.processor.dispatch.layers.Invoke
+                                               </class>
+                                               <configBean encoding="xstream">
+                                                       <null xmlns="" />
+                                               </configBean>
+                                       </dispatchLayer>
+                               </dispatchStack>
+                               <iterationStrategyStack>
+                                       <iteration>
+                                               <strategy>
+                                                       <port name="input" 
depth="0" />
+                                               </strategy>
+                                       </iteration>
+                               </iterationStrategyStack>
+                       </processor>
+               </processors>
+               <conditions />
+               <datalinks>
+                       <datalink>
+                               <sink type="processor">
+                                       <processor>Concat_XXX</processor>
+                                       <port>input</port>
+                               </sink>
+                               <source type="dataflow">
+                                       <port>input</port>
+                               </source>
+                       </datalink>
+                       <datalink>
+                               <sink type="dataflow">
+                                       <port>output</port>
+                               </sink>
+                               <source type="processor">
+                                       <processor>Concat_XXX</processor>
+                                       <port>output</port>
+                               </source>
+                       </datalink>
+               </datalinks>
+       </dataflow>
+</workflow>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-helper/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-helper/pom.xml b/taverna-workbench-helper/pom.xml
new file mode 100644
index 0000000..70c0621
--- /dev/null
+++ b/taverna-workbench-helper/pom.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>net.sf.taverna.t2</groupId>
+               <artifactId>ui-impl</artifactId>
+               <version>2.0-SNAPSHOT</version>
+       </parent>
+       <groupId>net.sf.taverna.t2.ui-impl</groupId>
+       <artifactId>helper</artifactId>
+       <name>Help System (legacy dependency)</name>
+       <dependencies>
+               <dependency>
+            <groupId>net.sf.taverna.t2.ui-api</groupId>
+            <artifactId>helper-api</artifactId>
+            <version>${t2.ui.api.version}</version>
+               </dependency>
+       </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-httpproxy-config/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-httpproxy-config/pom.xml 
b/taverna-workbench-httpproxy-config/pom.xml
new file mode 100644
index 0000000..f1a8328
--- /dev/null
+++ b/taverna-workbench-httpproxy-config/pom.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>net.sf.taverna.t2</groupId>
+               <artifactId>ui-impl</artifactId>
+               <version>2.0-SNAPSHOT</version>
+       </parent>
+       <groupId>net.sf.taverna.t2.ui-impl</groupId>
+       <artifactId>httpproxy-config</artifactId>
+       <packaging>bundle</packaging>
+       <name>HTTP Proxy configuration</name>
+       <dependencies>
+               <dependency>
+                       <groupId>net.sf.taverna.t2.lang</groupId>
+                       <artifactId>ui</artifactId>
+                       <version>${t2.lang.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>uk.org.taverna.configuration</groupId>
+                       <artifactId>taverna-configuration-api</artifactId>
+                       <version>${taverna.configuration.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>net.sf.taverna.t2.ui-api</groupId>
+                       <artifactId>helper-api</artifactId>
+                       <version>${t2.ui.api.version}</version>
+               </dependency>
+       </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-httpproxy-config/src/main/java/net/sf/taverna/t2/workbench/httpproxy/config/HttpProxyConfigurationPanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-workbench-httpproxy-config/src/main/java/net/sf/taverna/t2/workbench/httpproxy/config/HttpProxyConfigurationPanel.java
 
b/taverna-workbench-httpproxy-config/src/main/java/net/sf/taverna/t2/workbench/httpproxy/config/HttpProxyConfigurationPanel.java
new file mode 100644
index 0000000..1229d57
--- /dev/null
+++ 
b/taverna-workbench-httpproxy-config/src/main/java/net/sf/taverna/t2/workbench/httpproxy/config/HttpProxyConfigurationPanel.java
@@ -0,0 +1,582 @@
+/*******************************************************************************
+ * 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.httpproxy.config;
+
+import static java.awt.GridBagConstraints.BOTH;
+import static java.awt.GridBagConstraints.CENTER;
+import static java.awt.GridBagConstraints.HORIZONTAL;
+import static java.awt.GridBagConstraints.NONE;
+import static java.awt.GridBagConstraints.WEST;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED;
+import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED;
+import static net.sf.taverna.t2.workbench.helper.Helper.showHelp;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.PROXY_USE_OPTION;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.SYSTEM_NON_PROXY_HOSTS;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.SYSTEM_PROXY_HOST;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.SYSTEM_PROXY_PASSWORD;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.SYSTEM_PROXY_PORT;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.SYSTEM_PROXY_USER;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.TAVERNA_NON_PROXY_HOSTS;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.TAVERNA_PROXY_HOST;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.TAVERNA_PROXY_PASSWORD;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.TAVERNA_PROXY_PORT;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.TAVERNA_PROXY_USER;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.USE_NO_PROXY_OPTION;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.USE_SPECIFIED_VALUES_OPTION;
+import static 
uk.org.taverna.configuration.proxy.HttpProxyConfiguration.USE_SYSTEM_PROPERTIES_OPTION;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.AbstractAction;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+
+import net.sf.taverna.t2.lang.ui.DialogTextArea;
+import uk.org.taverna.configuration.proxy.HttpProxyConfiguration;
+
+/**
+ * The HttpProxyConfigurationPanel provides the user interface to a
+ * {@link HttpProxyConfiguration} to determine how HTTP Connections are made by
+ * Taverna.
+ * 
+ * @author alanrw
+ * @author David Withers
+ */
+public class HttpProxyConfigurationPanel extends JPanel {
+       static final long serialVersionUID = 3668473431971125038L;
+       /**
+        * The size of the field for the JTextFields.
+        */
+       private static int TEXTFIELD_SIZE = 25;
+
+       private final HttpProxyConfiguration httpProxyConfiguration;
+       /**
+        * RadioButtons that are in a common ButtonGroup. Selecting one of them
+        * indicates whether the system http proxy settings, the ad hoc 
specified
+        * values or no proxy settings at all should be used.
+        */
+       private JRadioButton useSystemProperties;
+       private JRadioButton useSpecifiedValues;
+       private JRadioButton useNoProxy;
+       /**
+        * JTextFields and one DialogTextArea to hold the settings for the HTTP
+        * proxy properties. The values are only editable if the user picks
+        * useSpecifiedValues.
+        */
+       private JTextField proxyHostField;
+       private JTextField proxyPortField;
+       private JTextField proxyUserField;
+       private JTextField proxyPasswordField;
+       private DialogTextArea nonProxyHostsArea;
+       private JScrollPane nonProxyScrollPane;
+       /**
+        * A string that indicates which HTTP setting option the user has 
currently
+        * picked. This does not necesarily match that which has been applied.
+        */
+       private String shownOption = USE_SYSTEM_PROPERTIES_OPTION;
+
+       /**
+        * The HttpProxyConfigurationPanel consists of a set of properties 
where the
+        * configuration values for HTTP can be specified and a set of buttons 
where
+        * the more general apply, help etc. appear.
+        */
+       public HttpProxyConfigurationPanel(
+                       HttpProxyConfiguration httpProxyConfiguration) {
+               this.httpProxyConfiguration = httpProxyConfiguration;
+               initComponents();
+       }
+
+       /**
+        * Populates the panel with a representation of the current HTTP proxy
+        * settings for the specified {@link HttpProxyConfiguration} and also 
the
+        * capability to alter them.
+        */
+       private void initComponents() {
+               shownOption = 
httpProxyConfiguration.getProperty(PROXY_USE_OPTION);
+
+               this.setLayout(new GridBagLayout());
+
+               GridBagConstraints gbc = new GridBagConstraints();
+
+               // Title describing what kind of settings we are configuring 
here
+               JTextArea descriptionText = new JTextArea("HTTP proxy 
configuration");
+               descriptionText.setLineWrap(true);
+               descriptionText.setWrapStyleWord(true);
+               descriptionText.setEditable(false);
+               descriptionText.setFocusable(false);
+               descriptionText.setBorder(new EmptyBorder(10, 10, 10, 10));
+               gbc.anchor = WEST;
+               gbc.gridx = 0;
+               gbc.gridy = 0;
+               gbc.gridwidth = 2;
+               gbc.weightx = 1.0;
+               gbc.weighty = 0.0;
+               gbc.fill = HORIZONTAL;
+               this.add(descriptionText, gbc);
+
+               /**
+                * Generate the three radio buttons and put them in a group. 
Each button
+                * is bound to an action that alters the shownOption and 
re-populates
+                * the shown HTTP property fields.
+                */
+               useNoProxy = new JRadioButton("Do not use a proxy");
+               useNoProxy.setAlignmentX(LEFT_ALIGNMENT);
+               gbc.gridx = 0;
+               gbc.gridy = 1;
+               gbc.gridwidth = 2;
+               gbc.weightx = 0.0;
+               gbc.weighty = 0.0;
+               gbc.fill = NONE;
+               gbc.insets = new Insets(10, 0, 0, 0);
+               this.add(useNoProxy, gbc);
+               ActionListener useNoProxyListener = new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               shownOption = USE_NO_PROXY_OPTION;
+                               populateFields();
+                       }
+               };
+               useNoProxy.addActionListener(useNoProxyListener);
+
+               useSystemProperties = new JRadioButton("Use system properties");
+               useSystemProperties.setAlignmentX(LEFT_ALIGNMENT);
+               gbc.gridx = 0;
+               gbc.gridy = 2;
+               gbc.insets = new Insets(0, 0, 0, 0);
+               this.add(useSystemProperties, gbc);
+               ActionListener systemPropertiesListener = new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               shownOption = USE_SYSTEM_PROPERTIES_OPTION;
+                               populateFields();
+                       }
+               };
+               useSystemProperties.addActionListener(systemPropertiesListener);
+
+               useSpecifiedValues = new JRadioButton("Use specified values");
+               useSpecifiedValues.setAlignmentX(LEFT_ALIGNMENT);
+               gbc.gridx = 0;
+               gbc.gridy = 3;
+               this.add(useSpecifiedValues, gbc);
+               ActionListener specifiedValuesListener = new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               shownOption = USE_SPECIFIED_VALUES_OPTION;
+                               populateFields();
+                       }
+               };
+               useSpecifiedValues.addActionListener(specifiedValuesListener);
+
+               ButtonGroup bg = new ButtonGroup();
+               bg.add(useSystemProperties);
+               bg.add(useSpecifiedValues);
+               bg.add(useNoProxy);
+
+               /**
+                * Create the fields to show the HTTP proxy property values. 
These
+                * become editable if the shown option is to use specified 
values.
+                */
+               proxyHostField = new JTextField(TEXTFIELD_SIZE);
+               gbc.gridx = 0;
+               gbc.gridy = 4;
+               gbc.gridwidth = 1;
+               gbc.fill = NONE;
+               gbc.insets = new Insets(10, 0, 0, 0);
+               this.add(new JLabel("Proxy host"), gbc);
+               gbc.gridx = 1;
+               gbc.gridy = 4;
+               gbc.gridwidth = 1;
+               gbc.fill = HORIZONTAL;
+               this.add(proxyHostField, gbc);
+
+               proxyPortField = new JTextField(TEXTFIELD_SIZE);
+               gbc.gridx = 0;
+               gbc.gridy = 5;
+               gbc.gridwidth = 1;
+               gbc.fill = NONE;
+               gbc.insets = new Insets(0, 0, 0, 0);
+               this.add(new JLabel("Proxy port"), gbc);
+               gbc.gridx = 1;
+               gbc.gridy = 5;
+               gbc.gridwidth = 1;
+               gbc.fill = HORIZONTAL;
+               this.add(proxyPortField, gbc);
+
+               proxyUserField = new JTextField(TEXTFIELD_SIZE);
+               gbc.gridx = 0;
+               gbc.gridy = 6;
+               gbc.gridwidth = 1;
+               gbc.fill = NONE;
+               this.add(new JLabel("Proxy user"), gbc);
+               gbc.gridx = 1;
+               gbc.gridy = 6;
+               gbc.gridwidth = 1;
+               gbc.fill = HORIZONTAL;
+               this.add(proxyUserField, gbc);
+
+               proxyPasswordField = new JTextField(TEXTFIELD_SIZE);
+               gbc.gridx = 0;
+               gbc.gridy = 7;
+               gbc.gridwidth = 1;
+               gbc.fill = NONE;
+               this.add(new JLabel("Proxy password"), gbc);
+               gbc.gridx = 1;
+               gbc.gridy = 7;
+               gbc.gridwidth = 1;
+               gbc.fill = HORIZONTAL;
+               this.add(proxyPasswordField, gbc);
+
+               nonProxyHostsArea = new DialogTextArea(10, 40);
+               nonProxyScrollPane = new JScrollPane(nonProxyHostsArea);
+               nonProxyScrollPane
+                               
.setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_AS_NEEDED);
+               nonProxyScrollPane
+                               
.setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_AS_NEEDED);
+               // nonProxyScrollPane.setPreferredSize(new Dimension(300, 500));
+               gbc.gridx = 0;
+               gbc.gridy = 8;
+               gbc.gridwidth = 2;
+               gbc.fill = NONE;
+               gbc.insets = new Insets(10, 0, 0, 0);
+               this.add(new JLabel("Non-proxy hosts"), gbc);
+               gbc.gridx = 0;
+               gbc.gridy = 9;
+               gbc.weightx = 1.0;
+               gbc.weighty = 1.0;
+               gbc.gridwidth = 2;
+               gbc.insets = new Insets(0, 0, 0, 0);
+               gbc.fill = BOTH;
+               this.add(nonProxyScrollPane, gbc);
+
+               // Add buttons panel
+               gbc.gridx = 0;
+               gbc.gridy = 10;
+               gbc.weightx = 0.0;
+               gbc.weighty = 0.0;
+               gbc.gridwidth = 2;
+               gbc.fill = HORIZONTAL;
+               gbc.anchor = CENTER;
+               gbc.insets = new Insets(10, 0, 0, 0);
+               this.add(createButtonPanel(), gbc);
+
+               setFields();
+       }
+
+       /**
+        * Populate the fields in the property panel according to which option 
is
+        * being shown and the stored values within the
+        * {@link HttpProxyConfiguration}.
+        */
+       private void populateFields() {
+               /**
+                * Editing of the property fields is only available when the 
option is
+                * to use the specified values.
+                */
+               boolean editingEnabled = shownOption
+                               .equals(USE_SPECIFIED_VALUES_OPTION);
+
+               if (shownOption.equals(USE_SYSTEM_PROPERTIES_OPTION)) {
+                       proxyHostField.setText(httpProxyConfiguration
+                                       .getProperty(SYSTEM_PROXY_HOST));
+                       proxyPortField.setText(httpProxyConfiguration
+                                       .getProperty(SYSTEM_PROXY_PORT));
+                       proxyUserField.setText(httpProxyConfiguration
+                                       .getProperty(SYSTEM_PROXY_USER));
+                       proxyPasswordField.setText(httpProxyConfiguration
+                                       .getProperty(SYSTEM_PROXY_PASSWORD));
+                       nonProxyHostsArea.setText(httpProxyConfiguration
+                                       .getProperty(SYSTEM_NON_PROXY_HOSTS));
+               } else if (shownOption.equals(USE_SPECIFIED_VALUES_OPTION)) {
+                       proxyHostField.setText(httpProxyConfiguration
+                                       .getProperty(TAVERNA_PROXY_HOST));
+                       proxyPortField.setText(httpProxyConfiguration
+                                       .getProperty(TAVERNA_PROXY_PORT));
+                       proxyUserField.setText(httpProxyConfiguration
+                                       .getProperty(TAVERNA_PROXY_USER));
+                       proxyPasswordField.setText(httpProxyConfiguration
+                                       .getProperty(TAVERNA_PROXY_PASSWORD));
+                       nonProxyHostsArea.setText(httpProxyConfiguration
+                                       .getProperty(TAVERNA_NON_PROXY_HOSTS));
+               } else {
+                       proxyHostField.setText(null);
+                       proxyPortField.setText(null);
+                       proxyUserField.setText(null);
+                       proxyPasswordField.setText(null);
+                       nonProxyHostsArea.setText(null);
+               }
+
+               proxyHostField.setEnabled(editingEnabled);
+               proxyPortField.setEnabled(editingEnabled);
+               proxyUserField.setEnabled(editingEnabled);
+               proxyPasswordField.setEnabled(editingEnabled);
+               nonProxyHostsArea.setEnabled(editingEnabled);
+               nonProxyHostsArea.setEditable(editingEnabled);
+               nonProxyScrollPane.setEnabled(editingEnabled);
+       }
+
+       /**
+        * Create the panel to contain the buttons
+        * 
+        * @return
+        */
+       @SuppressWarnings("serial")
+       private JPanel createButtonPanel() {
+               final JPanel panel = new JPanel();
+
+               /**
+                * The helpButton shows help about the current component
+                */
+               JButton helpButton = new JButton(new AbstractAction("Help") {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               showHelp(panel);
+                       }
+               });
+               panel.add(helpButton);
+
+               /**
+                * The resetButton changes the property values shown to those
+                * corresponding to the configuration currently applied.
+                */
+               JButton resetButton = new JButton(new AbstractAction("Reset") {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               setFields();
+                       }
+               });
+               panel.add(resetButton);
+
+               /**
+                * The applyButton applies the shown field values to the
+                * {@link HttpProxyConfiguration} and saves them for future.
+                */
+               JButton applyButton = new JButton(new AbstractAction("Apply") {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               applySettings();
+                               setFields();
+                       }
+               });
+               panel.add(applyButton);
+
+               return panel;
+       }
+
+       /**
+        * Checks that the specified values for the HTTP properties are a valid
+        * combination and, if so, saves them for future use. It does not apply 
them
+        * to the currently executing Taverna.
+        */
+       private void saveSettings() {
+               if (useSystemProperties.isSelected()) {
+                       httpProxyConfiguration.setProperty(PROXY_USE_OPTION,
+                                       USE_SYSTEM_PROPERTIES_OPTION);
+               } else if (useNoProxy.isSelected()) {
+                       httpProxyConfiguration.setProperty(PROXY_USE_OPTION,
+                                       USE_NO_PROXY_OPTION);
+               } else {
+                       if (validateFields()) {
+                               
httpProxyConfiguration.setProperty(PROXY_USE_OPTION,
+                                               USE_SPECIFIED_VALUES_OPTION);
+                               
httpProxyConfiguration.setProperty(TAVERNA_PROXY_HOST,
+                                               proxyHostField.getText());
+                               
httpProxyConfiguration.setProperty(TAVERNA_PROXY_PORT,
+                                               proxyPortField.getText());
+                               
httpProxyConfiguration.setProperty(TAVERNA_PROXY_USER,
+                                               proxyUserField.getText());
+                               
httpProxyConfiguration.setProperty(TAVERNA_PROXY_PASSWORD,
+                                               proxyPasswordField.getText());
+                               
httpProxyConfiguration.setProperty(TAVERNA_NON_PROXY_HOSTS,
+                                               nonProxyHostsArea.getText());
+                       }
+               }
+       }
+
+       /**
+        * Validates and, where appropriate formats, the properties values 
specified
+        * for HTTP Proxy configuration.
+        * 
+        * @return
+        */
+       private boolean validateFields() {
+               boolean result = true;
+               result = result && validateHostField();
+               result = result && validatePortField();
+               result = result && validateUserField();
+               result = result && validatePasswordField();
+               result = result && validateNonProxyHostsArea();
+               return result;
+       }
+
+       /**
+        * Checks that, if a value is specified for non-proxy hosts then a proxy
+        * host has also been specified. Formats the non-proxy hosts string so 
that
+        * if the user has entered the hosts on separate lines, then the stored
+        * values are separated by bars.
+        * 
+        * @return
+        */
+       private boolean validateNonProxyHostsArea() {
+               boolean result = true;
+               String value = nonProxyHostsArea.getText();
+               if ((value != null) && (!value.equals(""))) {
+                       value = value.replaceAll("\\n", "|");
+                       nonProxyHostsArea.setText(value);
+                       result = result
+                                       && dependsUpon("non-proxy host", "host",
+                                                       
proxyHostField.getText());
+               }
+               return result;
+       }
+
+       /**
+        * Checks that, if a password has been specified, then a user has also 
been
+        * specified.
+        * 
+        * @return
+        */
+       private boolean validatePasswordField() {
+               boolean result = true;
+               String value = proxyPasswordField.getText();
+               if ((value != null) && !value.isEmpty())
+                       result = result
+                                       && dependsUpon("password", "user", 
proxyHostField.getText());
+               return result;
+       }
+
+       /**
+        * Checks that if a user has been specified, then a host has also been
+        * specified.
+        * 
+        * @return
+        */
+       private boolean validateUserField() {
+               boolean result = true;
+               String value = proxyUserField.getText();
+               if ((value != null) && !value.isEmpty())
+                       result = result
+                                       && dependsUpon("user", "host", 
proxyHostField.getText());
+               return result;
+       }
+
+       /**
+        * Checks that if a port has been specified then a host has also been
+        * specified. Checks that the port number is a non-negative integer. If 
the
+        * port has not been specified, then if a host has been specified, the
+        * default value 80 is used.
+        * 
+        * @return
+        */
+       private boolean validatePortField() {
+               boolean result = true;
+               String value = proxyPortField.getText();
+               if ((value != null) && (!value.equals(""))) {
+                       result = result
+                                       && dependsUpon("port", "host", 
proxyHostField.getText());
+                       try {
+                               int parsedNumber = Integer.parseInt(value);
+                               if (parsedNumber <= 0) {
+                                       showMessageDialog(this, "The port must 
be non-negative");
+                                       result = false;
+                               }
+                       } catch (NumberFormatException e) {
+                               showMessageDialog(this, "The port must be an 
integer");
+                               result = false;
+                       }
+               } else {
+                       String hostField = proxyHostField.getText();
+                       if ((hostField != null) && !hostField.isEmpty())
+                               proxyPortField.setText("80");
+               }
+               return result;
+       }
+
+       /**
+        * Checks if the targetValue has been specified. If not then a message 
is
+        * displayed indicating that the dependent cannot be specified with the
+        * target.
+        * 
+        * @param dependent
+        * @param target
+        * @param targetValue
+        * @return
+        */
+       private boolean dependsUpon(String dependent, String target,
+                       String targetValue) {
+               boolean result = true;
+               if ((targetValue == null) || target.equals("")) {
+                       showMessageDialog(this, "A " + dependent
+                                       + " cannot be specified without a " + 
target);
+                       result = false;
+               }
+               return result;
+       }
+
+       /**
+        * Could validate the host field e.g. by establishing a connection.
+        * Currently no validation is done.
+        * 
+        * @return
+        */
+       private boolean validateHostField() {
+               boolean result = true;
+               // String value = proxyHostField.getText();
+               return result;
+       }
+
+       /**
+        * Save the currently set field values (if valid) to the
+        * {@link HttpProxyConfiguration}. Also applies those values to the
+        * currently running Taverna.
+        */
+       private void applySettings() {
+               if (validateFields()) {
+                       saveSettings();
+                       httpProxyConfiguration.changeProxySettings();
+               }
+       }
+
+       /**
+        * Set the shown field values to those currently in use (i.e. last saved
+        * configuration).
+        */
+       private void setFields() {
+               shownOption = 
httpProxyConfiguration.getProperty(PROXY_USE_OPTION);
+               useSystemProperties.setSelected(shownOption
+                               .equals(USE_SYSTEM_PROPERTIES_OPTION));
+               useSpecifiedValues.setSelected(shownOption
+                               .equals(USE_SPECIFIED_VALUES_OPTION));
+               useNoProxy.setSelected(shownOption.equals(USE_NO_PROXY_OPTION));
+               populateFields();
+       }
+}

Reply via email to