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/02/23 11:36:00 UTC

[45/58] [abbrv] incubator-taverna-plugin-component git commit: org.apache.taverna.component.ui

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentActivitySemanticAnnotationContextViewFactory.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentActivitySemanticAnnotationContextViewFactory.java b/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentActivitySemanticAnnotationContextViewFactory.java
deleted file mode 100644
index bf2942d..0000000
--- a/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentActivitySemanticAnnotationContextViewFactory.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package net.sf.taverna.t2.component.ui.view;
-
-import static org.apache.log4j.Logger.getLogger;
-import static org.apache.taverna.component.api.config.ComponentConfig.URI;
-
-import java.net.MalformedURLException;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-import org.apache.taverna.component.api.ComponentException;
-import org.apache.taverna.component.api.ComponentFactory;
-import org.apache.taverna.component.api.profile.Profile;
-
-import uk.org.taverna.scufl2.api.activity.Activity;
-import uk.org.taverna.scufl2.api.core.Workflow;
-import uk.org.taverna.scufl2.api.port.InputActivityPort;
-import uk.org.taverna.scufl2.api.port.InputWorkflowPort;
-import uk.org.taverna.scufl2.api.port.OutputActivityPort;
-import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;
-import uk.org.taverna.scufl2.api.port.Port;
-import net.sf.taverna.t2.component.annotation.AbstractSemanticAnnotationContextualView;
-import net.sf.taverna.t2.component.ui.ComponentActivityConfigurationBean;
-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;
-
-public class ComponentActivitySemanticAnnotationContextViewFactory implements
-		ContextualViewFactory<Object> {
-	public static final String VIEW_TITLE = "Inherited Semantic Annotations";
-	private static final Logger logger = getLogger(ComponentActivitySemanticAnnotationContextViewFactory.class);
-
-	private FileManager fm;
-	private ComponentFactory factory;
-
-	public void setFileManager(FileManager fm) {
-		this.fm = fm;
-	}
-
-	public void setComponentFactory(ComponentFactory factory) {
-		this.factory = factory;
-	}
-
-	@Override
-	public boolean canHandle(Object selection) {
-		return getContainingComponentActivity(selection) != null;
-	}
-
-	public Activity getContainingComponentActivity(Object selection) {
-		if (selection instanceof Activity) {
-			Activity a = (Activity) selection;
-			if (a.getType().equals(URI))
-				return a;
-		}
-		if (selection instanceof InputActivityPort
-				|| selection instanceof OutputActivityPort)
-			return getContainingComponentActivity(((OutputActivityPort) selection)
-					.getParent());
-		return null;
-	}
-
-	@Override
-	public List<ContextualView> getViews(Object selection) {
-		return Arrays
-				.<ContextualView> asList(new SemanticAnnotationCV(
-						selection));
-	}
-
-	@SuppressWarnings("serial")
-	private class SemanticAnnotationCV extends
-			AbstractSemanticAnnotationContextualView {
-		private Profile componentProfile;
-
-		public SemanticAnnotationCV(Object selection) {
-			super(fm, false);
-			Activity componentActivity = getContainingComponentActivity(selection);
-			try {
-				ComponentActivityConfigurationBean configuration = new ComponentActivityConfigurationBean(
-						componentActivity.getConfiguration(), factory);
-				setAnnotatedThing(selection, configuration.getVersion()
-						.getImplementation().getMainWorkflow());
-				componentProfile = configuration.getComponent().getFamily()
-						.getComponentProfile();
-				setProfile(selection);
-				super.initialise();
-			} catch (ComponentException e) {
-				logger.error("problem querying registry", e);
-			} catch (MalformedURLException e) {
-				logger.error("malformed URL in component description", e);
-			}
-		}
-
-		private void setAnnotatedThing(Object selection,
-				Workflow underlyingDataflow) {
-			if (selection instanceof Activity) {
-				setAnnotated(underlyingDataflow);
-			} else if (selection instanceof InputActivityPort) {
-				String name = ((Port) selection).getName();
-				for (InputWorkflowPort dip : underlyingDataflow.getInputPorts())
-					if (dip.getName().equals(name)) {
-						setAnnotated(dip);
-						break;
-					}
-			} else if (selection instanceof OutputActivityPort) {
-				String name = ((Port) selection).getName();
-				for (OutputWorkflowPort dop : underlyingDataflow
-						.getOutputPorts())
-					if (dop.getName().equals(name)) {
-						setAnnotated(dop);
-						break;
-					}
-			}
-		}
-
-		private void setProfile(Object selection) throws ComponentException {
-			if (componentProfile == null)
-				return;
-			if (selection instanceof Activity) {
-				setSemanticAnnotationProfiles(componentProfile
-						.getSemanticAnnotations());
-			} else if (selection instanceof InputActivityPort) {
-				setSemanticAnnotationProfiles(componentProfile
-						.getInputSemanticAnnotationProfiles());
-			} else if (selection instanceof OutputActivityPort) {
-				setSemanticAnnotationProfiles(componentProfile
-						.getOutputSemanticAnnotationProfiles());
-			}
-		}
-		
-		@Override
-		public String getViewTitle() {
-			return VIEW_TITLE;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentActivitySemanticAnnotationPanel.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentActivitySemanticAnnotationPanel.java b/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentActivitySemanticAnnotationPanel.java
deleted file mode 100644
index 7ab8f04..0000000
--- a/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentActivitySemanticAnnotationPanel.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package net.sf.taverna.t2.component.ui.view;
-
-import static java.awt.Color.GRAY;
-import static java.awt.Color.WHITE;
-import static java.awt.GridBagConstraints.BOTH;
-import static java.awt.GridBagConstraints.EAST;
-import static java.awt.GridBagConstraints.HORIZONTAL;
-import static java.awt.GridBagConstraints.SOUTHEAST;
-import static java.lang.String.format;
-import static net.sf.taverna.t2.component.annotation.SemanticAnnotationUtils.getDisplayName;
-import static net.sf.taverna.t2.component.annotation.SemanticAnnotationUtils.getObjectName;
-
-import java.awt.Component;
-import java.awt.Graphics;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.util.Set;
-
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JTextArea;
-import javax.swing.border.AbstractBorder;
-import javax.swing.border.EmptyBorder;
-
-import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
-
-import com.hp.hpl.jena.ontology.OntProperty;
-import com.hp.hpl.jena.rdf.model.Statement;
-
-public class ComponentActivitySemanticAnnotationPanel extends JPanel {
-	private static final long serialVersionUID = 3599768150252711758L;
-	private static final String ANNTYPE_MSG = "Annotation type : %s";
-	private static final String NONE_MSG = "No semantic annotations";	
-	private SemanticAnnotationProfile profile;
-	private final Set<Statement> statements;
-
-	public ComponentActivitySemanticAnnotationPanel(
-			SemanticAnnotationProfile profile, Set<Statement> statements) {
-		this.profile = profile;
-		this.statements = statements;
-		initialize();
-	}
-
-	private void initialize() {
-		setLayout(new GridBagLayout());
-		setBorder(new AbstractBorder() {
-			private static final long serialVersionUID = -5921448975807056953L;
-
-			@Override
-			public void paintBorder(Component c, Graphics g, int x, int y,
-					int width, int height) {
-				g.setColor(GRAY);
-				g.drawLine(x, y + height - 1, x + width - 1, y + height - 1);
-			}
-		});
-
-		GridBagConstraints c = new GridBagConstraints();
-		c.anchor = SOUTHEAST;
-		c.fill = BOTH;
-		c.weightx = 1;
-		c.gridx = 0;
-
-		OntProperty predicate = profile.getPredicate();
-		c.gridwidth = 2;
-		JLabel label = new JLabel(format(ANNTYPE_MSG, getDisplayName(predicate)));
-		label.setBorder(new EmptyBorder(5, 5, 5, 5));
-		label.setBackground(WHITE);
-		label.setOpaque(true);
-		add(label, c);
-
-		c.insets = new Insets(5, 7, 0, 0);
-		c.anchor = EAST;
-		c.fill = HORIZONTAL;
-		if (statements.isEmpty()) {
-			c.gridwidth = 2;
-			// c.weightx = 1;
-			// c.gridy++;
-			add(new JLabel(NONE_MSG), c);
-		} else {
-			c.gridwidth = 1;
-			for (Statement statement : statements) {
-				c.gridx = 0;
-				c.weightx = 1;
-				JTextArea value = new JTextArea(getObjectName(statement));
-				value.setBackground(WHITE);
-				value.setOpaque(true);
-				value.setBorder(new EmptyBorder(2, 4, 2, 4));
-				add(value, c);
-			}
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentContextViewFactory.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentContextViewFactory.java b/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentContextViewFactory.java
deleted file mode 100644
index f81d608..0000000
--- a/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentContextViewFactory.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.sf.taverna.t2.component.ui.view;
-
-import static org.apache.taverna.component.api.config.ComponentConfig.URI;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.taverna.component.api.Version;
-
-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.activity.Activity;
-import uk.org.taverna.scufl2.api.container.WorkflowBundle;
-
-public class ComponentContextViewFactory implements
-		ContextualViewFactory<WorkflowBundle> {
-	private FileManager fileManager;
-
-	public void setFileManager(FileManager fileManager) {
-		this.fileManager = fileManager;
-	}
-
-	@Override
-	public boolean canHandle(Object selection) {
-		if (selection instanceof WorkflowBundle) {
-			Object dataflowSource = fileManager
-					.getDataflowSource((WorkflowBundle) selection);
-			//FIXME Is this right?
-			return dataflowSource instanceof Version.ID;
-		}
-		return selection instanceof Activity
-				&& ((Activity) selection).getType().equals(URI);
-	}
-
-	@Override
-	public List<ContextualView> getViews(WorkflowBundle selection) {
-		Object dataflowSource = fileManager.getDataflowSource(selection);
-		return Arrays.<ContextualView> asList(new ComponentContextualView(
-				(Version.ID) dataflowSource));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentContextualView.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentContextualView.java b/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentContextualView.java
deleted file mode 100644
index acc1cc3..0000000
--- a/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ComponentContextualView.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package net.sf.taverna.t2.component.ui.view;
-
-import static java.lang.String.format;
-//import static net.sf.taverna.t2.component.ui.view.ViewUtil.getRawTablesHtml;
-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 java.awt.Color;
-
-import javax.swing.JComponent;
-import javax.swing.JEditorPane;
-
-import org.apache.taverna.component.api.Version;
-
-import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
-import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
-
-@SuppressWarnings("serial")
-public class ComponentContextualView extends ContextualView {
-	private JEditorPane editorPane;
-	private final Version.ID component;
-	ColourManager colourManager;//FIXME beaninject
-	ViewUtil viewUtils;//FIXME beaninject;
-
-	public ComponentContextualView(Version.ID component) {
-		this.component = component;
-		initView();
-	}
-
-	@Override
-	public JComponent getMainFrame() {
-		editorPane = createEditorPane(buildHtml());
-		return panelForHtml(editorPane);
-	}
-
-	private String buildHtml() {
-		StringBuilder html = new StringBuilder(getHtmlHead(getBackgroundColour()));
-		html.append(buildTableOpeningTag());
-		viewUtils.getRawTablesHtml(component, html);
-		return html.append("</table></body></html>").toString();
-	}
-
-	public String getBackgroundColour() {
-		Color colour = colourManager.getPreferredColour(
-				"net.sf.taverna.t2.component.registry.Component");
-		return format("#%1$2x%2$2x%3$2x", colour.getRed(), colour.getGreen(),
-				colour.getBlue());
-	}
-
-	@Override
-	public int getPreferredPosition() {
-		return 50;
-	}
-
-	private static int MAX_LENGTH = 50;
-
-	private String limitName(String fullName) {
-		if (fullName.length() > MAX_LENGTH)
-			return fullName.substring(0, MAX_LENGTH - 3) + "...";
-		return fullName;
-	}
-
-	@Override
-	public String getViewTitle() {
-		return "Component " + limitName(component.getComponentName());
-	}
-
-	@Override
-	public void refreshView() {
-		editorPane.setText(buildHtml());
-		repaint();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ViewUtil.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ViewUtil.java b/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ViewUtil.java
deleted file mode 100644
index 7e87e7e..0000000
--- a/taverna-component-activity-ui/src/main/java/net/sf/taverna/t2/component/ui/view/ViewUtil.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/**
- * 
- */
-package net.sf.taverna.t2.component.ui.view;
-
-import static java.lang.String.format;
-import static org.apache.log4j.Logger.getLogger;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Set;
-
-import net.sf.taverna.t2.component.ui.ComponentActivityConfigurationBean;
-
-import org.apache.log4j.Logger;
-import org.apache.taverna.component.api.Component;
-import org.apache.taverna.component.api.ComponentFactory;
-import org.apache.taverna.component.api.Family;
-import org.apache.taverna.component.api.Version;
-
-import uk.org.taverna.scufl2.api.configurations.Configuration;
-import uk.org.taverna.scufl2.api.container.WorkflowBundle;
-import uk.org.taverna.scufl2.api.port.InputWorkflowPort;
-import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;
-
-/**
- * @author alanrw
- */
-public class ViewUtil {
-	private static Logger logger = getLogger(ViewUtil.class);
-
-	private static final String VERSION_DESCRIPTION_LABEL = "Component version description";
-	private static final String COMPONENT_DESCRIPTION_LABEL = "Component description";
-	private static final String FAMILY_DESCRIPTION_LABEL = "Family description";
-
-	private static final String plainFormat = "<tr><td><b>%1$s</b></td><td nowrap=\"wrap\" style=\"width:100px;\">%2$s</td></tr>";
-	private static final String headerFormat = "<tr><th>%1$s</th><th>%2$s</th></tr>";
-	private static final String rowFormat = "<tr><td><b>%1$s</b></td><td>%2$s</td></tr>";
-	private static final String rowLinkFormat = "<tr><td><b>%1$s</b></td><td><a href=\"%3$s\">%2$s</a></td></tr>";
-	private static final String descriptionFormat = "<tr><td colspan=\"2\"><b>%1$s</b></td></tr><tr><td colspan=\"2\" nowrap=\"wrap\" style=\"width:100px;\">%2$s</td></tr>";
-
-	private ComponentFactory factory;//FIXME beaninject
-
-	public void setComponentFactory(ComponentFactory factory) {
-		this.factory = factory;
-	}
-
-	public String getRawTablesHtml(Version.ID id) {
-		StringBuilder html = new StringBuilder();
-		getRawTablesHtml(id, html);
-		return html.toString();
-	}
-
-	public String getRawTablesHtml(Configuration config) throws MalformedURLException {
-		StringBuilder html = new StringBuilder();
-		getRawTablesHtml(
-				new ComponentActivityConfigurationBean(
-						config.getJsonAsObjectNode(), factory), html);
-		return html.toString();
-	}
-
-	public void getRawTablesHtml(Version.ID id, StringBuilder html) {
-		URL registryBase = id.getRegistryBase();
-		String registryLink = null;
-		if (registryBase.getProtocol().startsWith("http"))
-			registryLink = registryBase.toExternalForm();
-		/*
-		 * \u200b is a zero-width space, so the HTML renderer can know to break
-		 * lines.
-		 */
-		String registryName = registryBase.toString().replaceAll("/", "\u200b/");
-		appendRow(html, "Component registry base", registryName, registryLink);
-
-		String familyName = id.getFamilyName();
-		appendRow(html, "Component family", familyName, null);
-		try {
-			Family family = factory.getFamily(registryBase, familyName);
-			if (family != null)
-				appendDescriptionHtml(html, FAMILY_DESCRIPTION_LABEL,
-						family.getDescription());
-		} catch (Exception e) {
-			logger.error("failed to get component family description", e);
-		}
-
-		String componentName = id.getComponentName();
-		String helpLink = null;
-		try {
-			URL helpURL = factory.getVersion(id).getHelpURL();
-			if (helpURL != null)
-				helpLink = helpURL.toExternalForm();
-		} catch (Exception e) {
-			logger.error(e);
-		}
-
-		appendRow(html, "Component name", componentName, helpLink);
-		try {
-			Component component = factory.getComponent(registryBase,
-					familyName, componentName);
-			if (component != null)
-				appendDescriptionHtml(html, COMPONENT_DESCRIPTION_LABEL,
-						component.getDescription());
-		} catch (Exception e) {
-			logger.error("failed to get component description", e);
-		}
-
-		Integer componentVersion = id.getComponentVersion();
-
-		if (componentVersion == null)
-			appendRow(html, "Component version", "N/A", helpLink);
-		else {
-			appendRow(html, "Component version", componentVersion, helpLink);
-			try {
-				Version version = factory.getVersion(registryBase,
-						familyName, componentName, componentVersion);
-				if (version != null) {
-					appendDescriptionHtml(html, VERSION_DESCRIPTION_LABEL,
-							version.getDescription());
-					WorkflowBundle impl = version.getImplementation();
-					Set<InputWorkflowPort> inputs = impl.getMainWorkflow().getInputPorts();
-					if (!inputs.isEmpty()) {
-						appendHeaderRow(html, "Input Port Name", "Depth");
-						for (InputWorkflowPort input : inputs)
-							appendPlainRow(html, input.getName(), input.getDepth());
-					}
-					Set<OutputWorkflowPort> outputs = impl.getMainWorkflow().getOutputPorts();
-					if (!outputs.isEmpty()) {
-						appendHeaderRow(html, "Output Port Name", "Depth");
-						for (OutputWorkflowPort output : outputs) {
-							//FIXME get depth of output ports!
-							appendPlainRow(html, output.getName(), -1 /*output.getDepth()*/);
-						}
-					}
-				}
-			} catch (Exception e) {
-				logger.error("failed to get component version description", e);
-			}
-		}
-	}
-
-	private static void appendRow(StringBuilder html, Object label,
-			Object value, String link) {
-		if (link == null)
-			html.append(format(rowFormat, label, value));
-		else
-			html.append(format(rowLinkFormat, label, value, link));
-	}
-
-	private static void appendHeaderRow(StringBuilder html, Object label1,
-			Object label2) {
-		html.append(format(headerFormat, label1, label2));
-	}
-
-	private static void appendPlainRow(StringBuilder html, Object value1,
-			Object value2) {
-		html.append(format(plainFormat, value1, value2));
-	}
-
-	private static void appendDescriptionHtml(StringBuilder html,
-			String header, String description) {
-		if ((description != null) && !description.isEmpty())
-			html.append(format(descriptionFormat, header, description));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/ComponentAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/ComponentAction.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/ComponentAction.java
new file mode 100644
index 0000000..0996620
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/ComponentAction.java
@@ -0,0 +1,48 @@
+package org.apache.taverna.component.ui;
+
+import static java.awt.Color.RED;
+import static javax.swing.SwingUtilities.invokeLater;
+import static org.apache.log4j.Logger.getLogger;
+
+import javax.swing.AbstractAction;
+
+import net.sf.taverna.t2.workbench.models.graph.GraphController;
+import net.sf.taverna.t2.workbench.models.graph.svg.SVGGraph;
+import net.sf.taverna.t2.workbench.views.graph.GraphViewComponent;
+
+import org.apache.log4j.Logger;
+import org.apache.taverna.component.ui.serviceprovider.ComponentServiceIcon;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+@SuppressWarnings("serial")
+public abstract class ComponentAction extends AbstractAction {
+	private static Logger logger = getLogger(ComponentAction.class);
+
+	protected GraphViewComponent graphView;
+
+	protected ComponentAction(String title, GraphViewComponent graphView) {
+		this.graphView = graphView;
+	}
+
+	public void setIcon(ComponentServiceIcon icon) {
+        putValue(SMALL_ICON, icon.getIcon());
+	}
+
+	protected void markGraphAsBelongingToComponent(WorkflowBundle bundle) {
+		final GraphController gc = graphView.getGraphController(bundle
+				.getMainWorkflow());
+		invokeLater(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					SVGGraph g = (SVGGraph) gc.getGraph();
+					g.setFillColor(RED);
+					gc.redraw();
+				} catch (NullPointerException e) {
+					logger.error(e);
+				}
+			}
+		});
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/ComponentActivityConfigurationBean.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/ComponentActivityConfigurationBean.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/ComponentActivityConfigurationBean.java
new file mode 100644
index 0000000..f0adfd5
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/ComponentActivityConfigurationBean.java
@@ -0,0 +1,165 @@
+package org.apache.taverna.component.ui;
+
+import static org.apache.log4j.Logger.getLogger;
+import static org.apache.taverna.component.api.config.ComponentPropertyNames.COMPONENT_NAME;
+import static org.apache.taverna.component.api.config.ComponentPropertyNames.COMPONENT_VERSION;
+import static org.apache.taverna.component.api.config.ComponentPropertyNames.FAMILY_NAME;
+import static org.apache.taverna.component.api.config.ComponentPropertyNames.REGISTRY_BASE;
+import static org.apache.taverna.component.ui.ComponentConstants.ACTIVITY_URI;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.apache.taverna.component.api.Component;
+import org.apache.taverna.component.api.ComponentException;
+import org.apache.taverna.component.api.ComponentFactory;
+import org.apache.taverna.component.api.Version;
+import org.apache.taverna.component.api.config.ComponentPropertyNames;
+import org.apache.taverna.component.api.profile.ExceptionHandling;
+
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.configurations.Configuration;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.port.InputActivityPort;
+import uk.org.taverna.scufl2.api.port.InputWorkflowPort;
+import uk.org.taverna.scufl2.api.port.OutputActivityPort;
+import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Component activity configuration bean.
+ */
+public class ComponentActivityConfigurationBean extends Version.Identifier {
+	public static final String ERROR_CHANNEL = "error_channel";
+	public static final List<String> ignorableNames = Arrays
+			.asList(ERROR_CHANNEL);
+	private static final long serialVersionUID = 5774901665863468058L;
+	private static final Logger logger = getLogger(ComponentActivityConfigurationBean.class);
+
+	private ActivityPortsDefinitionBean ports = null;
+	private ComponentFactory factory;
+	private ExceptionHandling eh;
+
+	public ComponentActivityConfigurationBean(Version.ID toBeCopied,
+			ComponentFactory factory) {
+		super(toBeCopied.getRegistryBase(), toBeCopied.getFamilyName(),
+				toBeCopied.getComponentName(), toBeCopied.getComponentVersion());
+		this.factory = factory;
+		try {
+			getPorts();
+		} catch (ComponentException e) {
+			logger.error("failed to get component realization", e);
+		}
+	}
+
+	public ComponentActivityConfigurationBean(JsonNode json,
+			ComponentFactory factory) throws MalformedURLException {
+		super(getUrl(json), getFamily(json), getComponent(json),
+				getVersion(json));
+		this.factory = factory;
+	}
+
+	public ComponentActivityConfigurationBean(Configuration configuration,
+			ComponentFactory factory) throws MalformedURLException {
+		this(configuration.getJson(), factory);
+	}
+
+	private static URL getUrl(JsonNode json) throws MalformedURLException {
+		return new URL(json.get(REGISTRY_BASE).textValue());
+	}
+
+	private static String getFamily(JsonNode json) {
+		return json.get(FAMILY_NAME).textValue();
+	}
+
+	private static String getComponent(JsonNode json) {
+		return json.get(COMPONENT_NAME).textValue();
+	}
+
+	private static Integer getVersion(JsonNode json) {
+		JsonNode node = json.get(COMPONENT_VERSION);
+		if (node == null || !node.isInt())
+			return null;
+		return node.intValue();
+	}
+
+	public Component getComponent() throws ComponentException {
+		return factory.getComponent(getRegistryBase(), getFamilyName(),
+				getComponentName());
+	}
+
+	public Version getVersion() throws ComponentException {
+		return factory.getVersion(this);
+	}
+
+	private ActivityPortsDefinitionBean getPortsDefinition(WorkflowBundle w) {
+		ActivityPortsDefinitionBean result = new ActivityPortsDefinitionBean();
+
+		for (InputWorkflowPort iwp : w.getMainWorkflow().getInputPorts())
+			result.inputs.add(makeInputDefinition(iwp));
+		for (OutputWorkflowPort owp : w.getMainWorkflow().getOutputPorts())
+			result.outputs.add(makeOutputDefinition(getDepth(owp), owp.getName()));
+
+		try {
+			eh = factory.getFamily(getRegistryBase(), getFamilyName())
+					.getComponentProfile().getExceptionHandling();
+			if (eh != null)
+				result.outputs.add(makeOutputDefinition(1, ERROR_CHANNEL));
+		} catch (org.apache.taverna.component.api.ComponentException e) {
+			logger.error("failed to get exception handling for family", e);
+		}
+		return result;
+	}
+
+	private int getDepth(OutputWorkflowPort owp) {
+		return 0; //FIXME How to get the depth of an output?
+	}
+
+	private InputActivityPort makeInputDefinition(InputWorkflowPort dip) {
+		InputActivityPort port = new InputActivityPort();
+		port.setName(dip.getName());
+		port.setDepth(dip.getDepth());
+		return port;
+	}
+
+	private OutputActivityPort makeOutputDefinition(int depth, String name) {
+		OutputActivityPort port = new OutputActivityPort();
+		port.setName(name);
+		port.setDepth(depth);
+		port.setGranularDepth(depth);
+		return port;
+	}
+
+	/**
+	 * @return the ports
+	 */
+	public ActivityPortsDefinitionBean getPorts() throws ComponentException {
+		if (ports == null)
+			ports = getPortsDefinition(getVersion().getImplementation());
+		return ports;
+	}
+
+	public ExceptionHandling getExceptionHandling() {
+		return eh;
+	}
+
+	public void installConfiguration(Activity a) {
+		Configuration conf = a.createConfiguration(ACTIVITY_URI);
+		ObjectNode json = conf.getJsonAsObjectNode();
+		json.put(REGISTRY_BASE, getRegistryBase().toExternalForm());
+		json.put(FAMILY_NAME, getFamilyName());
+		json.put(COMPONENT_NAME, getComponentName());
+		json.put(COMPONENT_VERSION, getComponentVersion());
+	}
+
+	public static class ActivityPortsDefinitionBean {
+		public List<InputActivityPort> inputs = new ArrayList<>();
+		public List<OutputActivityPort> outputs = new ArrayList<>();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/ComponentConstants.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/ComponentConstants.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/ComponentConstants.java
new file mode 100644
index 0000000..4053489
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/ComponentConstants.java
@@ -0,0 +1,9 @@
+package org.apache.taverna.component.ui;
+
+import static java.net.URI.create;
+
+import java.net.URI;
+
+public interface ComponentConstants {
+	URI ACTIVITY_URI = create("http://ns.taverna.org.uk/2010/activity/component");
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/AbstractSemanticAnnotationContextualView.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/AbstractSemanticAnnotationContextualView.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/AbstractSemanticAnnotationContextualView.java
new file mode 100644
index 0000000..48f75f0
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/AbstractSemanticAnnotationContextualView.java
@@ -0,0 +1,281 @@
+/**
+ * 
+ */
+package org.apache.taverna.component.ui.annotation;
+
+import static java.awt.GridBagConstraints.HORIZONTAL;
+import static java.awt.GridBagConstraints.NORTHWEST;
+import static java.lang.String.CASE_INSENSITIVE_ORDER;
+import static org.apache.log4j.Logger.getLogger;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.createSemanticAnnotation;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.getDisplayName;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.ExecutionException;
+
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSeparator;
+import javax.swing.SwingWorker;
+
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+
+import org.apache.log4j.Logger;
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+
+import uk.org.taverna.scufl2.api.common.AbstractNamed;
+import uk.org.taverna.scufl2.api.common.Named;
+
+import com.hp.hpl.jena.ontology.OntProperty;
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Resource;
+import com.hp.hpl.jena.rdf.model.Statement;
+
+/**
+ * @author alanrw
+ */
+public abstract class AbstractSemanticAnnotationContextualView extends
+		ContextualView {
+	private static final long serialVersionUID = 3567849347002793442L;
+	private static final Logger logger = getLogger(SemanticAnnotationContextualView.class);
+
+	private final FileManager fileManager;
+
+	public AbstractSemanticAnnotationContextualView(FileManager fileManager,
+			boolean allowChange) {
+		super();
+		this.fileManager = fileManager;
+		this.allowChange = allowChange;
+	}
+
+	private final boolean allowChange;
+	private JPanel panel;
+	private AbstractNamed annotated;
+	private List<SemanticAnnotationProfile> semanticAnnotationProfiles;
+	private Model model;
+	private Resource subject;
+
+	private static Comparator<SemanticAnnotationProfile> comparator = new Comparator<SemanticAnnotationProfile>() {
+		@Override
+		public int compare(SemanticAnnotationProfile arg0,
+				SemanticAnnotationProfile arg1) {
+			String d0 = getDisplayName(arg0.getPredicate());
+			String d1 = getDisplayName(arg1.getPredicate());
+			return CASE_INSENSITIVE_ORDER.compare(d0, d1);
+		}
+	};
+
+	@Override
+	public JComponent getMainFrame() {
+		return panel;
+	}
+
+	@Override
+	public int getPreferredPosition() {
+		return 510;
+	}
+
+	protected final void initialise() {
+		populateModel();
+		if (panel == null)
+			panel = new JPanel(new GridBagLayout());
+		else
+			panel.removeAll();
+		populatePanel(panel);
+	}
+
+	public void removeStatement(Statement statement) {
+		model.remove(statement);
+		// populatePanel(panel);
+		updateSemanticAnnotation();
+	}
+
+	public void addStatement(Statement statement) {
+		model.add(statement);
+		// populatePanel(panel);
+		updateSemanticAnnotation();
+	}
+
+	public void changeStatement(Statement origStatement, OntProperty predicate,
+			RDFNode node) {
+		if (predicate == null)
+			return;
+		model.remove(origStatement);
+		model.add(subject, predicate, node);
+		// populatePanel(panel);
+		updateSemanticAnnotation();
+	}
+
+	public void addStatement(OntProperty predicate, RDFNode node) {
+		if (predicate == null)
+			return;
+		model.add(subject, predicate, node);
+		// populatePanel(panel);
+		updateSemanticAnnotation();
+	}
+
+	@Override
+	public void refreshView() {
+		populatePanel(panel);
+	}
+
+	// public void addModel(Model model) {
+	// this.model.add(model);
+	// initialise();
+	// updateSemanticAnnotation();
+	// }
+
+	public void updateSemanticAnnotation() {
+		try {
+			createSemanticAnnotation(fileManager.getCurrentDataflow(),
+					annotated, model);
+		} catch (IOException e) {
+			logger.error("failed to add semantic annotation", e);
+		}
+	}
+
+	public void setAnnotated(Named annotated) {
+		this.annotated = (AbstractNamed) annotated;
+	}
+
+	public void setSemanticAnnotationProfiles(
+			List<SemanticAnnotationProfile> profiles) {
+		this.semanticAnnotationProfiles = profiles;
+	}
+
+	public Model getModel() {
+		return model;
+	}
+
+	private void populateModel() {
+		this.model = SemanticAnnotationUtils.populateModel(fileManager
+				.getCurrentDataflow());
+		this.subject = model.createResource(annotated.getURI().toASCIIString());
+	}
+
+	public Named getAnnotated() {
+		return annotated;
+	}
+
+	private void populatePanel(JPanel panel) {
+		panel.removeAll();
+		GridBagConstraints gbc = new GridBagConstraints();
+		gbc.anchor = NORTHWEST;
+		gbc.fill = HORIZONTAL;
+		gbc.gridx = 0;
+		gbc.weightx = 1;
+		gbc.weighty = 0;
+		gbc.insets = new Insets(5, 5, 5, 5);
+		panel.add(new JLabel("Reading semantic annotations"), gbc);
+		revalidate();
+		initView();
+		new StatementsReader().execute();
+	}
+
+	private Set<Statement> listStatements(OntProperty predicate) {
+		if (predicate == null)
+			return Collections.emptySet();
+		return model.listStatements(subject, predicate, (RDFNode) null).toSet();
+	}
+
+	private void populateViewWithPredicates(GridBagConstraints gbc,
+			Map<SemanticAnnotationProfile, Set<Statement>> profileStatements,
+			Set<Statement> statements,
+			Set<SemanticAnnotationProfile> unresolvablePredicates) {
+		for (Entry<SemanticAnnotationProfile, Set<Statement>> entry : profileStatements
+				.entrySet()) {
+			panel.add(
+					new SemanticAnnotationPanel(this, entry.getKey(), entry
+							.getValue(), allowChange), gbc);
+			panel.add(new JSeparator(), gbc);
+		}
+		for (SemanticAnnotationProfile semanticAnnotationProfile : unresolvablePredicates) {
+			panel.add(
+					new UnresolveablePredicatePanel(semanticAnnotationProfile),
+					gbc);
+			panel.add(new JSeparator(), gbc);
+		}
+
+		if (semanticAnnotationProfiles.isEmpty())
+			panel.add(new JLabel("No annotations possible"), gbc);
+		for (Statement s : statements)
+			panel.add(new UnrecognizedStatementPanel(s), gbc);
+
+		gbc.weighty = 1;
+		panel.add(new JPanel(), gbc);
+	}
+
+	private class StatementsReader extends SwingWorker<Void, Object> {
+		private Map<SemanticAnnotationProfile, Set<Statement>> profileStatements = new TreeMap<>(
+				comparator);
+		private Set<Statement> statements;
+		private Set<SemanticAnnotationProfile> unresolvablePredicates = new HashSet<>();
+
+		@Override
+		protected Void doInBackground() throws Exception {
+			try {
+				parseStatements();
+			} catch (Exception e) {
+				logger.error("failed to parse annotation statements", e);
+				throw e;
+			}
+			return null;
+		}
+
+		private void parseStatements() {
+			statements = listStatements(null);
+			for (SemanticAnnotationProfile semanticAnnotationProfile : semanticAnnotationProfiles) {
+				OntProperty predicate = semanticAnnotationProfile
+						.getPredicate();
+				if (predicate == null) {
+					unresolvablePredicates.add(semanticAnnotationProfile);
+					continue;
+				}
+
+				Set<Statement> statementsWithPredicate = listStatements(predicate);
+				profileStatements.put(semanticAnnotationProfile,
+						statementsWithPredicate);
+				statements.removeAll(statementsWithPredicate);
+			}
+		}
+
+		@Override
+		protected void done() {
+			panel.removeAll();
+			GridBagConstraints gbc = new GridBagConstraints();
+			gbc.anchor = NORTHWEST;
+			gbc.fill = HORIZONTAL;
+			gbc.gridx = 0;
+			gbc.weightx = 1;
+			gbc.weighty = 0;
+			gbc.insets = new Insets(5, 5, 5, 5);
+
+			try {
+				get();
+				populateViewWithPredicates(gbc, profileStatements, statements,
+						unresolvablePredicates);
+			} catch (ExecutionException | InterruptedException e) {
+				logger.error(e);
+				panel.add(new JLabel("Unable to read semantic annotations"),
+						gbc);
+			}
+
+			revalidate();
+			initView();
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/AnnotateSemanticsMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/AnnotateSemanticsMenuAction.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/AnnotateSemanticsMenuAction.java
new file mode 100644
index 0000000..6249239
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/AnnotateSemanticsMenuAction.java
@@ -0,0 +1,101 @@
+/**
+ * 
+ */
+package org.apache.taverna.component.ui.annotation;
+
+import static java.awt.BorderLayout.CENTER;
+import static java.awt.BorderLayout.SOUTH;
+import static java.awt.FlowLayout.TRAILING;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.URI;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+
+import org.apache.taverna.component.api.ComponentFactory;
+import org.apache.taverna.component.api.Version;
+
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.common.AbstractNamed;
+import uk.org.taverna.scufl2.api.port.ActivityPort;
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+import net.sf.taverna.t2.ui.menu.AbstractContextualMenuAction;
+import net.sf.taverna.t2.workbench.file.FileManager;
+
+/**
+ * @author alanrw
+ */
+public class AnnotateSemanticsMenuAction extends AbstractContextualMenuAction {
+	private static final String ANNOTATE_SEMANTICS = "Annotate semantics...";
+	private static final URI configureSection = URI
+			.create("http://taverna.sf.net/2009/contextMenu/configure");
+	private FileManager fileManager;
+	private ComponentFactory factory;
+
+	public AnnotateSemanticsMenuAction() {
+		super(configureSection, 45);
+	}
+
+	public void setComponentFactory(ComponentFactory factory) {
+		this.factory = factory;
+	}
+
+	public void setFileManager(FileManager fm) {
+		this.fileManager = fm;
+	}
+
+	@Override
+	public boolean isEnabled() {
+		Object selection = getContextualSelection().getSelection();
+		Object dataflowSource = fileManager.getDataflowSource(fileManager
+				.getCurrentDataflow());
+		if (dataflowSource instanceof Version.ID)
+			return (selection instanceof AbstractNamed)
+					&& !(selection instanceof Activity || selection instanceof ActivityPort);
+		return false;
+	}
+
+	@SuppressWarnings("serial")
+	@Override
+	protected Action createAction() {
+		return new AbstractAction(ANNOTATE_SEMANTICS) {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				showAnnotateSemanticsPanel();
+			}
+		};
+	}
+
+	private void showAnnotateSemanticsPanel() {
+		SemanticAnnotationContextualView view = new SemanticAnnotationContextualView(
+				fileManager, factory, (AbstractNamed) getContextualSelection()
+						.getSelection());
+
+		final JDialog dialog = new JDialog((Frame) null, "Annotate semantics");
+		dialog.setLayout(new BorderLayout());
+		dialog.add(new JScrollPane(view), CENTER);
+
+		JPanel buttonPanel = new JPanel(new FlowLayout(TRAILING));
+		buttonPanel.add(new DeselectingButton("OK", new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				dialog.setVisible(false);
+			}
+		}));
+
+		dialog.add(buttonPanel, SOUTH);
+		dialog.setSize(new Dimension(400, 300));
+		dialog.setLocationRelativeTo(null);
+		dialog.setModal(true);
+		dialog.setVisible(true);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/AnnotationPropertyPanelFactory.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/AnnotationPropertyPanelFactory.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/AnnotationPropertyPanelFactory.java
new file mode 100644
index 0000000..a0ba024
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/AnnotationPropertyPanelFactory.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * 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 org.apache.taverna.component.ui.annotation;
+
+import static com.hp.hpl.jena.rdf.model.ResourceFactory.createTypedLiteral;
+import static java.lang.Integer.MIN_VALUE;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.getObjectName;
+
+import javax.swing.JComponent;
+import javax.swing.JTextArea;
+
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+
+import com.hp.hpl.jena.ontology.OntProperty;
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Statement;
+
+/**
+ * 
+ * 
+ * @author Alan Williams
+ */
+public class AnnotationPropertyPanelFactory extends PropertyPanelFactorySPI {
+	@Override
+	public JComponent getInputComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement) {
+		return getDefaultInputComponent(semanticAnnotationProfile, statement);
+	}
+
+	@Override
+	public RDFNode getNewTargetNode(Statement originalStatement,
+			JComponent component) {
+		String newText = ((JTextArea) component).getText();
+		if ((originalStatement == null)
+				|| !getObjectName(originalStatement).equals(newText))
+			return createTypedLiteral(newText);
+		return null;
+	}
+
+	@Override
+	public int getRatingForSemanticAnnotation(
+			SemanticAnnotationProfile semanticAnnotationProfile) {
+		OntProperty property = semanticAnnotationProfile.getPredicate();
+		if ((property != null) && property.isAnnotationProperty())
+			return 100;
+		return MIN_VALUE;
+	}
+
+	@Override
+	public JComponent getDisplayComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement) {
+		return getDefaultDisplayComponent(semanticAnnotationProfile, statement);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/DatatypePropertyPanelFactory.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/DatatypePropertyPanelFactory.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/DatatypePropertyPanelFactory.java
new file mode 100644
index 0000000..903e538
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/DatatypePropertyPanelFactory.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * 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 org.apache.taverna.component.ui.annotation;
+
+import static com.hp.hpl.jena.rdf.model.ResourceFactory.createTypedLiteral;
+import static java.lang.Integer.MIN_VALUE;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.getObjectName;
+
+import javax.swing.JComponent;
+import javax.swing.JTextArea;
+
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+
+import com.hp.hpl.jena.ontology.OntProperty;
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Statement;
+
+/**
+ * @author Alan Williams
+ */
+public class DatatypePropertyPanelFactory extends PropertyPanelFactorySPI {
+	public DatatypePropertyPanelFactory() {
+		super();
+	}
+
+	@Override
+	public JComponent getInputComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement) {
+		return getDefaultInputComponent(semanticAnnotationProfile, statement);
+	}
+
+	@Override
+	public RDFNode getNewTargetNode(Statement originalStatement,
+			JComponent component) {
+		JTextArea inputText = (JTextArea) component;
+		String newText = inputText.getText();
+		if ((originalStatement == null)
+				|| !getObjectName(originalStatement).equals(newText))
+			return createTypedLiteral(newText);
+		return null;
+	}
+
+	@Override
+	public int getRatingForSemanticAnnotation(
+			SemanticAnnotationProfile semanticAnnotationProfile) {
+		OntProperty property = semanticAnnotationProfile.getPredicate();
+		if ((property != null) && property.isDatatypeProperty())
+			return 100;
+		return MIN_VALUE;
+	}
+
+	@Override
+	public JComponent getDisplayComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement) {
+		return getDefaultDisplayComponent(semanticAnnotationProfile, statement);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/DateTimePropertyPanelFactory.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/DateTimePropertyPanelFactory.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/DateTimePropertyPanelFactory.java
new file mode 100644
index 0000000..78cd3b1
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/DateTimePropertyPanelFactory.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * 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 org.apache.taverna.component.ui.annotation;
+
+import static com.hp.hpl.jena.datatypes.xsd.XSDDatatype.XSDdateTime;
+import static com.hp.hpl.jena.rdf.model.ResourceFactory.createTypedLiteral;
+import static java.lang.Integer.MIN_VALUE;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import javax.swing.JComponent;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerDateModel;
+import javax.swing.text.DefaultCaret;
+
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+
+import com.hp.hpl.jena.datatypes.xsd.XSDDateTime;
+import com.hp.hpl.jena.ontology.OntProperty;
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Statement;
+
+/**
+ * 
+ * 
+ * @author Alan Williams
+ */
+public class DateTimePropertyPanelFactory extends PropertyPanelFactorySPI {
+
+	private static String DateTimeString = XSDdateTime.getURI();
+
+	public DateTimePropertyPanelFactory() {
+		super();
+	}
+
+	@Override
+	public JComponent getInputComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement) {
+		Date now = new Date();
+		SpinnerDateModel dateModel = new SpinnerDateModel(now, null, now,
+				Calendar.DAY_OF_MONTH);
+		JSpinner s = new JSpinner(dateModel);
+		JSpinner.DateEditor de = new JSpinner.DateEditor(s,
+				"yyyy-MM-dd-HH-mm-ss");
+
+		/*
+		 * Suggested hack from
+		 * http://www.coderanch.com/t/345684/GUI/java/JSpinner-DateEditor-Set-default-focus
+		 */
+
+		de.getTextField().setCaret(new DefaultCaret() {
+			private static final long serialVersionUID = 6779256780590610172L;
+			private boolean diverted = false;
+
+			@Override
+			public void setDot(int dot) {
+				diverted = (dot == 0);
+				if (diverted)
+					dot = getComponent().getDocument().getLength();
+				super.setDot(dot);
+			}
+
+			@Override
+			public void moveDot(int dot) {
+				if (diverted) {
+					super.setDot(0);
+					diverted = false;
+				}
+				super.moveDot(dot);
+			}
+		});
+		s.setEditor(de);
+		if (statement != null) {
+			Object o = statement.getObject().asLiteral().getValue();
+			if (o instanceof XSDDateTime)
+				dateModel.setValue(((XSDDateTime) o).asCalendar().getTime());
+		}
+		return s;
+	}
+
+	@Override
+	public RDFNode getNewTargetNode(Statement originalStatement,
+			JComponent component) {
+		JSpinner spinner = (JSpinner) component;
+		Date d = (Date) spinner.getValue();
+		if ((originalStatement == null)
+				|| !originalStatement.getObject().asLiteral().getValue()
+						.equals(d)) {
+			Calendar cal = GregorianCalendar.getInstance();
+			cal.setTime(d);
+			return createTypedLiteral(cal);
+		}
+		return null;
+	}
+
+	@Override
+	public int getRatingForSemanticAnnotation(
+			SemanticAnnotationProfile semanticAnnotationProfile) {
+		OntProperty property = semanticAnnotationProfile.getPredicate();
+		if ((property != null) && property.isDatatypeProperty()
+				&& DateTimeString.equals(semanticAnnotationProfile
+						.getClassString()))
+			return 200;
+		return MIN_VALUE;
+	}
+
+	@Override
+	public JComponent getDisplayComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement) {
+		JComponent result = getInputComponent(semanticAnnotationProfile,
+				statement);
+		result.setEnabled(false);
+		return result;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/FallbackPropertyPanelFactory.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/FallbackPropertyPanelFactory.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/FallbackPropertyPanelFactory.java
new file mode 100644
index 0000000..6078ba3
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/FallbackPropertyPanelFactory.java
@@ -0,0 +1,44 @@
+/**
+ * 
+ */
+package org.apache.taverna.component.ui.annotation;
+
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Statement;
+
+/**
+ * @author alanrw
+ */
+public class FallbackPropertyPanelFactory extends PropertyPanelFactorySPI {
+	@Override
+	public JComponent getInputComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement) {
+		return new JLabel("Unable to handle "
+				+ semanticAnnotationProfile.getPredicateString());
+	}
+
+	@Override
+	public RDFNode getNewTargetNode(Statement originalStatement,
+			JComponent component) {
+		return null;
+	}
+
+	@Override
+	public int getRatingForSemanticAnnotation(
+			SemanticAnnotationProfile semanticAnnotationProfile) {
+		return 0;
+	}
+
+	@Override
+	public JComponent getDisplayComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement) {
+		return getDefaultDisplayComponent(semanticAnnotationProfile, statement);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/GreyBorder.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/GreyBorder.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/GreyBorder.java
new file mode 100644
index 0000000..0f143d2
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/GreyBorder.java
@@ -0,0 +1,17 @@
+package org.apache.taverna.component.ui.annotation;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+
+import javax.swing.border.AbstractBorder;
+
+@SuppressWarnings("serial")
+class GreyBorder extends AbstractBorder {
+	@Override
+	public void paintBorder(Component c, Graphics g, int x, int y, int width,
+			int height) {
+		g.setColor(Color.GRAY);
+		g.drawLine(x, y + height - 1, x + width - 1, y + height - 1);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/ObjectPropertyWithIndividualsPanelFactory.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/ObjectPropertyWithIndividualsPanelFactory.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/ObjectPropertyWithIndividualsPanelFactory.java
new file mode 100644
index 0000000..9f8e9a6
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/ObjectPropertyWithIndividualsPanelFactory.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * 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 org.apache.taverna.component.ui.annotation;
+
+import static java.awt.FlowLayout.RIGHT;
+import static java.awt.GridBagConstraints.EAST;
+import static java.awt.GridBagConstraints.NORTHWEST;
+import static java.lang.Integer.MIN_VALUE;
+import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
+import static javax.swing.JOptionPane.OK_OPTION;
+import static javax.swing.JOptionPane.QUESTION_MESSAGE;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showInputDialog;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.getDisplayName;
+
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+import java.util.Vector;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.ListCellRenderer;
+
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+import org.apache.taverna.component.ui.localworld.LocalWorld;
+
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+
+import com.hp.hpl.jena.ontology.Individual;
+import com.hp.hpl.jena.ontology.OntClass;
+import com.hp.hpl.jena.ontology.OntModel;
+import com.hp.hpl.jena.ontology.OntProperty;
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Statement;
+
+/**
+ * @author David Withers
+ * @author Alan Williams
+ */
+public class ObjectPropertyWithIndividualsPanelFactory extends
+		PropertyPanelFactorySPI {
+	/*
+	 * TODO Consider what sort of sharing model is appropriate for the local
+	 * world
+	 */
+	private static LocalWorld localWorld = LocalWorld.getInstance();
+
+	@Override
+	public int getRatingForSemanticAnnotation(
+			SemanticAnnotationProfile semanticAnnotationProfile) {
+		OntProperty property = semanticAnnotationProfile.getPredicate();
+		if ((property != null) && property.isObjectProperty()
+				/*
+				 * && !semanticAnnotationProfile.getIndividuals().isEmpty()
+				 */)
+			return 100;
+		return MIN_VALUE;
+	}
+
+	@Override
+	public JComponent getInputComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement) {
+		return new ComboBoxWithAdd(semanticAnnotationProfile, statement);
+	}
+
+	@Override
+	public RDFNode getNewTargetNode(Statement originalStatement,
+			JComponent component) {
+		ComboBoxWithAdd panel = (ComboBoxWithAdd) component;
+		RDFNode newNode = panel.getSelectedItem();
+		if ((originalStatement == null)
+				|| !originalStatement.getObject().equals(newNode))
+			return newNode;
+		return null;
+	}
+
+
+	private static class ComboBoxWithAdd extends JPanel {
+		private static final long serialVersionUID = -9156213096428945270L;
+		private static DefaultListCellRenderer defaultRenderer = new DefaultListCellRenderer();
+		OntClass rangeClass = null;
+		JComboBox<Individual> resources;
+
+		public ComboBoxWithAdd(
+				SemanticAnnotationProfile semanticAnnotationProfile,
+				Statement statement) {
+			super(new GridBagLayout());
+
+			rangeClass = semanticAnnotationProfile.getRangeClass();
+
+			GridBagConstraints gbc = new GridBagConstraints();
+			gbc.gridx = 0;
+			gbc.gridy = 0;
+			gbc.anchor = NORTHWEST;
+			List<Individual> individuals = semanticAnnotationProfile
+					.getIndividuals();
+			if (rangeClass != null)
+				individuals
+						.addAll(localWorld.getIndividualsOfClass(rangeClass));
+
+			resources = new JComboBox<Individual>(new Vector<>(individuals));
+			resources.setRenderer(new ListCellRenderer<Individual>() {
+				@Override
+				public Component getListCellRendererComponent(
+						JList<? extends Individual> list, Individual value,
+						int index, boolean isSelected, boolean cellHasFocus) {
+					return defaultRenderer.getListCellRendererComponent(list,
+							getDisplayName(value), index, isSelected,
+							cellHasFocus);
+				}
+			});
+			resources.setEditable(false);
+			if (statement != null) {
+				Object origResource = statement.getObject();
+				if (origResource != null)
+					resources.setSelectedItem(origResource);
+			}
+			this.add(resources, gbc);
+
+			gbc.gridy++;
+
+			JPanel buttonPanel = new JPanel(new FlowLayout(RIGHT));
+			buttonPanel.add(new DeselectingButton("Add external",
+					new ActionListener() {
+						@Override
+						public void actionPerformed(ActionEvent e) {
+							addExternal();
+						}
+					}));
+			buttonPanel.add(new DeselectingButton("Add local",
+					new ActionListener() {
+						@Override
+						public void actionPerformed(ActionEvent e) {
+							addLocal();
+						}
+					}));
+			gbc.anchor = EAST;
+			this.add(buttonPanel, gbc);
+		}
+
+		private void addExternal() {
+			String answer = showInputDialog("Please enter the URL for the resource");
+			resources.addItem(localWorld.createIndividual(answer, rangeClass));
+		}
+
+		private void addLocal() {
+			TurtleInputPanel turtlePanel = new TurtleInputPanel(rangeClass);
+			if (showConfirmDialog(null, turtlePanel, "Turtle input",
+					OK_CANCEL_OPTION, QUESTION_MESSAGE) == OK_OPTION) {
+				OntModel addedModel = turtlePanel.getContentAsModel();
+				for (Individual i : addedModel.listIndividuals(rangeClass)
+						.toList())
+					resources.addItem(i);
+				localWorld.addModelFromString(turtlePanel.getContentAsString());
+			}
+		}
+
+		public RDFNode getSelectedItem() {
+			return (RDFNode) resources.getSelectedItem();
+		}
+	}
+
+	@Override
+	public JComponent getDisplayComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement) {
+		JComponent result = getDefaultDisplayComponent(
+				semanticAnnotationProfile, statement);
+		return result;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/PropertyPanelFactorySPI.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/PropertyPanelFactorySPI.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/PropertyPanelFactorySPI.java
new file mode 100644
index 0000000..2768b02
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/PropertyPanelFactorySPI.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * 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 org.apache.taverna.component.ui.annotation;
+
+import static java.awt.Color.WHITE;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.getObjectName;
+
+import javax.swing.JComponent;
+import javax.swing.JTextArea;
+import javax.swing.border.EmptyBorder;
+
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Statement;
+
+/**
+ * @author David Withers
+ */
+public abstract class PropertyPanelFactorySPI {
+	public abstract JComponent getInputComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement);
+
+	/**
+	 * Returns null if the target node is the same as the original statement
+	 * 
+	 * @param origStatement
+	 * @param inputComponent
+	 * @return
+	 */
+	public abstract RDFNode getNewTargetNode(Statement origStatement,
+			JComponent inputComponent);
+
+	public abstract int getRatingForSemanticAnnotation(
+			SemanticAnnotationProfile semanticAnnotationProfile);
+
+	public abstract JComponent getDisplayComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement);
+
+	public static JComponent getDefaultInputComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement) {
+		JTextArea inputText = new JTextArea(20, 80);
+		if (statement != null)
+			inputText.setText(getObjectName(statement));
+		inputText.setLineWrap(true);
+		inputText.setWrapStyleWord(true);
+		return inputText;
+	}
+
+	public static JComponent getDefaultDisplayComponent(
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Statement statement) {
+		JTextArea value = new JTextArea(getObjectName(statement));
+		value.setLineWrap(true);
+		value.setWrapStyleWord(true);
+		value.setEditable(false);
+		value.setBackground(WHITE);
+		value.setOpaque(true);
+		value.setBorder(new EmptyBorder(2, 4, 2, 4));
+		return value;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationContextualView.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationContextualView.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationContextualView.java
new file mode 100644
index 0000000..b32ac69
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationContextualView.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * 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 org.apache.taverna.component.ui.annotation;
+
+import static java.lang.String.format;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.taverna.t2.workbench.file.FileManager;
+
+import org.apache.log4j.Logger;
+import org.apache.taverna.component.api.ComponentException;
+import org.apache.taverna.component.api.ComponentFactory;
+import org.apache.taverna.component.api.Family;
+import org.apache.taverna.component.api.Registry;
+import org.apache.taverna.component.api.Version;
+import org.apache.taverna.component.api.profile.Profile;
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+
+import uk.org.taverna.scufl2.api.common.AbstractNamed;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.core.Processor;
+import uk.org.taverna.scufl2.api.core.Workflow;
+import uk.org.taverna.scufl2.api.port.InputWorkflowPort;
+import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;
+
+/**
+ * @author David Withers
+ */
+public class SemanticAnnotationContextualView extends
+		AbstractSemanticAnnotationContextualView {
+	private static final long serialVersionUID = -322165507536778154L;
+	public static final String VIEW_TITLE = "Semantic Annotations";
+	private static Logger logger = getLogger(SemanticAnnotationContextualView.class);
+
+	private final FileManager fileManager;
+	private final ComponentFactory factory;
+
+	public SemanticAnnotationContextualView(FileManager fileManager,
+			ComponentFactory factory, AbstractNamed selection) {
+		super(fileManager, true);
+		this.fileManager = fileManager;
+		this.factory = factory;
+		super.setAnnotated(selection);
+		List<SemanticAnnotationProfile> profiles = new ArrayList<>();
+		try {
+			Profile componentProfile = getComponentProfile();
+			if (componentProfile != null) {
+				if (selection instanceof Workflow
+						|| selection instanceof WorkflowBundle)
+					profiles = componentProfile.getSemanticAnnotations();
+				else if (selection instanceof InputWorkflowPort)
+					profiles = componentProfile
+							.getInputSemanticAnnotationProfiles();
+				else if (selection instanceof OutputWorkflowPort)
+					profiles = componentProfile
+							.getOutputSemanticAnnotationProfiles();
+				else if (selection instanceof Processor)
+					profiles = componentProfile
+							.getActivitySemanticAnnotationProfiles();
+			}
+		} catch (ComponentException e) {
+			logger.error("failed to look up semantic annotations", e);
+		}
+		super.setSemanticAnnotationProfiles(profiles);
+		super.initialise();
+	}
+
+	private Profile getComponentProfile() {
+		Object dataflowSource = fileManager.getDataflowSource(fileManager
+				.getCurrentDataflow());
+		if (dataflowSource instanceof Version.ID) {
+			Version.ID identification = (Version.ID) dataflowSource;
+			try {
+				Registry componentRegistry = factory.getRegistry(identification
+						.getRegistryBase());
+				Family componentFamily = componentRegistry
+						.getComponentFamily(identification.getFamilyName());
+				return componentFamily.getComponentProfile();
+			} catch (ComponentException e) {
+				logger.warn(
+						format("No component profile found for component family %s at component registry %s",
+								identification.getFamilyName(),
+								identification.getRegistryBase()), e);
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public String getViewTitle() {
+		return VIEW_TITLE;
+	}
+
+/*
+	public static void main(String[] args) throws Exception {
+		JFrame frame = new JFrame();
+		frame.setSize(400, 200);
+		ComponentVersionIdentification identification = new ComponentVersionIdentification(
+				new URL("http://sandbox.myexperiment.org"),
+				"SCAPE Migration Action Components", "Image To Tiff", 2);
+		Dataflow dataflow = fileManager.openDataflow(new ComponentFileType(),
+				identification);
+
+		Processor processor = edits.createProcessor("processor");
+		try {
+			editManager.doDataflowEdit(dataflow,
+					edits.getAddProcessorEdit(dataflow, processor));
+		} catch (EditException e) {
+			e.printStackTrace();
+		}
+		final SemanticAnnotationContextualView view = new SemanticAnnotationContextualView(
+				processor);
+		editManager.addObserver(new Observer<EditManager.EditManagerEvent>() {
+			@Override
+			public void notify(Observable<EditManagerEvent> arg0,
+					EditManagerEvent arg1) throws Exception {
+				view.refreshView();
+				view.repaint();
+			}
+		});
+		frame.add(view);
+		frame.setVisible(true);
+	}
+*/
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationContextualViewFactory.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationContextualViewFactory.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationContextualViewFactory.java
new file mode 100644
index 0000000..6652dc4
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationContextualViewFactory.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * 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 org.apache.taverna.component.ui.annotation;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.taverna.component.api.ComponentFactory;
+import org.apache.taverna.component.api.Version;
+
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.common.AbstractNamed;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.port.ActivityPort;
+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;
+
+/**
+ * @author David Withers
+ */
+public class SemanticAnnotationContextualViewFactory implements
+		ContextualViewFactory<AbstractNamed> {
+	private FileManager fileManager;
+	private ComponentFactory factory;
+
+	private WorkflowBundle bundle;
+
+	public void setComponentFactory(ComponentFactory factory) {
+		this.factory = factory;
+	}
+
+	public void setFileManager(FileManager fm) {
+		this.fileManager = fm;
+	}
+
+	@Override
+	public boolean canHandle(Object selection) {
+		bundle = fileManager.getCurrentDataflow();
+		return fileManager.getDataflowSource(bundle) instanceof Version.ID
+				&& selection instanceof AbstractNamed
+				&& !(selection instanceof Activity || selection instanceof ActivityPort);
+	}
+
+	@Override
+	public List<ContextualView> getViews(AbstractNamed selection) {
+		return Arrays.asList(new SemanticAnnotationContextualView(fileManager,
+				factory, selection), new TurtleContextualView(selection, bundle));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/43334c1d/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationPanel.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationPanel.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationPanel.java
new file mode 100644
index 0000000..c2d2fb9
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationPanel.java
@@ -0,0 +1,253 @@
+package org.apache.taverna.component.ui.annotation;
+
+import static java.awt.BorderLayout.CENTER;
+import static java.awt.BorderLayout.NORTH;
+import static java.awt.Color.WHITE;
+import static java.awt.Font.BOLD;
+import static java.awt.GridBagConstraints.BOTH;
+import static java.awt.GridBagConstraints.EAST;
+import static java.awt.GridBagConstraints.HORIZONTAL;
+import static java.awt.GridBagConstraints.NONE;
+import static java.awt.GridBagConstraints.SOUTHEAST;
+import static java.lang.Integer.MIN_VALUE;
+import static java.lang.String.format;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
+import static javax.swing.JOptionPane.OK_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.getDisplayName;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.getObjectName;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.border.EmptyBorder;
+
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+
+import com.hp.hpl.jena.ontology.OntProperty;
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Statement;
+
+public class SemanticAnnotationPanel extends JPanel {
+	private static final long serialVersionUID = -5949183295606132775L;
+
+	private List<PropertyPanelFactorySPI> propertyPanelFactories; //FIXME beaninject
+	private final AbstractSemanticAnnotationContextualView semanticAnnotationContextualView;
+	private final SemanticAnnotationProfile semanticAnnotationProfile;
+	private final Set<Statement> statements;
+	private final boolean allowChange;
+	private final PropertyPanelFactorySPI bestFactory;
+
+	public SemanticAnnotationPanel(
+			AbstractSemanticAnnotationContextualView semanticAnnotationContextualView,
+			SemanticAnnotationProfile semanticAnnotationProfile,
+			Set<Statement> statements, boolean allowChange) {
+		this.semanticAnnotationContextualView = semanticAnnotationContextualView;
+		this.semanticAnnotationProfile = semanticAnnotationProfile;
+		this.statements = statements;
+		this.allowChange = allowChange;
+		this.bestFactory = findBestPanelFactory();
+		initialise();
+	}
+
+	private void initialise() {
+		setLayout(new GridBagLayout());
+		// setBorder(new AbstractBorder() {
+		// @Override
+		// public void paintBorder(Component c, Graphics g, int x, int y, int
+		// width, int height) {
+		// g.setColor(Color.GRAY);
+		// g.drawLine(x, y+height-1, x+width-1, y+height-1);
+		// }
+		// });
+
+		GridBagConstraints c = new GridBagConstraints();
+		c.anchor = SOUTHEAST;
+		c.fill = BOTH;
+		c.weightx = 1;
+		c.gridx = 0;
+
+		OntProperty predicate = semanticAnnotationProfile.getPredicate();
+		c.gridwidth = 3;
+		JLabel label = new JLabel(format("Annotation type : %s",
+				getDisplayName(predicate)));
+		label.setBorder(new EmptyBorder(5, 5, 5, 5));
+		label.setBackground(WHITE);
+		label.setOpaque(true);
+		add(label, c);
+
+		c.insets = new Insets(7, 0, 0, 0);
+		c.anchor = EAST;
+		c.fill = HORIZONTAL;
+		if (statements.isEmpty()) {
+			c.gridwidth = 2;
+			// c.weightx = 1;
+			// c.gridy++;
+			add(new JLabel("No semantic annotations"), c);
+		} else {
+			c.gridwidth = 1;
+			for (Statement statement : statements) {
+				c.gridx = 0;
+				c.weightx = 1;
+				if (bestFactory != null) {
+					add(bestFactory.getDisplayComponent(
+							semanticAnnotationProfile, statement), c);
+				} else {
+					JTextArea value = new JTextArea(getObjectName(statement));
+					value.setLineWrap(true);
+					value.setWrapStyleWord(true);
+					value.setEditable(false);
+					value.setBackground(WHITE);
+					value.setOpaque(true);
+					value.setBorder(new EmptyBorder(2, 4, 2, 4));
+					add(value, c);
+				}
+				if (allowChange) {
+					c.gridx = 1;
+					c.weightx = 0;
+					add(createChangeButton(statement), c);
+
+					c.gridx = 2;
+					add(createDeleteButton(statement), c);
+				}
+			}
+		}
+
+		if (allowChange
+				&& !enoughAlready(statements,
+						semanticAnnotationProfile.getMaxOccurs())) {
+			c.gridx = 0;
+			c.gridwidth = 3;
+			c.anchor = SOUTHEAST;
+			c.fill = NONE;
+			add(createAddButton(), c);
+		}
+	}
+
+	private boolean enoughAlready(Set<Statement> statements, Integer maxOccurs) {
+		return (maxOccurs != null) && (statements.size() >= maxOccurs);
+	}
+
+	private JButton createChangeButton(final Statement statement) {
+		return new DeselectingButton("Change", new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent arg0) {
+				addOrChangeAnnotation(statement);
+			}
+		});
+	}
+
+	private JButton createDeleteButton(final Statement statement) {
+		return new DeselectingButton("Delete", new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent arg0) {
+				semanticAnnotationContextualView.removeStatement(statement);
+			}
+		});
+	}
+
+	private JButton createAddButton() {
+		return new DeselectingButton("Add Annotation", new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				addOrChangeAnnotation(null);
+			}
+		});
+	}
+
+	private void addOrChangeAnnotation(Statement statement) {
+		JPanel annotationPanel = null;
+		JComponent inputComponent = null;
+
+		if (bestFactory != null) {
+			inputComponent = bestFactory.getInputComponent(
+					semanticAnnotationProfile, statement);
+			annotationPanel = getPropertyPanel(
+					getDisplayName(semanticAnnotationProfile.getPredicate()),
+					inputComponent);
+		}
+
+		if (annotationPanel == null) {
+			showMessageDialog(null, format("Unable to handle %s",
+					semanticAnnotationProfile.getPredicateString()),
+					"Annotation problem", ERROR_MESSAGE);
+			return;
+		}
+
+		int answer = showConfirmDialog(null, annotationPanel,
+				"Add/change annotation", OK_CANCEL_OPTION);
+		if (answer == OK_OPTION) {
+			RDFNode response = bestFactory.getNewTargetNode(statement,
+					inputComponent);
+			if (response == null)
+				return;
+			if (statement != null)
+				semanticAnnotationContextualView.changeStatement(statement,
+						semanticAnnotationProfile.getPredicate(), response);
+			else
+				semanticAnnotationContextualView.addStatement(
+						semanticAnnotationProfile.getPredicate(), response);
+		}
+	}
+
+	private PropertyPanelFactorySPI findBestPanelFactory() {
+		PropertyPanelFactorySPI result = null;
+		int currentRating = MIN_VALUE;
+		for (PropertyPanelFactorySPI factory : propertyPanelFactories) {
+			int ratingForSemanticAnnotation = factory
+					.getRatingForSemanticAnnotation(semanticAnnotationProfile);
+			if (ratingForSemanticAnnotation > currentRating) {
+				currentRating = ratingForSemanticAnnotation;
+				result = factory;
+			}
+		}
+		return result;
+	}
+
+	public static JPanel getPropertyPanel(String displayName,
+			Component inputComponent) {
+		JPanel result = new JPanel();
+		result.setLayout(new BorderLayout());
+		JPanel messagePanel = new JPanel(new BorderLayout());
+		messagePanel.setBorder(new EmptyBorder(5, 5, 0, 0));
+		messagePanel.setBackground(WHITE);
+		result.add(messagePanel, NORTH);
+
+		JLabel inputLabel = new JLabel("Enter a value for the annotation");
+		inputLabel.setBackground(WHITE);
+		Font baseFont = inputLabel.getFont();
+		inputLabel.setFont(baseFont.deriveFont(BOLD));
+		messagePanel.add(inputLabel, NORTH);
+
+		JTextArea messageText = new JTextArea(format(
+				"Enter a value for the annotation '%s'", displayName));
+		messageText.setMargin(new Insets(5, 10, 10, 10));
+		messageText.setMinimumSize(new Dimension(0, 30));
+		messageText.setFont(baseFont.deriveFont(11f));
+		messageText.setEditable(false);
+		messageText.setFocusable(false);
+		messagePanel.add(messageText, CENTER);
+
+		result.add(new JScrollPane(inputComponent), CENTER);
+		return result;
+	}
+}