http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ListConfigurationComponent.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ListConfigurationComponent.java
 
b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ListConfigurationComponent.java
deleted file mode 100644
index c0e3aab..0000000
--- 
a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ListConfigurationComponent.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2012 The University of Manchester
- *
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- 
******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.views.contextualviews.activity;
-
-import static java.awt.BorderLayout.CENTER;
-import static java.awt.BorderLayout.EAST;
-import static java.awt.BorderLayout.SOUTH;
-import static java.awt.FlowLayout.RIGHT;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.FlowLayout;
-import java.awt.event.ActionEvent;
-import java.util.List;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.JButton;
-import javax.swing.JComponent;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-
-/**
- * @author David Withers
- */
-@SuppressWarnings("serial")
-public abstract class ListConfigurationComponent<T> extends JPanel {
-       private static final String REMOVE = "Remove";
-       private static final String ADD = "Add";
-
-       private String name;
-       private List<T> items;
-       private JPanel listPanel;
-
-       public ListConfigurationComponent(String name, List<T> items) {
-               this.name = name;
-               setLayout(new BorderLayout());
-
-               listPanel = new JPanel(new ListLayout());
-               JPanel buttonPanel = new JPanel(new FlowLayout(RIGHT));
-               buttonPanel.add(new JButton(createAddAction()));
-
-               add(new JScrollPane(listPanel), CENTER);
-               add(buttonPanel, SOUTH);
-
-               setItems(items);
-       }
-
-       protected void setItems(List<T> items) {
-               this.items = items;
-               listPanel.removeAll();
-               for (T item : items)
-                       addItemComponent(item);
-       }
-
-       protected void addItem(T item) {
-               items.add(item);
-               addItemComponent(item);
-       }
-
-       protected void addItemComponent(T item) {
-               JComponent itemPanel = new JPanel(new BorderLayout());
-               itemPanel.add(createItemComponent(item), CENTER);
-               itemPanel.add(new JButton(createRemoveAction(item)), EAST);
-               listPanel.add(itemPanel);
-               listPanel.revalidate();
-               listPanel.repaint();
-       }
-
-       protected void removeItem(T item) {
-               int index = items.indexOf(item);
-               if (index >= 0) {
-                       items.remove(index);
-                       listPanel.remove(index);
-                       listPanel.revalidate();
-                       listPanel.repaint();
-               }
-       }
-
-       private Action createRemoveAction(final T item) {
-               return new AbstractAction(REMOVE) {
-                       @Override
-                       public void actionPerformed(ActionEvent e) {
-                               removeItem(item);
-                       }
-               };
-       }
-
-       private Action createAddAction() {
-               return new AbstractAction(ADD + " " + name) {
-                       @Override
-                       public void actionPerformed(ActionEvent e) {
-                               addItem(createDefaultItem());
-                       }
-               };
-       }
-
-       protected abstract Component createItemComponent(T item);
-
-       protected abstract T createDefaultItem();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ListLayout.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ListLayout.java
 
b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ListLayout.java
deleted file mode 100644
index 0ce35b5..0000000
--- 
a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ListLayout.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2012 The University of Manchester
- *
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- 
******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.views.contextualviews.activity;
-
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.Dimension;
-import java.awt.Insets;
-import java.awt.LayoutManager;
-
-/**
- * Lays out components vertically using their preferred height and the 
available
- * width.
- * 
- * @author David Withers
- */
-public class ListLayout implements LayoutManager {
-       private static final int DEFAULT_GAP = 5;
-       private final int gap;
-
-       public ListLayout() {
-               this(DEFAULT_GAP);
-       }
-
-       public ListLayout(int gap) {
-               this.gap = gap;
-       }
-
-       @Override
-       public void removeLayoutComponent(Component comp) {
-       }
-
-       @Override
-       public void addLayoutComponent(String name, Component comp) {
-       }
-
-       @Override
-       public void layoutContainer(Container parent) {
-               Insets insets = parent.getInsets();
-               int x = insets.left;
-               int y = insets.top;
-               int width = parent.getWidth() - insets.left - insets.right;
-               Component[] components = parent.getComponents();
-               for (int i = 0; i < components.length; i++) {
-                       components[i].setLocation(x, y);
-                       components[i].setSize(width,
-                                       
components[i].getPreferredSize().height);
-                       y = y + gap + components[i].getHeight();
-               }
-       }
-
-       @Override
-       public Dimension minimumLayoutSize(Container parent) {
-               Insets insets = parent.getInsets();
-               int minimumWidth = 0;
-               int minimumHeight = 0;
-               Component[] components = parent.getComponents();
-               for (int i = 0; i < components.length; i++) {
-                       Dimension size = components[i].getPreferredSize();
-                       if (size.width > minimumWidth)
-                               minimumWidth = size.width;
-                       minimumHeight = minimumHeight + size.height + gap;
-               }
-               minimumWidth = minimumWidth + insets.left + insets.right;
-               minimumHeight = minimumHeight + insets.top + insets.bottom;
-
-               return new Dimension(minimumWidth, minimumHeight);
-       }
-
-       @Override
-       public Dimension preferredLayoutSize(Container parent) {
-               return minimumLayoutSize(parent);
-       }
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/MultiPageActivityConfigurationPanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/MultiPageActivityConfigurationPanel.java
 
b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/MultiPageActivityConfigurationPanel.java
deleted file mode 100644
index c6862ff..0000000
--- 
a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/MultiPageActivityConfigurationPanel.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2012 The University of Manchester
- *
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- 
******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.views.contextualviews.activity;
-
-import static java.awt.BorderLayout.CENTER;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-
-import javax.swing.JTabbedPane;
-
-import org.apache.taverna.scufl2.api.activity.Activity;
-
-/**
- * Component for configuring activities that have multiple configuration pages.
- * 
- * @author David Withers
- */
-@SuppressWarnings("serial")
-public abstract class MultiPageActivityConfigurationPanel extends
-               ActivityConfigurationPanel {
-       private JTabbedPane tabbedPane;
-
-       /**
-        * Constructs a new <code>MultiPageActivityConfigurationPanel</code>.
-        * 
-        * @param activity
-        */
-       public MultiPageActivityConfigurationPanel(Activity activity) {
-               super(activity);
-               setLayout(new BorderLayout());
-               tabbedPane = new JTabbedPane();
-               add(tabbedPane, CENTER);
-       }
-
-       public void addPage(String name, Component component) {
-               tabbedPane.addTab(name, component);
-       }
-
-       public void removePage(String name) {
-               tabbedPane.removeTabAt(tabbedPane.indexOfTab(name));
-       }
-
-       public void removeAllPages() {
-               tabbedPane.removeAll();
-       }
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ScriptConfigurationComponent.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ScriptConfigurationComponent.java
 
b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ScriptConfigurationComponent.java
deleted file mode 100644
index 8cb7652..0000000
--- 
a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ScriptConfigurationComponent.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2012 The University of Manchester
- *
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- 
******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.views.contextualviews.activity;
-
-import static java.awt.BorderLayout.CENTER;
-import static java.awt.BorderLayout.SOUTH;
-import static java.awt.Color.WHITE;
-import static java.awt.Font.PLAIN;
-import static javax.swing.JOptionPane.INFORMATION_MESSAGE;
-import static javax.swing.JOptionPane.YES_NO_OPTION;
-import static javax.swing.JOptionPane.YES_OPTION;
-import static javax.swing.JOptionPane.showConfirmDialog;
-import static javax.swing.JOptionPane.showMessageDialog;
-import static net.sf.taverna.t2.lang.ui.FileTools.readStringFromFile;
-import static net.sf.taverna.t2.lang.ui.FileTools.saveStringToFile;
-
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.Font;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.Set;
-
-import javax.swing.JButton;
-import javax.swing.JPanel;
-import javax.swing.JTextPane;
-
-import net.sf.taverna.t2.lang.ui.KeywordDocument;
-import net.sf.taverna.t2.lang.ui.LineEnabledTextPanel;
-import net.sf.taverna.t2.lang.ui.LinePainter;
-import net.sf.taverna.t2.lang.ui.NoWrapEditorKit;
-
-/**
- * Component for configuring activities that have scripts.
- *
- * @author David Withers
- */
-@SuppressWarnings("serial")
-public class ScriptConfigurationComponent extends JPanel {
-       private JTextPane scriptTextArea;
-
-       public ScriptConfigurationComponent(String script, Set<String> keywords,
-                       Set<String> ports, final String scriptType,
-                       final String fileExtension) {
-               this(script, keywords, ports, scriptType, fileExtension, "");
-       }
-
-       public ScriptConfigurationComponent(String script, Set<String> keywords,
-                       Set<String> ports, final String scriptType,
-                       final String fileExtension, final String resetScript) {
-               super(new BorderLayout());
-               scriptTextArea = new JTextPane();
-               new LinePainter(scriptTextArea, WHITE);
-
-               final KeywordDocument doc = new KeywordDocument(keywords, 
ports);
-
-               // NOTE: Due to T2-1145 - always set editor kit BEFORE 
setDocument
-               scriptTextArea.setEditorKit(new NoWrapEditorKit());
-               scriptTextArea.setFont(new Font("Monospaced", PLAIN, 14));
-               scriptTextArea.setDocument(doc);
-               scriptTextArea.setText(script);
-               scriptTextArea.setCaretPosition(0);
-               scriptTextArea.setPreferredSize(new Dimension(200, 100));
-
-               add(new LineEnabledTextPanel(scriptTextArea), CENTER);
-
-               final JButton checkScriptButton = new JButton("Check script");
-               checkScriptButton.setToolTipText("Check the " + scriptType + " 
script");
-               checkScriptButton.addActionListener(new ActionListener() {
-                       @Override
-                       public void actionPerformed(ActionEvent ex) {
-                               
showMessageDialog(ScriptConfigurationComponent.this, scriptType
-                                               + " script check not 
implemented", scriptType
-                                               + " script check", 
INFORMATION_MESSAGE);
-                       }
-               });
-
-               JButton loadScriptButton = new JButton("Load script");
-               loadScriptButton.setToolTipText("Load a " + scriptType
-                               + " script from a file");
-               loadScriptButton.addActionListener(new ActionListener() {
-                       @Override
-                       public void actionPerformed(ActionEvent e) {
-                               String newScript = readStringFromFile(
-                                               
ScriptConfigurationComponent.this, "Load " + scriptType
-                                                               + " script", 
fileExtension);
-                               if (newScript != null) {
-                                       scriptTextArea.setText(newScript);
-                                       scriptTextArea.setCaretPosition(0);
-                               }
-                       }
-               });
-
-               JButton saveRScriptButton = new JButton("Save script");
-               saveRScriptButton.setToolTipText("Save the " + scriptType
-                               + " script to a file");
-               saveRScriptButton.addActionListener(new ActionListener() {
-                       @Override
-                       public void actionPerformed(ActionEvent e) {
-                               
saveStringToFile(ScriptConfigurationComponent.this, "Save "
-                                               + scriptType + " script", 
fileExtension,
-                                               scriptTextArea.getText());
-                       }
-               });
-
-               JButton clearScriptButton = new JButton("Clear script");
-               clearScriptButton.setToolTipText("Clear current script from the 
edit area");
-               clearScriptButton.addActionListener(new ActionListener() {
-                       @Override
-                       public void actionPerformed(ActionEvent e) {
-                               if 
(showConfirmDialog(ScriptConfigurationComponent.this,
-                                               "Do you really want to clear 
the script?",
-                                               "Clearing the script", 
YES_NO_OPTION) == YES_OPTION)
-                                       scriptTextArea.setText(resetScript);
-                       }
-               });
-
-               JPanel buttonPanel = new JPanel();
-               buttonPanel.setLayout(new FlowLayout());
-               buttonPanel.add(checkScriptButton);
-               buttonPanel.add(loadScriptButton);
-               buttonPanel.add(saveRScriptButton);
-               buttonPanel.add(clearScriptButton);
-
-               add(buttonPanel, SOUTH);
-       }
-
-       public String getScript() {
-               return scriptTextArea.getText();
-       }
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ValidatingTextField.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ValidatingTextField.java
 
b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ValidatingTextField.java
deleted file mode 100644
index cf1ff96..0000000
--- 
a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ValidatingTextField.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2012 The University of Manchester
- *
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- 
******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.views.contextualviews.activity;
-
-import javax.swing.JTextField;
-
-/**
- * Adds a "<tt>valid</tt>" property to a JTextField.
- * 
- * @author David Withers
- */
-@SuppressWarnings("serial")
-public class ValidatingTextField extends JTextField {
-       private boolean valid = true;
-
-       public ValidatingTextField() {
-       }
-
-       public ValidatingTextField(String text) {
-               super(text);
-       }
-
-       @Override
-       public boolean isValid() {
-               return valid;
-       }
-
-       public void setValid(boolean valid) {
-               if (this.valid != valid) {
-                       boolean old = this.valid;
-                       this.valid = valid;
-                       firePropertyChange("valid", old, valid);
-               }
-       }
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ValidatingTextGroup.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ValidatingTextGroup.java
 
b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ValidatingTextGroup.java
deleted file mode 100644
index 7597f7c..0000000
--- 
a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ValidatingTextGroup.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2012 The University of Manchester
- *
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- 
******************************************************************************/
-package net.sf.taverna.t2.workbench.ui.views.contextualviews.activity;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-
-/**
- *
- *
- * @author David Withers
- */
-public class ValidatingTextGroup {
-       private Map<ValidatingTextField, DocumentListener> textComponents;
-
-       public ValidatingTextGroup() {
-               textComponents = new HashMap<>();
-       }
-
-       public void addValidTextComponent(ValidatingTextField textComponent) {
-               setUniqueText(textComponent);
-               DocumentListener documentListener = new 
ValidatorDocumentListener();
-               
textComponent.getDocument().addDocumentListener(documentListener);
-               textComponents.put(textComponent, documentListener);
-       }
-
-       public void addTextComponent(ValidatingTextField textComponent) {
-               DocumentListener documentListener = new 
ValidatorDocumentListener();
-               
textComponent.getDocument().addDocumentListener(documentListener);
-               textComponents.put(textComponent, documentListener);
-               validate();
-       }
-
-       public void removeTextComponent(ValidatingTextField textComponent) {
-               textComponent.getDocument().removeDocumentListener(
-                               textComponents.remove(textComponent));
-               validate();
-       }
-
-       private void setUniqueText(ValidatingTextField textComponent) {
-               String text = textComponent.getText();
-               if (textExists(text)) {
-                       // Remove any existing number suffix
-                       String nameTemplate = text.replaceAll("_\\d+$", "_");
-                       long i = 1;
-                       do {
-                               text = nameTemplate + i++;
-                       } while (textExists(text));
-
-                       textComponent.setText(text);
-               }
-       }
-
-       private void validate() {
-               Map<String, ValidatingTextField> textValues = new HashMap<>();
-               Set<ValidatingTextField> maybeValid = new HashSet<>();
-               for (ValidatingTextField textComponent : 
textComponents.keySet()) {
-                       ValidatingTextField duplicate = 
textValues.get(textComponent
-                                       .getText());
-                       if (duplicate != null) {
-                               duplicate.setValid(false);
-                               maybeValid.remove(duplicate);
-                               textComponent.setValid(false);
-                       } else {
-                               textValues.put(textComponent.getText(), 
textComponent);
-                               maybeValid.add(textComponent);
-                       }
-               }
-               for (ValidatingTextField textComponent : maybeValid)
-                       textComponent.setValid(true);
-       }
-
-       private boolean textExists(String text) {
-               for (ValidatingTextField currentTextComponent : 
textComponents.keySet())
-                       if (text.equals(currentTextComponent.getText()))
-                               return true;
-               return false;
-       }
-
-       class ValidatorDocumentListener implements DocumentListener {
-               @Override
-               public void insertUpdate(DocumentEvent e) {
-                       validate();
-               }
-
-               @Override
-               public void removeUpdate(DocumentEvent e) {
-                       validate();
-               }
-
-               @Override
-               public void changedUpdate(DocumentEvent e) {
-                       validate();
-               }
-       }
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/actions/activity/ActivityConfigurationAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/actions/activity/ActivityConfigurationAction.java
 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/actions/activity/ActivityConfigurationAction.java
new file mode 100644
index 0000000..23fae78
--- /dev/null
+++ 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/actions/activity/ActivityConfigurationAction.java
@@ -0,0 +1,166 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.actions.activity;
+
+import java.util.List;
+import java.util.WeakHashMap;
+
+import javax.swing.AbstractAction;
+import javax.swing.JDialog;
+
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+import org.apache.taverna.servicedescriptions.ServiceDescription;
+import org.apache.taverna.servicedescriptions.ServiceDescriptionRegistry;
+import org.apache.taverna.workbench.activityicons.ActivityIconManager;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.file.events.ClosingDataflowEvent;
+import org.apache.taverna.workbench.file.events.FileManagerEvent;
+import 
org.apache.taverna.workbench.ui.views.contextualviews.activity.ActivityConfigurationDialog;
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.profiles.ProcessorBinding;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+
+@SuppressWarnings("serial")
+public abstract class ActivityConfigurationAction extends AbstractAction {
+       private static WeakHashMap<Activity, ActivityConfigurationDialog> 
configurationDialogs = new WeakHashMap<>();
+       private static DataflowCloseListener listener;
+
+       protected Activity activity;
+       private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+       public ActivityConfigurationAction(Activity activity,
+                       ActivityIconManager activityIconManager,
+                       ServiceDescriptionRegistry serviceDescriptionRegistry) {
+               this.activity = activity;
+               this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+               putValue(SMALL_ICON,
+                               
activityIconManager.iconForActivity(activity.getType()));
+       }
+
+       protected Activity getActivity() {
+               return activity;
+       }
+
+       protected ServiceDescription getServiceDescription() {
+               return serviceDescriptionRegistry.getServiceDescription(activity
+                               .getType());
+       }
+
+       protected static void setDialog(Activity activity,
+                       ActivityConfigurationDialog dialog, FileManager 
fileManager) {
+               if (listener == null) {
+                       listener = new DataflowCloseListener();
+                       /*
+                        * Ensure that the DataflowCloseListener is the first 
notified
+                        * listener. Otherwise you cannot save the 
configurations.
+                        */
+                       List<Observer<FileManagerEvent>> existingListeners = 
fileManager
+                                       .getObservers();
+                       fileManager.addObserver(listener);
+                       for (Observer<FileManagerEvent> observer : 
existingListeners)
+                               if (!observer.equals(listener)) {
+                                       fileManager.removeObserver(observer);
+                                       fileManager.addObserver(observer);
+                               }
+               }
+               if (configurationDialogs.containsKey(activity)) {
+                       ActivityConfigurationDialog currentDialog = 
configurationDialogs
+                                       .get(activity);
+                       if (!currentDialog.equals(dialog) && 
currentDialog.isVisible())
+                               currentDialog.setVisible(false);
+               }
+               configurationDialogs.put(activity, dialog);
+               dialog.setVisible(true);
+       }
+
+       public static void clearDialog(Activity activity) {
+               if (configurationDialogs.containsKey(activity)) {
+                       ActivityConfigurationDialog currentDialog = 
configurationDialogs
+                                       .get(activity);
+                       if (currentDialog.isVisible())
+                               currentDialog.setVisible(false);
+                       configurationDialogs.remove(activity);
+                       currentDialog.dispose();
+               }
+       }
+
+       protected static void clearDialog(JDialog dialog) {
+               if (configurationDialogs.containsValue(dialog)) {
+                       if (dialog.isVisible())
+                               dialog.setVisible(false);
+                       for (Activity activity : configurationDialogs.keySet())
+                               if 
(configurationDialogs.get(activity).equals(dialog))
+                                       configurationDialogs.remove(activity);
+                       dialog.dispose();
+               }
+       }
+
+       public static boolean closeDialog(Activity activity) {
+               boolean closeIt = true;
+               if (configurationDialogs.containsKey(activity)) {
+                       ActivityConfigurationDialog currentDialog = 
configurationDialogs
+                                       .get(activity);
+                       if (currentDialog.isVisible())
+                               closeIt = currentDialog.closeDialog();
+                       if (closeIt)
+                               configurationDialogs.remove(activity);
+               }
+               return closeIt;
+       }
+
+       public static ActivityConfigurationDialog getDialog(Activity activity) {
+               return configurationDialogs.get(activity);
+       }
+
+       private static class DataflowCloseListener implements
+                       Observer<FileManagerEvent> {
+               private Scufl2Tools scufl2Tools = new Scufl2Tools();
+
+               @Override
+               public void notify(Observable<FileManagerEvent> sender,
+                               FileManagerEvent message) throws Exception {
+                       if (message instanceof ClosingDataflowEvent) {
+                               ClosingDataflowEvent closingDataflowEvent = 
(ClosingDataflowEvent) message;
+                               if (closingDataflowEvent.isAbortClose())
+                                       return;
+                               closingDataflow(closingDataflowEvent,
+                                               ((ClosingDataflowEvent) 
message).getDataflow());
+                       }
+               }
+
+               private void closingDataflow(ClosingDataflowEvent event,
+                               WorkflowBundle bundle) {
+                       Profile profile = bundle.getMainProfile();
+                       for (Workflow workflow : bundle.getWorkflows())
+                               for (Processor p : workflow.getProcessors()) {
+                                       ProcessorBinding processorBinding = 
scufl2Tools
+                                                       
.processorBindingForProcessor(p, profile);
+                                       Activity activity = 
processorBinding.getBoundActivity();
+                                       if (!closeDialog(activity))
+                                               event.setAbortClose(true);
+                               }
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/actions/activity/ActivityContextualView.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/actions/activity/ActivityContextualView.java
 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/actions/activity/ActivityContextualView.java
new file mode 100644
index 0000000..58323d6
--- /dev/null
+++ 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/actions/activity/ActivityContextualView.java
@@ -0,0 +1,68 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.actions.activity;
+
+import org.apache.taverna.workbench.ui.views.contextualviews.ContextualView;
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+
+/**
+ * A contextual view specific to an Activity. Concrete subclasses must
+ * initialise the view by calling {@link #initView()}.
+ * <p>
+ * The implementation provides a view based upon the properties set in the
+ * Configuration
+ * 
+ * @author Stuart Owen
+ * @author Ian Dunlop
+ * 
+ * @see Activity
+ * @see ContextualView
+ */
+@SuppressWarnings("serial")
+public abstract class ActivityContextualView extends ContextualView {
+       private Activity activity;
+       private Scufl2Tools scufl2Tools = new Scufl2Tools();
+
+       /**
+        * Constructs an instance of the view.
+        * <p>
+        * The constructor parameter for the implementation of this class should
+        * define the specific Activity type itself.
+        * 
+        * @param activity
+        */
+       protected ActivityContextualView(Activity activity) {
+               super();
+               this.activity = activity;
+       }
+
+       public Activity getActivity() {
+               return activity;
+       }
+
+       public Configuration getConfigBean() {
+               return scufl2Tools.configurationFor(activity, 
activity.getParent());
+       }
+
+       @Override
+       public abstract void refreshView();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/actions/activity/HTMLBasedActivityContextualView.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/actions/activity/HTMLBasedActivityContextualView.java
 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/actions/activity/HTMLBasedActivityContextualView.java
new file mode 100644
index 0000000..1d649cf
--- /dev/null
+++ 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/actions/activity/HTMLBasedActivityContextualView.java
@@ -0,0 +1,80 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.actions.activity;
+
+import static org.apache.taverna.lang.ui.HtmlUtils.buildTableOpeningTag;
+import static org.apache.taverna.lang.ui.HtmlUtils.createEditorPane;
+import static org.apache.taverna.lang.ui.HtmlUtils.getHtmlHead;
+import static org.apache.taverna.lang.ui.HtmlUtils.panelForHtml;
+
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+
+import org.apache.taverna.workbench.configuration.colour.ColourManager;
+import org.apache.taverna.scufl2.api.activity.Activity;
+
+@SuppressWarnings("serial")
+public abstract class HTMLBasedActivityContextualView extends 
ActivityContextualView {
+       private static final String BEANSHELL_URI = 
"http://ns.taverna.org.uk/2010/activity/beanshell";;
+       private static final String LOCALWORKER_URI = 
"http://ns.taverna.org.uk/2010/activity/localworker";;
+       private JEditorPane editorPane;
+       private final ColourManager colourManager;
+
+       public HTMLBasedActivityContextualView(Activity activity, ColourManager 
colourManager) {
+               super(activity);
+               this.colourManager = colourManager;
+               initView();
+       }
+
+       @Override
+       public JComponent getMainFrame() {
+               editorPane = createEditorPane(buildHtml());
+               return panelForHtml(editorPane);
+       }
+
+       private String buildHtml() {
+               StringBuilder html = new 
StringBuilder(getHtmlHead(getBackgroundColour()));
+               html.append(buildTableOpeningTag());
+               html.append("<tr><th 
colspan=\"2\">").append(getViewTitle()).append("</th></tr>");
+               html.append(getRawTableRowsHtml()).append("</table>");
+               html.append("</body></html>");
+               return html.toString();
+       }
+
+       protected abstract String getRawTableRowsHtml();
+
+       public String getBackgroundColour() {
+               String activityType = getActivity().getType().toString();
+               if (LOCALWORKER_URI.equals(activityType))
+                       if 
(getConfigBean().getJson().get("isAltered").booleanValue())
+                               return (String) 
colourManager.getProperty(BEANSHELL_URI);
+               String colour = (String) 
colourManager.getProperty(activityType);
+               return colour == null ? "#ffffff" : colour;
+       }
+
+       /**
+        * Update the html view with the latest information in the configuration
+        * bean
+        */
+       @Override
+       public void refreshView() {
+               editorPane.setText(buildHtml());
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/AddLayerFactorySPI.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/AddLayerFactorySPI.java
 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/AddLayerFactorySPI.java
new file mode 100644
index 0000000..91aad6c
--- /dev/null
+++ 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/AddLayerFactorySPI.java
@@ -0,0 +1,42 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.views.contextualviews;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import org.apache.taverna.scufl2.api.core.Processor;
+
+/**
+ * SPI for adding dispatch stack layers to a processor, such as
+ * {@link org.apache.taverna.workflowmodel.processor.dispatch.layers.Loop}.
+ * <p>
+ * Buttons or similar will be added in the processor contextual view.
+ * 
+ * @author Stian Soiland-Reyes
+ */
+public interface AddLayerFactorySPI {
+       boolean canAddLayerFor(Processor proc);
+
+       Action getAddLayerActionFor(Processor proc);
+
+       boolean canCreateLayerClass(URI dispatchLayerType);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/ContextualView.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/ContextualView.java
 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/ContextualView.java
new file mode 100644
index 0000000..394f2a9
--- /dev/null
+++ 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/ContextualView.java
@@ -0,0 +1,108 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.views.contextualviews;
+
+import static java.awt.BorderLayout.CENTER;
+
+import java.awt.BorderLayout;
+import java.awt.Frame;
+
+import javax.swing.Action;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+/**
+ * An abstract class defining the base container to hold a contextual view over
+ * Dataflow element.
+ * <p>
+ * The specific implementation of this class to support a given dataflow 
element
+ * needs to implement the {@link #getMainFrame()} and {@link #getViewTitle()}.
+ * <p>
+ * If a view is associated with an action handler to configure this component,
+ * then the {@link #getConfigureAction(Frame) getConfigureAction} handler must
+ * be over-ridden. If this returns null then the configure button is left
+ * disabled and it is not possible to configure the element.
+ * 
+ * @author Stuart Owen
+ * @author Ian Dunlop
+ * @author Alan R Williams
+ */
+@SuppressWarnings("serial")
+public abstract class ContextualView extends JPanel {
+       /**
+        * When implemented, this method should define the main frame that is 
placed
+        * in this container, and provides a static view of the Dataflow 
element.
+        * 
+        * @return a JComponent that represents the dataflow element.
+        */
+       public abstract JComponent getMainFrame();
+
+       /**
+        * @return a String providing a title for the view
+        */
+       public abstract String getViewTitle();
+
+       /**
+        * Allows the item to be configured, but returning an action handler 
that
+        * will be invoked when selecting to configure. By default this is 
provided
+        * by a button.
+        * <p>
+        * If there is no ability to configure the given item, then this should
+        * return null.
+        * 
+        * @param owner
+        *            the owning dialog to be used when displaying dialogues for
+        *            configuration options
+        * @return an action that allows the element being viewed to be 
configured.
+        */
+       public Action getConfigureAction(Frame owner) {
+               return null;
+       }
+
+       /**
+        * This <i>must</i> be called by any sub-classes after they have 
initialised
+        * their own view since it gets their main panel and adds it to the main
+        * contextual view. If you don't do this you will get a very empty frame
+        * popping up!
+        */
+       public void initView() {
+               setLayout(new BorderLayout());
+               add(getMainFrame(), CENTER);
+               setName(getViewTitle());
+       }
+
+       public abstract void refreshView();
+
+       public abstract int getPreferredPosition();
+
+       public static String getTextFromDepth(String kind, Integer depth) {
+               String labelText = "The last prediction said the " + kind;
+               if (depth == null) {
+                       labelText += " would not transmit a value";
+               } else if (depth == -1) {
+                       labelText += " was invalid/unpredicted";
+               } else if (depth == 0) {
+                       labelText += " would carry a single value";
+               } else {
+                       labelText += " would carry a list of depth " + depth;
+               }
+               return labelText;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ActivityConfigurationDialog.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ActivityConfigurationDialog.java
 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ActivityConfigurationDialog.java
new file mode 100644
index 0000000..372bba5
--- /dev/null
+++ 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ActivityConfigurationDialog.java
@@ -0,0 +1,493 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.views.contextualviews.activity;
+
+import static java.awt.BorderLayout.SOUTH;
+import static java.awt.Cursor.DEFAULT_CURSOR;
+import static java.awt.Cursor.WAIT_CURSOR;
+import static java.awt.Cursor.getPredefinedCursor;
+import static java.lang.Math.max;
+import static javax.swing.JOptionPane.CANCEL_OPTION;
+import static javax.swing.JOptionPane.NO_OPTION;
+import static javax.swing.JOptionPane.YES_NO_CANCEL_OPTION;
+import static javax.swing.JOptionPane.YES_NO_OPTION;
+import static javax.swing.JOptionPane.YES_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static org.apache.taverna.workbench.MainWindow.getMainWindow;
+import static org.apache.taverna.workbench.helper.Helper.showHelp;
+import static 
org.apache.taverna.workbench.ui.actions.activity.ActivityConfigurationAction.clearDialog;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.border.EmptyBorder;
+
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+import org.apache.taverna.lang.ui.DeselectingButton;
+import org.apache.taverna.workbench.edits.CompoundEdit;
+import org.apache.taverna.workbench.edits.Edit;
+import org.apache.taverna.workbench.edits.EditException;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.edits.EditManager.DataFlowRedoEvent;
+import org.apache.taverna.workbench.edits.EditManager.DataFlowUndoEvent;
+import org.apache.taverna.workbench.edits.EditManager.EditManagerEvent;
+import org.apache.taverna.workbench.helper.HelpEnabledDialog;
+import org.apache.taverna.workflow.edits.AddChildEdit;
+import org.apache.taverna.workflow.edits.AddProcessorInputPortEdit;
+import org.apache.taverna.workflow.edits.AddProcessorOutputPortEdit;
+import org.apache.taverna.workflow.edits.ChangeDepthEdit;
+import org.apache.taverna.workflow.edits.ChangeGranularDepthEdit;
+import org.apache.taverna.workflow.edits.ChangeJsonEdit;
+import org.apache.taverna.workflow.edits.RemoveChildEdit;
+import org.apache.taverna.workflow.edits.RemoveProcessorInputPortEdit;
+import org.apache.taverna.workflow.edits.RemoveProcessorOutputPortEdit;
+import org.apache.taverna.workflow.edits.RenameEdit;
+
+import org.apache.log4j.Logger;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.port.ActivityPort;
+import org.apache.taverna.scufl2.api.port.InputActivityPort;
+import org.apache.taverna.scufl2.api.port.InputProcessorPort;
+import org.apache.taverna.scufl2.api.port.OutputActivityPort;
+import org.apache.taverna.scufl2.api.port.OutputProcessorPort;
+import org.apache.taverna.scufl2.api.profiles.ProcessorBinding;
+import org.apache.taverna.scufl2.api.profiles.ProcessorInputPortBinding;
+import org.apache.taverna.scufl2.api.profiles.ProcessorOutputPortBinding;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+@SuppressWarnings("serial")
+public class ActivityConfigurationDialog extends HelpEnabledDialog {
+       private enum PortType {
+               INPUT, OUTPUT
+       }
+       
+       protected static Logger logger = 
Logger.getLogger(ActivityConfigurationDialog.class);
+       private static final Scufl2Tools scufl2Tools = new Scufl2Tools();
+
+       private final EditManager editManager;
+
+       private Activity activity;
+       private ActivityConfigurationPanel panel;
+       protected WorkflowBundle owningWorkflowBundle;
+       protected Processor owningProcessor;
+       private Observer<EditManagerEvent> observer;
+       Dimension minimalSize = null;
+       Dimension buttonPanelSize = null;
+       JPanel buttonPanel;
+       protected JButton applyButton;
+
+       public ActivityConfigurationDialog(Activity a, 
ActivityConfigurationPanel p,
+                       EditManager editManager) {
+               super(getMainWindow(), "Configuring " + 
a.getClass().getSimpleName(),
+                               false, null);
+               this.activity = a;
+               this.panel = p;
+               this.editManager = editManager;
+
+               owningWorkflowBundle = activity.getParent().getParent();
+               owningProcessor = findProcessor(a);
+
+               setTitle(getRelativeName(owningWorkflowBundle, activity));
+               setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+               setLayout(new BorderLayout());
+
+               add(panel, BorderLayout.CENTER);
+
+               buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+               buttonPanel.setBorder(new EmptyBorder(5, 20, 5, 5));
+
+               JButton helpButton = new DeselectingButton("Help", new 
AbstractAction() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               showHelp(panel);
+                       }
+               });
+               buttonPanel.add(helpButton);
+
+               applyButton = new DeselectingButton("Apply", new 
AbstractAction() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               /*
+                                * For the moment it always does an apply as 
what should be
+                                * happening is that the apply button only 
becomes available
+                                * when the configuration has changed. However, 
many
+                                * configuration panels are not set up to 
detected changes
+                                */
+                               // if (panel.isConfigurationChanged()) {
+                               if (checkPanelValues())
+                                       applyConfiguration();
+                               // } else {
+                               // logger.info("Ignoring apply");
+                               // }
+                       }
+               });
+               buttonPanel.add(applyButton);
+
+               JButton closeButton = new DeselectingButton("Close", new 
AbstractAction() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               closeDialog();
+                       }
+               });
+               buttonPanel.add(closeButton);
+
+               add(buttonPanel, SOUTH);
+
+               this.addWindowListener(new WindowAdapter() {
+                       @Override
+                       public void windowOpened(WindowEvent e) {
+                               requestFocusInWindow();
+                               panel.whenOpened();
+                       }
+
+                       @Override
+                       public void windowClosing(WindowEvent e) {
+                               closeDialog();
+                       }
+               });
+               pack();
+               minimalSize = getSize();
+               setLocationRelativeTo(null);
+               setResizable(true);
+               addComponentListener(new ComponentAdapter() {
+                       @Override
+                       public void componentResized(ComponentEvent e) {
+                               int newWidth = max(getWidth(), 
minimalSize.width);
+                               int newHeight = max(getHeight(), 
minimalSize.height);
+                               setSize(new Dimension(newWidth, newHeight));
+                       }
+               });
+
+               observer = new Observer<EditManagerEvent>() {
+                       @Override
+                       public void notify(Observable<EditManagerEvent> sender, 
EditManagerEvent message)
+                                       throws Exception {
+                               logger.info("sender is a " + 
sender.getClass().getCanonicalName());
+                               logger.info("message is a " + 
message.getClass().getCanonicalName());
+                               Edit<?> edit = message.getEdit();
+                               logger.info(edit.getClass().getCanonicalName());
+                               considerEdit(message, edit);
+                       }
+               };
+               editManager.addObserver(observer);
+       }
+
+       private boolean checkPanelValues() {
+               boolean result = false;
+               try {
+                       setCursor(getPredefinedCursor(WAIT_CURSOR));
+                       result = panel.checkValues();
+               } finally {
+                       setCursor(getPredefinedCursor(DEFAULT_CURSOR));
+               }
+               return result;
+       }
+
+       private void considerEdit(EditManagerEvent message, Edit<?> edit) {
+               // boolean result = false;
+               if (edit instanceof CompoundEdit) {
+                       for (Edit<?> subEdit : ((CompoundEdit) 
edit).getChildEdits())
+                               considerEdit(message, subEdit);
+                       return;
+               }
+
+               Object subject = edit.getSubject();
+               if (subject == owningProcessor) {
+                       // panel.reevaluate();
+                       setTitle(getRelativeName(owningWorkflowBundle, 
activity));
+               } else if (subject == owningWorkflowBundle) {
+                       for (Workflow workflow : 
owningWorkflowBundle.getWorkflows())
+                               if 
(!workflow.getProcessors().contains(owningProcessor))
+                                       clearDialog(activity);
+               } else if (subject == activity) {
+                       if (message instanceof DataFlowUndoEvent) {
+                               logger.info("undo of activity edit found");
+                               panel.refreshConfiguration();
+                       } else if (message instanceof DataFlowRedoEvent) {
+                               logger.info("redo of activity edit found");
+                               panel.refreshConfiguration();
+                       }
+               }
+       }
+
+       protected void configureActivity(ObjectNode json, 
List<ActivityPortConfiguration> inputPorts,
+                       List<ActivityPortConfiguration> outputPorts) {
+               configureActivity(owningWorkflowBundle, activity, json, 
inputPorts, outputPorts);
+       }
+
+       public void configureActivity(WorkflowBundle workflowBundle, Activity 
activity,
+                       ObjectNode json, List<ActivityPortConfiguration> 
inputPorts,
+                       List<ActivityPortConfiguration> outputPorts) {
+               try {
+                       List<Edit<?>> editList = new ArrayList<Edit<?>>();
+                       Profile profile = activity.getParent();
+                       List<ProcessorBinding> processorBindings = scufl2Tools
+                                       .processorBindingsToActivity(activity);
+                       Configuration configuration = 
scufl2Tools.configurationFor(activity, profile);
+                       editList.add(new ChangeJsonEdit(configuration, json));
+
+                       configurePorts(activity, editList, processorBindings, 
inputPorts, PortType.INPUT);
+                       configurePorts(activity, editList, processorBindings, 
outputPorts, PortType.OUTPUT);
+                       editManager.doDataflowEdit(workflowBundle, new 
CompoundEdit(editList));
+               } catch (IllegalStateException | EditException e) {
+                       logger.error(e);
+               }
+       }
+
+       private void configurePorts(Activity activity, List<Edit<?>> editList,
+                       List<ProcessorBinding> processorBindings,
+                       List<ActivityPortConfiguration> portDefinitions, 
PortType portType) {
+               Set<ActivityPort> ports = new HashSet<>();
+               for (ActivityPort activityPort : portType == PortType.INPUT ? 
activity
+                               .getInputPorts() : activity.getOutputPorts())
+                       ports.add(activityPort);
+               for (ActivityPortConfiguration portDefinition : 
portDefinitions) {
+                       String portName = portDefinition.getName();
+                       int portDepth = portDefinition.getDepth();
+                       int granularPortDepth = 
portDefinition.getGranularDepth();
+                       ActivityPort activityPort = 
portDefinition.getActivityPort();
+                       if (activityPort == null) {
+                               // no activity port so add a new one
+                               if (portType == PortType.INPUT)
+                                       createInputPort(activity, editList, 
processorBindings, portDefinition);
+                               else
+                                       createOutputPort(activity, editList, 
processorBindings, portDefinition);
+                       } else {
+                               ports.remove(activityPort);
+                               // check if port has changed
+                               for (ProcessorBinding processorBinding : 
processorBindings)
+                                       if (portType == PortType.INPUT)
+                                               for (ProcessorInputPortBinding 
portBinding : processorBinding
+                                                               
.getInputPortBindings()) {
+                                                       if 
(!portBinding.getBoundActivityPort().equals(
+                                                                       
activityPort))
+                                                               continue;
+                                                       InputProcessorPort 
processorPort = portBinding
+                                                                       
.getBoundProcessorPort();
+                                                       if 
(!activityPort.getName().equals(portName))
+                                                               // port name 
changed
+                                                               if 
(processorPort.getName().equals(activityPort.getName()))
+                                                                       // 
default mapping so change processor port
+                                                                       
editList.add(new RenameEdit<>(processorPort, portName));
+                                                       if 
(!processorPort.getDepth().equals(portDepth))
+                                                               // port depth 
changed
+                                                               
editList.add(new ChangeDepthEdit<>(
+                                                                               
processorPort, portDepth));
+                                               }
+                                       else
+                                               for (ProcessorOutputPortBinding 
portBinding : processorBinding
+                                                               
.getOutputPortBindings()) {
+                                                       if 
(!portBinding.getBoundActivityPort().equals(
+                                                                       
activityPort))
+                                                               continue;
+                                                       OutputProcessorPort 
processorPort = portBinding
+                                                                       
.getBoundProcessorPort();
+                                                       if 
(!activityPort.getName().equals(portName))
+                                                               // port name 
changed
+                                                               if 
(processorPort.getName().equals(
+                                                                               
activityPort.getName()))
+                                                                       // 
default mapping so change processor port
+                                                                       
editList.add(new RenameEdit<>(
+                                                                               
        processorPort, portName));
+                                                       if 
(!processorPort.getDepth().equals(portDepth))
+                                                               // port depth 
changed
+                                                               
editList.add(new ChangeDepthEdit<>(
+                                                                               
processorPort, portDepth));
+                                                       if 
(!processorPort.getGranularDepth().equals(
+                                                                       
granularPortDepth))
+                                                               // port 
granular depth changed
+                                                               
editList.add(new ChangeGranularDepthEdit<>(
+                                                                               
processorPort, granularPortDepth));
+                                               }
+                               if (!activityPort.getName().equals(portName))
+                                       // port name changed
+                                       editList.add(new 
RenameEdit<>(activityPort, portName));
+                               if (!activityPort.getDepth().equals(portDepth))
+                                       // port depth changed
+                                       editList.add(new 
ChangeDepthEdit<>(activityPort, portDepth));
+                               if (activityPort instanceof OutputActivityPort) 
{
+                                       OutputActivityPort outputActivityPort = 
(OutputActivityPort) activityPort;
+                                       Integer granularDepth = 
outputActivityPort
+                                                       .getGranularDepth();
+                                       if (granularDepth == null
+                                                       || 
!granularDepth.equals(granularPortDepth))
+                                               // granular port depth changed
+                                               editList.add(new 
ChangeGranularDepthEdit<>(
+                                                               
outputActivityPort, granularPortDepth));
+                               }
+                       }
+               }
+
+               // remove any unconfigured ports
+               for (ActivityPort activityPort : ports) {
+                       // remove processor ports and bindings
+                       for (ProcessorBinding processorBinding : 
processorBindings)
+                               if (portType.equals(PortType.INPUT))
+                                       for (ProcessorInputPortBinding 
portBinding : processorBinding
+                                                       
.getInputPortBindings()) {
+                                               if 
(portBinding.getBoundActivityPort().equals(activityPort)) {
+                                                       editList.add(new 
RemoveProcessorInputPortEdit(processorBinding
+                                                                       
.getBoundProcessor(), portBinding.getBoundProcessorPort()));
+                                                       editList.add(new 
RemoveChildEdit<>(processorBinding,
+                                                                       
portBinding));
+                                               }
+                                       }
+                               else
+                                       for (ProcessorOutputPortBinding 
portBinding : processorBinding
+                                                       
.getOutputPortBindings())
+                                               if 
(portBinding.getBoundActivityPort().equals(activityPort)) {
+                                                       editList.add(new 
RemoveProcessorOutputPortEdit(processorBinding
+                                                                       
.getBoundProcessor(), portBinding.getBoundProcessorPort()));
+                                                       editList.add(new 
RemoveChildEdit<>(processorBinding,
+                                                                       
portBinding));
+                                               }
+                       // remove activity port
+                       editList.add(new RemoveChildEdit<Activity>(activity, 
activityPort));
+               }
+       }
+
+       private void createInputPort(Activity activity, List<Edit<?>> editList,
+                       List<ProcessorBinding> processorBindings,
+                       ActivityPortConfiguration portDefinition) {
+               InputActivityPort actPort = new InputActivityPort(null,
+                               portDefinition.getName());
+               actPort.setDepth(portDefinition.getDepth());
+               // add port to activity
+               editList.add(new AddChildEdit<>(activity, actPort));
+               for (ProcessorBinding processorBinding : processorBindings) {
+                       Processor processor = 
processorBinding.getBoundProcessor();
+                       // add a new processor port
+                       InputProcessorPort procPort = new InputProcessorPort();
+                       procPort.setName(portDefinition.getName());
+                       procPort.setDepth(portDefinition.getDepth());
+                       editList.add(new AddProcessorInputPortEdit(processor, 
procPort));
+                       // add a new port binding
+                       ProcessorInputPortBinding binding = new 
ProcessorInputPortBinding();
+                       binding.setBoundProcessorPort(procPort);
+                       binding.setBoundActivityPort(actPort);
+                       editList.add(new AddChildEdit<>(processorBinding, 
binding));
+               }
+       }
+
+       private void createOutputPort(Activity activity, List<Edit<?>> editList,
+                       List<ProcessorBinding> processorBindings,
+                       ActivityPortConfiguration portDefinition) {
+               OutputActivityPort actPort = new OutputActivityPort(null,
+                               portDefinition.getName());
+               actPort.setDepth(portDefinition.getDepth());
+               actPort.setGranularDepth(portDefinition.getGranularDepth());
+               // add port to activity
+               editList.add(new AddChildEdit<Activity>(activity, actPort));
+               for (ProcessorBinding processorBinding : processorBindings) {
+                       Processor processor = 
processorBinding.getBoundProcessor();
+                       // add a new processor port
+                       OutputProcessorPort procPort = new 
OutputProcessorPort();
+                       procPort.setName(portDefinition.getName());
+                       procPort.setDepth(portDefinition.getDepth());
+                       
procPort.setGranularDepth(portDefinition.getGranularDepth());
+                       editList.add(new AddProcessorOutputPortEdit(processor, 
procPort));
+                       // add a new port binding
+                       ProcessorOutputPortBinding binding = new 
ProcessorOutputPortBinding();
+                       binding.setBoundProcessorPort(procPort);
+                       binding.setBoundActivityPort(actPort);
+                       editList.add(new AddChildEdit<>(processorBinding, 
binding));
+               }
+       }
+
+       protected static Processor findProcessor(Activity activity) {
+               for (ProcessorBinding processorBinding : scufl2Tools
+                               .processorBindingsToActivity(activity))
+                       return processorBinding.getBoundProcessor();
+               return null;
+       }
+
+       public static String getRelativeName(WorkflowBundle workflowBundle, 
Activity activity) {
+               StringBuilder relativeName = new StringBuilder("");
+               if (workflowBundle != null) {
+                       Workflow workflow = workflowBundle.getMainWorkflow();
+                       if (workflow != null) {
+                               relativeName.append(workflow.getName());
+                               relativeName.append(":");
+                       }
+               }
+               Processor processor = findProcessor(activity);
+               if (processor != null)
+                       relativeName.append(processor.getName());
+               return relativeName.toString();
+       }
+
+       public boolean closeDialog() {
+               if (panel.isConfigurationChanged()) {
+                       String relativeName = 
getRelativeName(owningWorkflowBundle, activity);
+                       if (checkPanelValues()) {
+                               int answer = showConfirmDialog(this,
+                                               "Do you want to save the 
configuration of " + relativeName + "?",
+                                               relativeName, 
YES_NO_CANCEL_OPTION);
+                               if (answer == YES_OPTION) {
+                                       applyConfiguration();
+                               } else if (answer == CANCEL_OPTION) {
+                                       return false;
+                               }
+                       } else if (showConfirmDialog(
+                                       this,
+                                       "New configuration could not be saved. 
Do you still want to close?",
+                                       relativeName, YES_NO_OPTION) == 
NO_OPTION)
+                               return false;
+               }
+               panel.whenClosed();
+               clearDialog(activity);
+               return true;
+       }
+
+       private void applyConfiguration() {
+               panel.noteConfiguration();
+               configureActivity(panel.getJson(), panel.getInputPorts(),
+                               panel.getOutputPorts());
+               panel.refreshConfiguration();
+       }
+
+       @Override
+       public void dispose() {
+               super.dispose();
+               editManager.removeObserver(observer);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ActivityConfigurationPanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ActivityConfigurationPanel.java
 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ActivityConfigurationPanel.java
new file mode 100644
index 0000000..b0a6fa9
--- /dev/null
+++ 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ActivityConfigurationPanel.java
@@ -0,0 +1,230 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.views.contextualviews.activity;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.JPanel;
+
+import org.apache.log4j.Logger;
+
+import org.apache.taverna.commons.services.ActivityTypeNotFoundException;
+import org.apache.taverna.commons.services.InvalidConfigurationException;
+import org.apache.taverna.commons.services.ServiceRegistry;
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.port.ActivityPort;
+import org.apache.taverna.scufl2.api.port.InputActivityPort;
+import org.apache.taverna.scufl2.api.port.OutputActivityPort;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * @author alanrw
+ */
+@SuppressWarnings("serial")
+public abstract class ActivityConfigurationPanel extends JPanel {
+       private static final Logger logger = 
Logger.getLogger(ActivityConfigurationPanel.class);
+       private final static Scufl2Tools scufl2Tools = new Scufl2Tools();
+
+       // protected final URITools uriTools = new URITools();
+       private final Activity activity;
+       private final Configuration configuration;
+       private final List<ActivityPortConfiguration> inputPorts;
+       private final List<ActivityPortConfiguration> outputPorts;
+       protected ObjectNode json;
+
+       public ActivityConfigurationPanel(Activity activity) {
+               this(activity, scufl2Tools.configurationFor(activity,
+                               activity.getParent()));
+       }
+
+       public ActivityConfigurationPanel(Activity activity,
+                       Configuration configuration) {
+               this.activity = activity;
+               this.configuration = configuration;
+               inputPorts = new ArrayList<>();
+               outputPorts = new ArrayList<>();
+       }
+
+       /**
+        * Initializes the configuration panel. This method is also used to 
discard
+        * any changes and reset the panel to its initial state. Subclasses 
should
+        * implement this method to set up the panel and must call
+        * <tt>super.initialise()</tt> first.
+        */
+       protected void initialise() {
+               json = configuration.getJson().deepCopy();
+               inputPorts.clear();
+               for (InputActivityPort activityPort : activity.getInputPorts())
+                       inputPorts.add(new 
ActivityPortConfiguration(activityPort));
+               outputPorts.clear();
+               for (OutputActivityPort activityPort : 
activity.getOutputPorts())
+                       outputPorts.add(new 
ActivityPortConfiguration(activityPort));
+       }
+
+       public abstract boolean checkValues();
+
+       public abstract void noteConfiguration();
+
+       public boolean isConfigurationChanged() {
+               noteConfiguration();
+               if (portsChanged(inputPorts, activity.getInputPorts().size()))
+                       return true;
+               if (portsChanged(outputPorts, activity.getOutputPorts().size()))
+                       return true;
+               return !json.equals(configuration.getJson());
+       }
+
+       public Configuration getConfiguration() {
+               return configuration;
+       }
+
+       public ObjectNode getJson() {
+               return json;
+       }
+
+       protected void setJson(ObjectNode json) {
+               this.json = json;
+       }
+
+       public void refreshConfiguration() {
+               initialise();
+       }
+
+       public void whenOpened() {
+       }
+
+       public void whenClosed() {
+       }
+
+       /**
+        * Convenience method for getting simple String property values.
+        *
+        * @param name
+        *            the property name
+        * @return the property value
+        */
+       protected String getProperty(String name) {
+               JsonNode jsonNode = json.get(name);
+               if (jsonNode == null)
+                       return null;
+               return json.get(name).asText();
+       }
+
+       /**
+        * Convenience method for setting simple String property values.
+        *
+        * @param name
+        *            the property name
+        * @param value
+        *            the property value
+        */
+       protected void setProperty(String name, String value) {
+               json.put(name, value);
+       }
+
+       public List<ActivityPortConfiguration> getInputPorts() {
+               return inputPorts;
+       }
+
+       public List<ActivityPortConfiguration> getOutputPorts() {
+               return outputPorts;
+       }
+
+       protected void configureInputPorts(ServiceRegistry serviceRegistry) {
+               try {
+                       Map<String, InputActivityPort> newInputPorts = new 
HashMap<>();
+                       for (InputActivityPort port : serviceRegistry
+                                       
.getActivityInputPorts(getActivity().getType(), getJson()))
+                               newInputPorts.put(port.getName(), port);
+                       List<ActivityPortConfiguration> inputPorts = 
getInputPorts();
+                       for (ActivityPortConfiguration portConfig : new 
ArrayList<>(
+                                       inputPorts))
+                               if 
(newInputPorts.containsKey(portConfig.getName())) {
+                                       InputActivityPort port = 
newInputPorts.remove(portConfig
+                                                       .getName());
+                                       portConfig.setDepth(port.getDepth());
+                               } else
+                                       inputPorts.remove(portConfig);
+                       for (InputActivityPort newPort : newInputPorts.values())
+                               inputPorts.add(new 
ActivityPortConfiguration(newPort.getName(),
+                                               newPort.getDepth()));
+               } catch (InvalidConfigurationException | 
ActivityTypeNotFoundException e) {
+                       logger.warn("Error configuring input ports", e);
+               }
+       }
+
+       protected void configureOutputPorts(ServiceRegistry serviceRegistry) {
+               try {
+                       Map<String, OutputActivityPort> newOutputPorts = new 
HashMap<>();
+                       for (OutputActivityPort port : serviceRegistry
+                                       
.getActivityOutputPorts(getActivity().getType(), getJson()))
+                               newOutputPorts.put(port.getName(), port);
+                       List<ActivityPortConfiguration> outputPorts = 
getOutputPorts();
+                       for (ActivityPortConfiguration portConfig : new 
ArrayList<>(
+                                       outputPorts))
+                               if 
(newOutputPorts.containsKey(portConfig.getName())) {
+                                       OutputActivityPort port = 
newOutputPorts.remove(portConfig
+                                                       .getName());
+                                       portConfig.setDepth(port.getDepth());
+                                       
portConfig.setGranularDepth(port.getGranularDepth());
+                               } else
+                                       outputPorts.remove(portConfig);
+                       for (OutputActivityPort newPort : 
newOutputPorts.values())
+                               outputPorts.add(new ActivityPortConfiguration(
+                                               newPort.getName(), 
newPort.getDepth()));
+               } catch (InvalidConfigurationException | 
ActivityTypeNotFoundException e) {
+                       logger.warn("Error configuring output ports", e);
+               }
+       }
+
+       private boolean portsChanged(List<ActivityPortConfiguration> 
portDefinitions, int ports) {
+               int checkedPorts = 0;
+               for (ActivityPortConfiguration portDefinition : 
portDefinitions) {
+                       String portName = portDefinition.getName();
+                       int portDepth = portDefinition.getDepth();
+                       ActivityPort activityPort = 
portDefinition.getActivityPort();
+                       if (activityPort == null)
+                               // new port added
+                               return true;
+                       if (!activityPort.getName().equals(portName))
+                               // port name changed
+                               return true;
+                       if (!activityPort.getDepth().equals(portDepth))
+                               // port depth changed
+                               return true;
+                       checkedPorts++;
+               }
+               if (checkedPorts < ports)
+                       // ports deleted
+                       return true;
+               return false;
+       }
+
+       public Activity getActivity() {
+               return activity;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ActivityPortConfiguration.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ActivityPortConfiguration.java
 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ActivityPortConfiguration.java
new file mode 100644
index 0000000..f3ea920
--- /dev/null
+++ 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ActivityPortConfiguration.java
@@ -0,0 +1,83 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.views.contextualviews.activity;
+
+import org.apache.taverna.scufl2.api.port.ActivityPort;
+
+/**
+ *
+ *
+ * @author David Withers
+ */
+public class ActivityPortConfiguration {
+
+       private ActivityPort activityPort;
+
+       private String name;
+
+       private int depth;
+
+       private int granularDepth;
+
+       public ActivityPortConfiguration(ActivityPort activityPort) {
+               this.activityPort = activityPort;
+               name = activityPort.getName();
+               depth = activityPort.getDepth();
+       }
+
+       public ActivityPortConfiguration(String name, int depth) {
+               this(name, depth, depth);
+       }
+
+       public ActivityPortConfiguration(String name, int depth, int 
granularDepth) {
+               this.name = name;
+               this.depth = depth;
+               this.granularDepth = granularDepth;
+       }
+
+       public ActivityPort getActivityPort() {
+               return activityPort;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public void setName(String name) {
+               this.name = name;
+       }
+
+       public int getDepth() {
+               return depth;
+       }
+
+       public void setDepth(int depth) {
+               this.depth = depth;
+       }
+
+       public int getGranularDepth() {
+               return granularDepth;
+       }
+
+       public void setGranularDepth(int granularDepth) {
+               this.granularDepth = granularDepth;
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ContextualViewFactory.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ContextualViewFactory.java
 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ContextualViewFactory.java
new file mode 100644
index 0000000..926268f
--- /dev/null
+++ 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ContextualViewFactory.java
@@ -0,0 +1,62 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.views.contextualviews.activity;
+
+import java.util.List;
+
+import org.apache.taverna.workbench.ui.views.contextualviews.ContextualView;
+
+/**
+ * Defines a factory class that when associated with a selected object creates 
a
+ * {@link ContextualView} for that selection.
+ * <p>
+ * This factory acts as an SPI to find {@link ContextualView}s for a given
+ * Activity and other workflow components.
+ * </p>
+ * 
+ * @author Stuart Owen
+ * @author Ian Dunlop
+ * @author Stian Soiland-Reyes
+ * 
+ * 
+ * @param <SelectionType>
+ *            - the selection type this factory is associated with
+ * 
+ * @see ContextualView
+ * @see ContextualViewFactoryRegistry
+ */
+public interface ContextualViewFactory<SelectionType> {
+       /**
+        * @param selection
+        *            - the object for which ContextualViews needs to be 
generated
+        * @return instance of {@link ContextualView}
+        */
+       public List<ContextualView> getViews(SelectionType selection);
+
+       /**
+        * Used by the SPI system to find the correct factory that can handle 
the
+        * given object type. 
+        * 
+        * @param selection
+        * @return true if this factory relates to the given selection type
+        * @see ContextualViewFactoryRegistry
+        */
+       public boolean canHandle(Object selection);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ContextualViewFactoryRegistry.java
----------------------------------------------------------------------
diff --git 
a/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ContextualViewFactoryRegistry.java
 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ContextualViewFactoryRegistry.java
new file mode 100644
index 0000000..735302d
--- /dev/null
+++ 
b/taverna-contextual-views-api/src/main/java/org/apache/taverna/workbench/ui/views/contextualviews/activity/ContextualViewFactoryRegistry.java
@@ -0,0 +1,42 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.taverna.workbench.ui.views.contextualviews.activity;
+
+import java.util.List;
+
+/**
+ * A registry for discovering ActivityViewFactories for a given object,
+ * like an {@link 
org.apache.taverna.workflowmodel.processor.activity.Activity}.
+ *
+ * @author David Withers
+ */
+public interface ContextualViewFactoryRegistry {
+       /**
+        * Discover and return the ContextualViewFactory associated to the 
provided
+        * object. This is accomplished by returning the discovered
+        * {@link ContextualViewFactory#canHandle(Object)} that returns true for
+        * that Object.
+        *
+        * @param object
+        * @return
+        * @see ContextualViewFactory#canHandle(Object)
+        */
+       public <T> List<ContextualViewFactory<? super T>> 
getViewFactoriesForObject(T object);
+}

Reply via email to