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

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

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ActivityConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ActivityConfigurationPanel.java b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ActivityConfigurationPanel.java
new file mode 100644
index 0000000..cf7f42a
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ActivityConfigurationPanel.java
@@ -0,0 +1,214 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.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 uk.org.taverna.commons.services.ActivityTypeNotFoundException;
+import uk.org.taverna.commons.services.InvalidConfigurationException;
+import uk.org.taverna.commons.services.ServiceRegistry;
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.common.Scufl2Tools;
+import uk.org.taverna.scufl2.api.configurations.Configuration;
+import uk.org.taverna.scufl2.api.port.ActivityPort;
+import uk.org.taverna.scufl2.api.port.InputActivityPort;
+import uk.org.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/52fd79dd/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ActivityPortConfiguration.java
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ActivityPortConfiguration.java b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ActivityPortConfiguration.java
new file mode 100644
index 0000000..6b23fd5
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ActivityPortConfiguration.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (C) 2013 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.ui.views.contextualviews.activity;
+
+import uk.org.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/52fd79dd/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ContextualViewFactory.java
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ContextualViewFactory.java b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ContextualViewFactory.java
new file mode 100644
index 0000000..b5d29d7
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ContextualViewFactory.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.ui.views.contextualviews.activity;
+
+import java.util.List;
+
+import net.sf.taverna.t2.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/52fd79dd/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ContextualViewFactoryRegistry.java
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ContextualViewFactoryRegistry.java b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ContextualViewFactoryRegistry.java
new file mode 100644
index 0000000..305f3c0
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ContextualViewFactoryRegistry.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (C) 2011 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.ui.views.contextualviews.activity;
+
+import java.util.List;
+
+/**
+ * A registry for discovering ActivityViewFactories for a given object,
+ * like an {@link net.sf.taverna.t2.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);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/DependencyConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/DependencyConfigurationPanel.java b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/DependencyConfigurationPanel.java
new file mode 100644
index 0000000..c28cb55
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/DependencyConfigurationPanel.java
@@ -0,0 +1,293 @@
+/*******************************************************************************
+ * Copyright (C) 2013 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.ui.views.contextualviews.activity;
+
+import static java.awt.BorderLayout.CENTER;
+import static java.awt.BorderLayout.NORTH;
+import static java.awt.Color.RED;
+import static java.awt.GridBagConstraints.FIRST_LINE_START;
+import static java.awt.GridBagConstraints.HORIZONTAL;
+import static java.awt.event.ItemEvent.DESELECTED;
+import static java.awt.event.ItemEvent.SELECTED;
+import static java.util.Arrays.asList;
+import static javax.swing.Box.createRigidArea;
+import static javax.swing.BoxLayout.PAGE_AXIS;
+import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER;
+import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.BoxLayout;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * Component for configuring activities that require dependencies.
+ *
+ * @author David Withers
+ */
+@SuppressWarnings("serial")
+public class DependencyConfigurationPanel extends JPanel {
+	private String classLoaderSharing;
+	private List<String> localDependencies;
+	private File libDir;
+
+	public DependencyConfigurationPanel(String classLoaderSharing,
+			List<String> localDependencies, File libDir) {
+		this.classLoaderSharing = classLoaderSharing;
+		this.localDependencies = localDependencies;
+		this.libDir = libDir;
+		setLayout(new BoxLayout(this, PAGE_AXIS));
+
+		// Create panel with classloading options
+		JPanel classloadingPanel = new ClassloadingPanel();
+		// Create panel for selecting jar files
+		JPanel jarFilesPanel = new JarFilesPanel();
+
+		add(classloadingPanel);
+		add(createRigidArea(new Dimension(0,10)));
+		add(jarFilesPanel);
+		add(createRigidArea(new Dimension(0,10)));
+
+	}
+
+	public String getClassLoaderSharing() {
+		return classLoaderSharing;
+	}
+
+	public List<String> getLocalDependencies() {
+		return localDependencies;
+	}
+
+	// Classloading option 'workflow'
+	private static final String WORKFLOW = "Shared for whole workflow";
+	// Classloading option 'system'
+	private static final String SYSTEM = "System classloader";
+	
+	// Panel containing classloading options
+	private class ClassloadingPanel extends JPanel {
+		// Combobox with classloading options
+		private JComboBox<String> jcbClassloadingOption;
+		// Classloading option descriptions
+		private HashMap<String, String> classloadingDescriptions;
+		// JLabel with classloading option description
+		private JLabel jlClassloadingDescription;
+
+		/*
+		 * Panel containing a list of possible classloading options which users
+		 * can select from
+		 */
+		private ClassloadingPanel() {
+			super(new GridBagLayout());
+			jcbClassloadingOption = new JComboBox<>(new String[] { WORKFLOW,
+					SYSTEM });
+			// Set the current classlaoding option based on the configuration bean
+			if ("workflow".equals(classLoaderSharing)) {
+				jcbClassloadingOption.setSelectedItem(WORKFLOW);
+			} else if ("system".equals(classLoaderSharing)) {
+				jcbClassloadingOption.setSelectedItem(SYSTEM);
+			}
+
+			jcbClassloadingOption.addActionListener(new ActionListener(){
+				// Fires up when combobox selection changes
+				@Override
+				public void actionPerformed(ActionEvent e) {
+					Object selectedItem = jcbClassloadingOption.getSelectedItem();
+					jlClassloadingDescription.setText(classloadingDescriptions
+							.get(selectedItem));
+					if (selectedItem.equals(WORKFLOW))
+						classLoaderSharing = "workflow";
+					else if (selectedItem.equals(SYSTEM))
+						classLoaderSharing = "system";
+				}
+			});
+			//jcbClassloadingOption.setEnabled(false);
+
+			classloadingDescriptions = new HashMap<>();
+			classloadingDescriptions.put(WORKFLOW, "<html><small>"
+					+ "Classes are shared across the whole workflow (with any service<br>"
+					+ "also selecting this option), but are reinitialised for each workflow run.<br>"
+					+ "This might be needed if a service passes objects to another, or <br>"
+					+ "state is shared within static members of loaded classes."
+					+ "</small></html>");
+			classloadingDescriptions.put(SYSTEM, "<html><small><p>"
+					+ "The (global) system classloader is used, any dependencies defined here are<br>"
+					+ "made available globally on the first run. Note that if you are NOT using<br>"
+					+ "the defaulf Taverna BootstrapClassLoader, any settings here will be disregarded."
+					+ "</p><p>"
+					+ "This is mainly useful if you are using JNI-based libraries. Note that <br>"
+					+ "for JNI you also have to specify <code>-Djava.library.path</code> and <br>"
+					+ "probably your operating system's dynamic library search path<br>"
+					+ "<code>LD_LIBRARY_PATH</code> / <code>DYLD_LIBRARY_PATH</code> / <code>PATH</code> </p>"
+					+ "</small></html>");
+
+			/*
+			 * Set the current classlaoding description based on the item
+			 * selected in the combobox.
+			 */
+			jlClassloadingDescription = new JLabel(classloadingDescriptions
+					.get(jcbClassloadingOption.getSelectedItem()));
+
+			// Add components to the ClassloadingPanel
+			GridBagConstraints c = new GridBagConstraints();
+			c.anchor = FIRST_LINE_START;
+			c.fill = HORIZONTAL;
+			c.gridx = 0;
+			c.insets = new Insets(10,0,0,0);
+			add(new JLabel("Classloader persistence"), c);
+			c.insets = new Insets(0,0,0,0);
+			add(jcbClassloadingOption, c);
+			c.insets = new Insets(0,30,0,0);
+			add(jlClassloadingDescription, c);
+		}
+	}
+
+	// Panel for users to add local JAR dependencies (contains a list of jar files which users can select from)
+	private class JarFilesPanel extends JPanel {
+		private JLabel warning = new JLabel(
+				"<html>"
+						+ "<center<font color='red'>"
+						+ "Warning: Depending on local libraries makes this workflow<br>"
+						+ "difficult or impossible to run for other users. Try depending<br>"
+						+ "on artifacts from a public repository if possible.</font></center>"
+						+ "</html>");
+
+		private JarFilesPanel() {
+			super();
+			setMinimumSize(new Dimension(400, 150));
+			setLayout(new BorderLayout());
+			setBorder(new EmptyBorder(0,10,0,10));
+
+			JPanel labelPanel = new JPanel();
+			labelPanel.setLayout(new BoxLayout(labelPanel, PAGE_AXIS));
+			JLabel label = new JLabel("Local JAR files");
+			JLabel libLabel = new JLabel("<html><small>" + libDir.getAbsolutePath()
+					+ "</small></html>");
+			labelPanel.add(label);
+			labelPanel.add(libLabel);
+
+			add(labelPanel, NORTH);
+			add(new JScrollPane(jarFiles(), VERTICAL_SCROLLBAR_AS_NEEDED,
+					HORIZONTAL_SCROLLBAR_NEVER), CENTER);
+
+			warning.setVisible(false);
+			/*
+			 * We'll skip the warning until we actually have support for
+			 * artifacts
+			 */
+			//add(warning);
+			updateWarning();
+		}
+
+		private void updateWarning() {
+			// Show warning if there is any local dependencies
+			warning.setVisible(!localDependencies.isEmpty());
+		}
+
+		public JPanel jarFiles() {
+			JPanel panel = new JPanel();
+			panel.setLayout(new BoxLayout(panel, PAGE_AXIS));
+
+			// List of all jar files in the lib directory
+			List<String> jarFiles = asList(libDir
+					.list(new FileExtFilter(".jar")));
+			/*
+			 * We also add the list of jars that may have been configured
+			 * sometime before but are now not present in the lib directory for
+			 * some reason
+			 */
+			Set<String> missingLocalDeps = new HashSet<>(localDependencies);
+			missingLocalDeps.removeAll(jarFiles);
+			/*
+			 * jarFiles and missingLocalDeps now contain two sets of files that
+			 * do not intersect
+			 */
+			List<String> jarFilesList = new ArrayList<>();
+			// Put them all together
+			jarFilesList.addAll(jarFiles);
+			jarFilesList.addAll(missingLocalDeps);
+			Collections.sort(jarFilesList);
+
+			if (jarFilesList.isEmpty()) {
+				panel.add(new JLabel("<html><small>To depend on a JAR file, "
+					+ "copy it to the above-mentioned folder.</small></html>"));
+				return panel;
+			}
+
+			for (String jarFile : jarFilesList) {
+				JCheckBox checkBox = new JCheckBox(jarFile);
+				// Has it already been selected in some previous configuring?
+				checkBox.setSelected(localDependencies.contains(jarFile));
+				checkBox.addItemListener(new ItemListener() {
+					@Override
+					public void itemStateChanged(ItemEvent e) {
+						JCheckBox box = (JCheckBox) e.getSource();
+						if (e.getStateChange() == SELECTED)
+							localDependencies.add(box.getText());
+						else if (e.getStateChange() == DESELECTED)
+							localDependencies.remove(box.getText());
+						updateWarning();
+					}
+				});
+				panel.add(checkBox);
+				// The jar may not be in the lib directory, so warn the user
+				if (!new File(libDir, jarFile).exists()) {
+					checkBox.setForeground(RED);
+					checkBox.setText(checkBox.getText() + " (missing file!)");
+				}
+			}
+			return panel;
+		}
+	}
+
+	public static class FileExtFilter implements FilenameFilter {
+		final String ext;
+
+		public FileExtFilter(String ext) {
+			this.ext = ext;
+		}
+
+		@Override
+		public boolean accept(File dir, String name) {
+			return name.endsWith(ext);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/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
new file mode 100644
index 0000000..c0e3aab
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ListConfigurationComponent.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * 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/52fd79dd/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
new file mode 100644
index 0000000..0ce35b5
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ListLayout.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * 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/52fd79dd/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
new file mode 100644
index 0000000..19cd180
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/MultiPageActivityConfigurationPanel.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * 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 uk.org.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/52fd79dd/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
new file mode 100644
index 0000000..8cb7652
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ScriptConfigurationComponent.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * 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/52fd79dd/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
new file mode 100644
index 0000000..cf1ff96
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ValidatingTextField.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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/52fd79dd/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
new file mode 100644
index 0000000..7597f7c
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/ValidatingTextGroup.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * 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/52fd79dd/taverna-contextual-views-api/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.zaria.UIComponentFactorySPI
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-api/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.zaria.UIComponentFactorySPI b/taverna-contextual-views-api/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.zaria.UIComponentFactorySPI
new file mode 100644
index 0000000..312f95b
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.zaria.UIComponentFactorySPI
@@ -0,0 +1,2 @@
+#net.sf.taverna.t2.workbench.ui.actions.activity.draggable.ActivityDraggerPaletteComponentFactory
+#net.sf.taverna.t2.workbench.ui.views.contextualviews.DragActivitiesToHereComponentFactory

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-api/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.zaria.UIComponentSPI
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-api/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.zaria.UIComponentSPI b/taverna-contextual-views-api/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.zaria.UIComponentSPI
new file mode 100644
index 0000000..1448a49
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.zaria.UIComponentSPI
@@ -0,0 +1,3 @@
+#net.sf.taverna.t2.workbench.ui.actions.activity.draggable.ActivityDraggerPaletteComponent
+#net.sf.taverna.t2.workbench.ui.views.contextualviews.DragActivitiesToHereComponent
+net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualViewComponent

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-api/src/main/resources/META-INF/spring/contextual-views-api-context-osgi.xml
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-api/src/main/resources/META-INF/spring/contextual-views-api-context-osgi.xml b/taverna-contextual-views-api/src/main/resources/META-INF/spring/contextual-views-api-context-osgi.xml
new file mode 100644
index 0000000..ab22b97
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/resources/META-INF/spring/contextual-views-api-context-osgi.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:beans="http://www.springframework.org/schema/beans"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd
+                      http://www.springframework.org/schema/osgi
+                      http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+</beans:beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-api/src/main/resources/META-INF/spring/contextual-views-api-context.xml
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-api/src/main/resources/META-INF/spring/contextual-views-api-context.xml b/taverna-contextual-views-api/src/main/resources/META-INF/spring/contextual-views-api-context.xml
new file mode 100644
index 0000000..d662d87
--- /dev/null
+++ b/taverna-contextual-views-api/src/main/resources/META-INF/spring/contextual-views-api-context.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-impl/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-impl/pom.xml b/taverna-contextual-views-impl/pom.xml
new file mode 100644
index 0000000..c0398e9
--- /dev/null
+++ b/taverna-contextual-views-impl/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.workbench</groupId>
+		<artifactId>taverna-workbench</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-contextual-views-impl</artifactId>
+	<packaging>bundle</packaging>
+	<name>Apache Taverna Contextual Views Impl</name>
+	<description>Contextual views for the activities</description>
+	<dependencies>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-contextual-views-api</artifactId>
+			<version>${project.parent.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-selection-api</artifactId>
+			<version>${project.parent.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-api</artifactId>
+			<version>${taverna.language.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>javax.help</groupId>
+			<artifactId>javahelp</artifactId>
+			<version>${javahelp.version}</version>
+		</dependency>
+
+	</dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/impl/ContextualViewFactoryRegistryImpl.java
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/impl/ContextualViewFactoryRegistryImpl.java b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/impl/ContextualViewFactoryRegistryImpl.java
new file mode 100644
index 0000000..8bac354
--- /dev/null
+++ b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/activity/impl/ContextualViewFactoryRegistryImpl.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+
+/**
+ * @author Alan R Williams
+ */
+package net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactoryRegistry;
+
+/**
+ * An SPI registry for discovering ActivityViewFactories for a given object,
+ * like an {@link net.sf.taverna.t2.workflowmodel.processor.activity.Activity}.
+ * <p>
+ * For {@link ContextualViewFactory factories} to be found, its full qualified
+ * name needs to be defined as a resource file
+ * <code>/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualViewFactory</code>
+ * 
+ * @author Stuart Owen
+ * @author Ian Dunlop
+ * @author Stian Soiland-Reyes
+ * 
+ * @see ContextualViewFactory
+ */
+public class ContextualViewFactoryRegistryImpl implements
+		ContextualViewFactoryRegistry {
+	private List<ContextualViewFactory<?>> contextualViewFactories;
+
+	/**
+	 * 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)
+	 */
+	@Override
+	public List<ContextualViewFactory<?>> getViewFactoriesForObject(
+			Object object) {
+		List<ContextualViewFactory<?>> result = new ArrayList<>();
+		for (ContextualViewFactory<?> factory : contextualViewFactories)
+			if (factory.canHandle(object))
+				result.add(factory);
+		return result;
+	}
+
+	public void setContextualViewFactories(
+			List<ContextualViewFactory<?>> contextualViewFactories) {
+		this.contextualViewFactories = contextualViewFactories;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/annotated/AnnotatedContextualView.java
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/annotated/AnnotatedContextualView.java b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/annotated/AnnotatedContextualView.java
new file mode 100644
index 0000000..018a121
--- /dev/null
+++ b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/annotated/AnnotatedContextualView.java
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.ui.views.contextualviews.annotated;
+
+import static javax.swing.BoxLayout.Y_AXIS;
+
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+import java.util.regex.Pattern;
+
+import javax.swing.BoxLayout;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.TitledBorder;
+
+import net.sf.taverna.t2.annotation.Annotated;
+import net.sf.taverna.t2.annotation.AnnotationBeanSPI;
+import net.sf.taverna.t2.lang.ui.DialogTextArea;
+import net.sf.taverna.t2.workbench.edits.CompoundEdit;
+import net.sf.taverna.t2.workbench.edits.Edit;
+import net.sf.taverna.t2.workbench.edits.EditException;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.impl.ContextualViewComponent;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * This is a ContextualView that should be able to display and allow editing of
+ * Annotation information for any Annotated. At the moment it is only used for
+ * Dataflow.
+ * 
+ * @author Alan R Williams
+ */
+@SuppressWarnings("serial")
+class AnnotatedContextualView extends ContextualView {
+	private static final int WORKFLOW_NAME_LENGTH = 20;
+	public static final String VIEW_TITLE = "Annotations";
+	private final static String MISSING_VALUE = "Type here to give details";
+	private final static int DEFAULT_AREA_WIDTH = 60;
+	private final static int DEFAULT_AREA_ROWS = 8;
+
+	private static Logger logger = Logger
+			.getLogger(AnnotatedContextualView.class);
+	private static PropertyResourceBundle prb = (PropertyResourceBundle) ResourceBundle
+			.getBundle("annotatedcontextualview");
+
+	// TODO convert to scufl2
+	// private static AnnotationTools annotationTools = new AnnotationTools();
+
+	/**
+	 * The object to which the Annotations apply
+	 */
+	private Annotated<?> annotated;
+	private SelectionManager selectionManager;
+	private EditManager editManager;
+	private boolean isStandalone = false;
+	private JPanel panel;
+	@SuppressWarnings("unused")
+	private final List<AnnotationBeanSPI> annotationBeans;
+
+	public AnnotatedContextualView(Annotated<?> annotated,
+			EditManager editManager, SelectionManager selectionManager,
+			List<AnnotationBeanSPI> annotationBeans) {
+		super();
+		this.editManager = editManager;
+		this.selectionManager = selectionManager;
+		this.annotationBeans = annotationBeans;
+		this.annotated = annotated;
+
+		initialise();
+		initView();
+	}
+
+	@Override
+	public void refreshView() {
+		initialise();
+	}
+
+	private void initialise() {
+		if (panel == null) {
+			panel = new JPanel();
+			panel.setLayout(new BoxLayout(panel, Y_AXIS));
+		} else
+			panel.removeAll();
+		populatePanel();
+		revalidate();
+	}
+
+	@Override
+	public JComponent getMainFrame() {
+		return panel;
+	}
+
+	@Override
+	public String getViewTitle() {
+		return VIEW_TITLE;
+	}
+
+	private Map<String,String> getAnnotations() {
+		// TODO convert to scufl2
+		Map<String, String> result = new HashMap<>();
+		//for (Class<?> c : annotationTools.getAnnotatingClasses(annotated)) {
+		// String name = "";
+		// try {
+		// name = prb.getString(c.getCanonicalName());
+		// } catch (MissingResourceException e) {
+		// name = c.getCanonicalName();
+		// }
+		// String value = annotationTools.getAnnotationString(annotated, c,
+		// MISSING_VALUE);
+		// result.put(name,value);
+		//}
+		return result;
+	}
+	public void populatePanel() {
+		JPanel scrollPanel = new JPanel();
+		scrollPanel.setLayout(new BoxLayout(scrollPanel, Y_AXIS));
+		panel.setBorder(new EmptyBorder(5, 5, 5, 5));
+		Map<String,String>annotations = getAnnotations();
+		for (String name : annotations.keySet()) {
+			JPanel subPanel = new JPanel();
+			subPanel.setBorder(new TitledBorder(name));
+			subPanel.add(createTextArea(String.class, annotations.get(name)));
+			scrollPanel.add(subPanel);
+		}
+		JScrollPane scrollPane = new JScrollPane(scrollPanel);
+		panel.add(scrollPane);
+	}
+
+	private JScrollPane createTextArea(Class<?> c, String value) {
+		DialogTextArea area = new DialogTextArea(value);
+		area.setFocusable(true);
+		area.addFocusListener(new TextAreaFocusListener(area, c));
+		area.setColumns(DEFAULT_AREA_WIDTH);
+		area.setRows(DEFAULT_AREA_ROWS);
+		area.setLineWrap(true);
+		area.setWrapStyleWord(true);
+
+		return new JScrollPane(area);
+	}
+
+	private class TextAreaFocusListener implements FocusListener {
+		String oldValue = null;
+		Class<?> annotationClass;
+		DialogTextArea area = null;
+
+		public TextAreaFocusListener(DialogTextArea area, Class<?> c) {
+			annotationClass = c;
+			oldValue = area.getText();
+			this.area = area;
+		}
+
+		@Override
+		public void focusGained(FocusEvent e) {
+			if (area.getText().equals(MISSING_VALUE))
+				area.setText("");
+		}
+
+		@Override
+		public void focusLost(FocusEvent e) {
+			String currentValue = area.getText();
+			if (currentValue.isEmpty() || currentValue.equals(MISSING_VALUE)) {
+				currentValue = MISSING_VALUE;
+				area.setText(currentValue);
+			}
+			if (!currentValue.equals(oldValue)) {
+				if (currentValue == MISSING_VALUE)
+					currentValue = "";
+				try {
+					WorkflowBundle currentDataflow = selectionManager
+							.getSelectedWorkflowBundle();
+					List<Edit<?>> editList = new ArrayList<>();
+					addWorkflowNameEdits(currentValue, currentDataflow,
+							editList);
+					if (!isStandalone)
+						ContextualViewComponent.selfGenerated = true;
+					editManager.doDataflowEdit(currentDataflow,
+							new CompoundEdit(editList));
+					ContextualViewComponent.selfGenerated = false;
+				} catch (EditException e1) {
+					logger.warn("Can't set annotation", e1);
+				}
+				oldValue = area.getText();
+			}
+		}
+
+		private boolean isTitleAnnotation() {
+			// TODO convert to scufl2
+			return prb.getString(annotationClass.getCanonicalName()).equals(
+					"Title");
+		}
+
+		// TODO convert to scufl2
+		private void addWorkflowNameEdits(String currentValue,
+				WorkflowBundle currentDataflow, List<Edit<?>> editList) {
+			//editList.add(annotationTools.setAnnotationString(annotated,
+			//		annotationClass, currentValue, edits));
+			if (annotated == currentDataflow && isTitleAnnotation()
+					&& !currentValue.isEmpty()) {
+				@SuppressWarnings("unused")
+				String sanitised = sanitiseName(currentValue);
+				//editList.add(edits.getUpdateDataflowNameEdit(currentDataflow,
+				//		sanitised));
+			}
+		}
+	}
+
+	/**
+	 * Checks that the name does not have any characters that are invalid for a
+	 * processor name.
+	 * <p>
+	 * The resulting name must contain only the chars [A-Za-z_0-9].
+	 * 
+	 * @param name
+	 *            the original name
+	 * @return the sanitised name
+	 */
+	private static String sanitiseName(String name) {
+		if (name.length() > WORKFLOW_NAME_LENGTH)
+			name = name.substring(0, WORKFLOW_NAME_LENGTH);
+		if (Pattern.matches("\\w++", name))
+			return name;
+		StringBuilder temp = new StringBuilder();
+		for (char c : name.toCharArray())
+			temp.append(Character.isLetterOrDigit(c) || c == '_' ? c : '_');
+		return temp.toString();
+	}
+
+	@Override
+	public int getPreferredPosition() {
+		return 500;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/annotated/AnnotatedContextualViewFactory.java
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/annotated/AnnotatedContextualViewFactory.java b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/annotated/AnnotatedContextualViewFactory.java
new file mode 100644
index 0000000..eb18803
--- /dev/null
+++ b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/annotated/AnnotatedContextualViewFactory.java
@@ -0,0 +1,43 @@
+package net.sf.taverna.t2.workbench.ui.views.contextualviews.annotated;
+
+import static java.util.Collections.singletonList;
+
+import java.util.List;
+
+import net.sf.taverna.t2.annotation.Annotated;
+import net.sf.taverna.t2.annotation.AnnotationBeanSPI;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory;
+import net.sf.taverna.t2.workflowmodel.processor.activity.Activity;
+
+public class AnnotatedContextualViewFactory implements
+		ContextualViewFactory<Annotated<?>> {
+	private EditManager editManager;
+	private List<AnnotationBeanSPI> annotationBeans;
+	private SelectionManager selectionManager;
+
+	@Override
+	public boolean canHandle(Object selection) {
+		return ((selection instanceof Annotated) && !(selection instanceof Activity));
+	}
+
+	@Override
+	public List<ContextualView> getViews(Annotated<?> selection) {
+		return singletonList((ContextualView) new AnnotatedContextualView(
+				selection, editManager, selectionManager, annotationBeans));
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setSelectionManager(SelectionManager selectionManager) {
+		this.selectionManager = selectionManager;
+	}
+
+	public void setAnnotationBeans(List<AnnotationBeanSPI> annotationBeans) {
+		this.annotationBeans = annotationBeans;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/condition/ConditionContextualView.java
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/condition/ConditionContextualView.java b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/condition/ConditionContextualView.java
new file mode 100644
index 0000000..f9308b5
--- /dev/null
+++ b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/condition/ConditionContextualView.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.ui.views.contextualviews.condition;
+
+import java.awt.FlowLayout;
+
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.border.EmptyBorder;
+
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import uk.org.taverna.scufl2.api.core.BlockingControlLink;
+
+/**
+ * Contextual view for dataflow's control (condition) links.
+ * 
+ * @author David Withers
+ */
+class ConditionContextualView extends ContextualView {
+	private static final long serialVersionUID = -894521200616176439L;
+
+	private final BlockingControlLink condition;
+	private JPanel contitionView;
+
+	public ConditionContextualView(BlockingControlLink condition) {
+		this.condition = condition;
+		initView();
+	}
+
+	@Override
+	public JComponent getMainFrame() {
+		refreshView();
+		return contitionView;
+	}
+
+	@Override
+	public String getViewTitle() {
+		return "Control link: " + condition.getBlock().getName()
+				+ " runs after " + condition.getUntilFinished().getName();
+	}
+
+	@Override
+	public void refreshView() {
+		contitionView = new JPanel(new FlowLayout(FlowLayout.LEFT));
+		contitionView.setBorder(new EmptyBorder(5, 5, 5, 5));
+		JLabel label = new JLabel(
+				"<html><body><i>No details available.</i></body><html>");
+		contitionView.add(label);
+	}
+
+	@Override
+	public int getPreferredPosition() {
+		return 100;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/condition/ConditionContextualViewFactory.java
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/condition/ConditionContextualViewFactory.java b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/condition/ConditionContextualViewFactory.java
new file mode 100644
index 0000000..ea69f1a
--- /dev/null
+++ b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/condition/ConditionContextualViewFactory.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.ui.views.contextualviews.condition;
+
+import static java.util.Arrays.asList;
+
+import java.util.List;
+
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory;
+import net.sf.taverna.t2.workflowmodel.Condition;
+import uk.org.taverna.scufl2.api.core.BlockingControlLink;
+
+/**
+ * A factory of contextual views for dataflow's condition links.
+ * 
+ * @author David Withers
+ * 
+ */
+public class ConditionContextualViewFactory implements
+		ContextualViewFactory<BlockingControlLink> {
+	@Override
+	public boolean canHandle(Object object) {
+		return object instanceof Condition;
+	}
+
+	@Override
+	public List<ContextualView> getViews(BlockingControlLink condition) {
+		return asList(new ContextualView[] { new ConditionContextualView(
+				condition) });
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/dataflow/DataflowContextualView.java
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/dataflow/DataflowContextualView.java b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/dataflow/DataflowContextualView.java
new file mode 100644
index 0000000..4a63868
--- /dev/null
+++ b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/dataflow/DataflowContextualView.java
@@ -0,0 +1,108 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.workbench.ui.views.contextualviews.dataflow;
+
+import static net.sf.taverna.t2.lang.ui.HtmlUtils.buildTableOpeningTag;
+import static net.sf.taverna.t2.lang.ui.HtmlUtils.createEditorPane;
+import static net.sf.taverna.t2.lang.ui.HtmlUtils.getHtmlHead;
+import static net.sf.taverna.t2.lang.ui.HtmlUtils.panelForHtml;
+
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workflowmodel.Dataflow;
+import uk.org.taverna.scufl2.api.core.Workflow;
+import uk.org.taverna.scufl2.api.port.InputWorkflowPort;
+import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;
+
+/**
+ * @author alanrw
+ */
+@SuppressWarnings("serial")
+class DataflowContextualView extends ContextualView {
+	private static int MAX_LENGTH = 50;
+	private static final String ELLIPSIS = "...";
+
+	private Workflow dataflow;
+	private JEditorPane editorPane;
+	private final FileManager fileManager;
+	private final ColourManager colourManager;
+
+	public DataflowContextualView(Workflow dataflow, FileManager fileManager,
+			ColourManager colourManager) {
+		this.dataflow = dataflow;
+		this.fileManager = fileManager;
+		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><td colspan=\"2\" align=\"center\"><b>Source</b></td></tr>");
+		String source = "Newly created";
+		if (fileManager.getDataflowSource(dataflow.getParent()) != null)
+			source = fileManager.getDataflowName(dataflow.getParent());
+
+		html.append("<tr><td colspan=\"2\" align=\"center\">").append(source)
+				.append("</td></tr>");
+		if (!dataflow.getInputPorts().isEmpty()) {
+			html.append("<tr><th>Input Port Name</th><th>Depth</th></tr>");
+			for (InputWorkflowPort dip : dataflow.getInputPorts())
+				html.append("<tr><td>")
+						.append(dip.getName())
+						.append("</td><td>")
+						.append(dip.getDepth() < 0 ? "invalid/unpredicted"
+								: dip.getDepth()).append("</td></tr>");
+		}
+		if (!dataflow.getOutputPorts().isEmpty()) {
+			html.append("<tr><th>Output Port Name</th><th>Depth</th></tr>");
+			for (OutputWorkflowPort dop : dataflow.getOutputPorts())
+				html.append("<tr><td>")
+						.append(dop.getName())
+						.append("</td><td>")
+						.append(/*(dop.getDepth() < 0 ?*/ "invalid/unpredicted" /*: dop.getDepth())*/)
+						.append("</td>" + "</tr>");
+		}
+
+		return html.append("</table>").append("</body></html>").toString();
+	}
+
+	public String getBackgroundColour() {
+		return colourManager.getDefaultPropertyMap().get(
+				Dataflow.class.toString());
+	}
+
+	@Override
+	public int getPreferredPosition() {
+		return 100;
+	}
+
+	private String limitName(String fullName) {
+		if (fullName.length() <= MAX_LENGTH)
+			return fullName;
+		return fullName.substring(0, MAX_LENGTH - ELLIPSIS.length()) + ELLIPSIS;
+	}
+
+	@Override
+	public String getViewTitle() {
+		return "Workflow " + limitName(dataflow.getName());
+	}
+
+	@Override
+	public void refreshView() {
+		editorPane.setText(buildHtml());
+		repaint();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/dataflow/DataflowContextualViewFactory.java
----------------------------------------------------------------------
diff --git a/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/dataflow/DataflowContextualViewFactory.java b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/dataflow/DataflowContextualViewFactory.java
new file mode 100644
index 0000000..0d7f3c0
--- /dev/null
+++ b/taverna-contextual-views-impl/src/main/java/net/sf/taverna/t2/workbench/ui/views/contextualviews/dataflow/DataflowContextualViewFactory.java
@@ -0,0 +1,41 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.workbench.ui.views.contextualviews.dataflow;
+
+import java.util.Arrays;
+import java.util.List;
+
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory;
+import uk.org.taverna.scufl2.api.core.Workflow;
+
+/**
+ * @author alanrw
+ */
+public class DataflowContextualViewFactory implements
+		ContextualViewFactory<Workflow> {
+	private FileManager fileManager;
+	private ColourManager colourManager;
+
+	@Override
+	public boolean canHandle(Object selection) {
+		return selection instanceof Workflow;
+	}
+
+	@Override
+	public List<ContextualView> getViews(Workflow selection) {
+		return Arrays.asList(new ContextualView[] {
+				new DataflowContextualView(selection, fileManager, colourManager)});
+	}
+
+	public void setFileManager(FileManager fileManager) {
+		this.fileManager = fileManager;
+	}
+
+	public void setColourManager(ColourManager colourManager) {
+		this.colourManager = colourManager;
+	}
+}