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:35:59 UTC
[44/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/org/apache/taverna/component/ui/annotation/SemanticAnnotationUtils.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationUtils.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationUtils.java
new file mode 100644
index 0000000..b59ffcc
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/SemanticAnnotationUtils.java
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * 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.ModelFactory.createDefaultModel;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.apache.taverna.component.api.ComponentException;
+import org.apache.taverna.component.api.profile.Profile;
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+
+import uk.org.taverna.scufl2.api.annotation.Annotation;
+import uk.org.taverna.scufl2.api.common.AbstractNamed;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+import com.hp.hpl.jena.ontology.OntProperty;
+import com.hp.hpl.jena.ontology.OntResource;
+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 David Withers
+ */
+public class SemanticAnnotationUtils {
+ protected static final String ENCODING = "TURTLE";
+ /* Pretend-base for making relative URIs */
+ private static String BASE = "widget://4aa8c93c-3212-487c-a505-3e337adf54a3/";
+ private static Logger logger = getLogger(SemanticAnnotationUtils.class);
+
+ public static String getObjectName(Statement statement) {
+ return getDisplayName(statement.getObject());
+ }
+
+ public static String getDisplayName(RDFNode node) {
+ if (node == null)
+ return "unknown";
+ else if (node.isAnon())
+ return "anon";
+ else if (node.isLiteral())
+ return node.asLiteral().getLexicalForm();
+ else if (node.isResource()) {
+ Resource resource = node.asResource();
+ if (resource instanceof OntResource) {
+ String label = ((OntResource) resource).getLabel(null);
+ if (label != null)
+ return label;
+ }
+ String localName = resource.getLocalName();
+ if ((localName != null) && !localName.isEmpty())
+ return localName;
+ return resource.toString();
+ } else
+ return "unknown";
+ }
+
+ public static Annotation findSemanticAnnotation(AbstractNamed annotated) {
+ for (Annotation annotation : annotated.getAnnotations())
+ return annotation;
+ return null;
+ }
+
+ public static String getStrippedAnnotationContent(Annotation annotation)
+ throws IOException {
+ AbstractNamed target = (AbstractNamed) annotation.getTarget();
+ return annotation.getRDFContent().replace(
+ target.getRelativeURI(annotation).toASCIIString(), BASE);
+ }
+
+ public static Annotation createSemanticAnnotation(WorkflowBundle bundle,
+ AbstractNamed target, Model model) throws IOException {
+ Calendar now = new GregorianCalendar();
+ Annotation annotation = new Annotation();
+ annotation.setParent(bundle);
+ String path = annotation.getResourcePath();
+ annotation.setTarget(target);
+ // annotation.setAnnotatedBy(annotatedBy);
+ annotation.setAnnotatedAt(now);
+ // annotation.setSerializedBy(serializedBy);
+ annotation.setSerializedAt(now);
+ bundle.getResources().addResource(
+ "@base<" + target.getRelativeURI(annotation).toASCIIString()
+ + "> .\n" + createTurtle(model), path, "text/rdf+n3");
+ return annotation;
+ }
+
+ /**
+ * @param model
+ * @return
+ */
+ public static String createTurtle(Model model) {
+ StringWriter stringWriter = new StringWriter();
+ model.write(stringWriter, ENCODING, BASE);
+ // Workaround for https://issues.apache.org/jira/browse/JENA-132
+ return stringWriter.toString().replace(BASE, "");
+ }
+
+ public static Model populateModel(WorkflowBundle annotated) {
+ Model result = createDefaultModel();
+ try {
+ for (Annotation a : annotated.getAnnotations())
+ populateModelFromString(result, a.getRDFContent());
+ } catch (Exception e) {
+ logger.error("failed to construct semantic annotation model", e);
+ }
+ return result;
+ }
+
+ public static void populateModel(Model result, Annotation annotation)
+ throws IOException {
+ AbstractNamed target = (AbstractNamed) annotation.getTarget();
+ String content = annotation.getRDFContent().replace(
+ target.getRelativeURI(annotation).toASCIIString(), BASE);
+ populateModelFromString(result, content);
+ }
+
+ public static void populateModelFromString(Model result, String content) {
+ result.read(new StringReader(content), BASE, ENCODING);
+ }
+
+ public static Resource createBaseResource(Model model) {
+ return model.createResource(BASE);
+ }
+
+ /**
+ * Check if a profile is satisfied by a component.
+ *
+ * @param bundle
+ * The component definition.
+ * @param componentProfile
+ * The profile definition.
+ * @return The set of failed constraints. If empty, the profile is satisfied
+ * by the component.
+ */
+ public static Set<SemanticAnnotationProfile> checkComponent(
+ WorkflowBundle bundle, Profile componentProfile) {
+ // TODO Check port presence by name
+ Set<SemanticAnnotationProfile> problemProfiles = new HashSet<>();
+ Model model = populateModel(bundle);
+ Set<Statement> statements = model.listStatements().toSet();
+ try {
+ for (SemanticAnnotationProfile saProfile : componentProfile
+ .getSemanticAnnotations()) {
+ OntProperty predicate = saProfile.getPredicate();
+ if (predicate == null)
+ continue;
+ int count = 0;
+ for (Statement statement : statements)
+ if (statement.getPredicate().equals(predicate))
+ count++;
+ if (count < saProfile.getMinOccurs())
+ problemProfiles.add(saProfile);
+ if (saProfile.getMaxOccurs() != null
+ && count > saProfile.getMaxOccurs())
+ // The UI should prevent this, but check anyway
+ problemProfiles.add(saProfile);
+ }
+ } catch (ComponentException e) {
+ logger.error("failed to look up profiles for semantic annotations", e);
+ }
+ return problemProfiles;
+ }
+}
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/TurtleContextualView.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/TurtleContextualView.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/TurtleContextualView.java
new file mode 100644
index 0000000..586c557
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/TurtleContextualView.java
@@ -0,0 +1,78 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.annotation;
+
+import static java.awt.BorderLayout.CENTER;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.findSemanticAnnotation;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.getStrippedAnnotationContent;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.awt.BorderLayout;
+import java.io.IOException;
+
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+
+import org.slf4j.Logger;
+
+import uk.org.taverna.scufl2.api.annotation.Annotation;
+import uk.org.taverna.scufl2.api.common.AbstractNamed;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * @author alanrw
+ */
+public class TurtleContextualView extends ContextualView {
+ private static final long serialVersionUID = -3401885589263647202L;
+ private static final Logger log = getLogger(TurtleContextualView.class);
+ private JPanel panel;
+ private String annotationContent = "";
+
+ public TurtleContextualView(AbstractNamed selection, WorkflowBundle bundle) {
+ Annotation annotation = findSemanticAnnotation(selection);
+ try {
+ if (annotation != null)
+ annotationContent = getStrippedAnnotationContent(annotation);
+ } catch (IOException e) {
+ log.info("failed to read semantic annotation; using empty string", e);
+ }
+ initialise();
+ initView();
+ }
+
+ @Override
+ public JComponent getMainFrame() {
+ return panel;
+ }
+
+ @Override
+ public int getPreferredPosition() {
+ return 512;
+ }
+
+ @Override
+ public String getViewTitle() {
+ return "Turtle representation";
+ }
+
+ @Override
+ public void refreshView() {
+ initialise();
+ }
+
+ protected final void initialise() {
+ if (panel == null)
+ panel = new JPanel(new BorderLayout());
+ else
+ panel.removeAll();
+ JTextArea textArea = new JTextArea(20, 80);
+ textArea.setEditable(false);
+ textArea.setText(annotationContent);
+ panel.add(textArea, CENTER);
+ revalidate();
+ }
+}
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/TurtleInputPanel.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/TurtleInputPanel.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/TurtleInputPanel.java
new file mode 100644
index 0000000..30a4c9b
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/TurtleInputPanel.java
@@ -0,0 +1,90 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.annotation;
+
+import static com.hp.hpl.jena.rdf.model.ModelFactory.createOntologyModel;
+import static java.awt.BorderLayout.CENTER;
+import static java.awt.BorderLayout.EAST;
+import static java.awt.BorderLayout.SOUTH;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.populateModelFromString;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+import net.sf.taverna.t2.lang.ui.ReadOnlyTextArea;
+
+import com.hp.hpl.jena.ontology.Individual;
+import com.hp.hpl.jena.ontology.OntClass;
+import com.hp.hpl.jena.ontology.OntModel;
+
+/**
+ * @author alanrw
+ */
+@SuppressWarnings("serial")
+public class TurtleInputPanel extends JPanel {
+ JTextArea turtleTextArea = new JTextArea(30, 80);
+ ReadOnlyTextArea errors = new ReadOnlyTextArea(1, 80);
+ private OntClass clazz;
+
+ public TurtleInputPanel(OntClass clazz) {
+ super(new BorderLayout());
+ this.clazz = clazz;
+
+ add(new JScrollPane(turtleTextArea), CENTER);
+
+ turtleTextArea.setText("<#changeme> a <" + clazz.getURI() + ">\n\n\n.");
+
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new BorderLayout());
+ JButton validateButton = new DeselectingButton(new AbstractAction(
+ "Validate") {
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ getContentAsModel();
+ }
+ });
+ buttonPanel.add(errors, CENTER);
+ errors.setOpaque(false);
+ buttonPanel.add(validateButton, EAST);
+ add(buttonPanel, SOUTH);
+ }
+
+ public OntModel getContentAsModel() {
+ OntModel result = createOntologyModel();
+ try {
+ populateModelFromString(result, getContentAsString());
+
+ // Check it is not still called changeme
+ List<Individual> individuals = result.listIndividuals(clazz)
+ .toList();
+ if (individuals.isEmpty()) {
+ errors.setText("No valid individuals");
+ return null;
+ }
+ for (Individual i : individuals)
+ if (i.getURI().endsWith("changeme")) {
+ errors.setText("Name has not been changed");
+ return null;
+ }
+
+ errors.setText("No errors found");
+ return result;
+ } catch (Throwable ex) { // syntax error?
+ errors.setText(ex.getMessage());
+ return null;
+ }
+ }
+
+ public String getContentAsString() {
+ return turtleTextArea.getText();
+ }
+}
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/UnrecognizedStatementPanel.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/UnrecognizedStatementPanel.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/UnrecognizedStatementPanel.java
new file mode 100644
index 0000000..e16c30d
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/UnrecognizedStatementPanel.java
@@ -0,0 +1,27 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.annotation;
+
+import static java.lang.String.format;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import com.hp.hpl.jena.rdf.model.Statement;
+
+/**
+ * @author alanrw
+ *
+ */
+@SuppressWarnings("serial")
+public class UnrecognizedStatementPanel extends JPanel {
+ public UnrecognizedStatementPanel(Statement statement) {
+ setLayout(new BorderLayout());
+ setBorder(new GreyBorder());
+ add(new JLabel(format("Unable to find %s in the profile",
+ statement.getPredicate())));
+ }
+}
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/UnresolveablePredicatePanel.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/UnresolveablePredicatePanel.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/UnresolveablePredicatePanel.java
new file mode 100644
index 0000000..454986b
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/annotation/UnresolveablePredicatePanel.java
@@ -0,0 +1,27 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.annotation;
+
+import static java.lang.String.format;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+
+/**
+ * @author alanrw
+ */
+@SuppressWarnings("serial")
+public class UnresolveablePredicatePanel extends JPanel {
+ public UnresolveablePredicatePanel(
+ SemanticAnnotationProfile semanticAnnotationProfile) {
+ setLayout(new BorderLayout());
+ setBorder(new GreyBorder());
+ add(new JLabel(format("Unable to resolve %s in the ontology",
+ semanticAnnotationProfile.getPredicateString())));
+ }
+}
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/config/ComponentConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/config/ComponentConfigurationPanel.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/config/ComponentConfigurationPanel.java
new file mode 100644
index 0000000..293a8bc
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/config/ComponentConfigurationPanel.java
@@ -0,0 +1,153 @@
+package org.apache.taverna.component.ui.config;
+
+import static java.awt.event.ItemEvent.SELECTED;
+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.util.Utils.SHORT_STRING;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.util.SortedMap;
+
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ActivityConfigurationPanel;
+
+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.ui.panel.ComponentListCellRenderer;
+
+import uk.org.taverna.commons.services.ServiceRegistry;
+import uk.org.taverna.scufl2.api.activity.Activity;
+
+@SuppressWarnings("serial")
+public class ComponentConfigurationPanel extends ActivityConfigurationPanel {
+ private static Logger logger = getLogger(ComponentConfigurationPanel.class);
+
+ private ComponentFactory factory;//FIXME beaninject
+ private ServiceRegistry sr;
+
+ private final JComboBox<Object> componentVersionChoice = new JComboBox<>();
+
+ public ComponentConfigurationPanel(Activity activity,
+ ComponentFactory factory, ServiceRegistry serviceRegistry) {
+ super(activity);
+ sr = serviceRegistry;
+ this.factory = factory;
+ componentVersionChoice.setPrototypeDisplayValue(SHORT_STRING);
+ initGui();
+ }
+
+ private Version getSelectedVersion() {
+ return (Version) componentVersionChoice.getSelectedItem();
+ }
+ private URI getRegistryBase() {
+ return URI.create(getProperty(REGISTRY_BASE));
+ }
+ private String getFamilyName() {
+ return getProperty(FAMILY_NAME);
+ }
+ private String getComponentName() {
+ return getProperty(COMPONENT_NAME);
+ }
+ private Integer getComponentVersion() {
+ return Integer.parseInt(getProperty(COMPONENT_VERSION));
+ }
+
+ protected void initGui() {
+ removeAll();
+ setLayout(new GridLayout(0, 2));
+
+ componentVersionChoice.setRenderer(new ComponentListCellRenderer<>());
+ componentVersionChoice.addItemListener(new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent event) {
+ if (event.getStateChange() == SELECTED)
+ updateToolTipText();
+ }
+ });
+ updateComponentVersionChoice();
+
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.insets = new Insets(0, 5, 0, 5);
+ gbc.gridx = 0;
+ gbc.anchor = GridBagConstraints.WEST;
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+ gbc.gridy = 2;
+ this.add(new JLabel("Component version:"), gbc);
+ gbc.gridx = 1;
+ gbc.weightx = 1;
+ this.add(componentVersionChoice, gbc);
+
+ // Populate fields from activity configuration bean
+ refreshConfiguration();
+ }
+
+ /**
+ * Check that user values in UI are valid
+ */
+ @Override
+ public boolean checkValues() {
+ return true;
+ }
+
+ /**
+ * Check if the user has changed the configuration from the original
+ */
+ @Override
+ public boolean isConfigurationChanged() {
+ return !getSelectedVersion().getVersionNumber().equals(
+ getComponentVersion());
+ }
+
+ /**
+ * Prepare a new configuration bean from the UI, to be returned with
+ * getConfiguration()
+ */
+ @Override
+ public void noteConfiguration() {
+ setProperty(COMPONENT_VERSION, getSelectedVersion().getVersionNumber()
+ .toString());
+ //FIXME is this right at all???
+ configureInputPorts(sr);
+ configureOutputPorts(sr);
+ }
+
+ private void updateComponentVersionChoice() {
+ Component component;
+ componentVersionChoice.removeAllItems();
+ componentVersionChoice.setToolTipText(null);
+ try {
+ component = factory.getComponent(getRegistryBase().toURL(),
+ getFamilyName(), getComponentName());
+ } catch (ComponentException | MalformedURLException e) {
+ logger.error("failed to get component", e);
+ return;
+ }
+ SortedMap<Integer, Version> componentVersionMap = component
+ .getComponentVersionMap();
+ for (Version v : componentVersionMap.values())
+ componentVersionChoice.addItem(v);
+ componentVersionChoice.setSelectedItem(componentVersionMap
+ .get(getComponentVersion()));
+ updateToolTipText();
+ }
+
+ private void updateToolTipText() {
+ Version selectedVersion = (Version) componentVersionChoice
+ .getSelectedItem();
+ componentVersionChoice.setToolTipText(selectedVersion.getDescription());
+ }
+}
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/config/ComponentConfigureAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/config/ComponentConfigureAction.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/config/ComponentConfigureAction.java
new file mode 100644
index 0000000..f7252cc
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/config/ComponentConfigureAction.java
@@ -0,0 +1,50 @@
+package org.apache.taverna.component.ui.config;
+
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+
+import org.apache.taverna.component.api.ComponentFactory;
+
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.actions.activity.ActivityConfigurationAction;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ActivityConfigurationDialog;
+import uk.org.taverna.commons.services.ServiceRegistry;
+import uk.org.taverna.scufl2.api.activity.Activity;
+
+@SuppressWarnings("serial")
+public class ComponentConfigureAction extends ActivityConfigurationAction {
+ private EditManager editManager;
+ private FileManager fileManager;
+ private ServiceRegistry serviceRegistry;
+ private ComponentFactory factory;
+
+ public ComponentConfigureAction(Activity activity, Frame owner,
+ ComponentFactory factory, ActivityIconManager activityIconManager,
+ ServiceDescriptionRegistry serviceDescriptionRegistry,
+ EditManager editManager, FileManager fileManager,
+ ServiceRegistry serviceRegistry) {
+ super(activity, activityIconManager, serviceDescriptionRegistry);
+ this.editManager = editManager;
+ this.fileManager = fileManager;
+ this.serviceRegistry = serviceRegistry;
+ this.factory = factory;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ ActivityConfigurationDialog currentDialog = getDialog(getActivity());
+ if (currentDialog != null) {
+ currentDialog.toFront();
+ return;
+ }
+
+ ComponentConfigurationPanel configView = new ComponentConfigurationPanel(
+ activity, factory, serviceRegistry);
+ ActivityConfigurationDialog dialog = new ActivityConfigurationDialog(
+ getActivity(), configView, editManager);
+ setDialog(getActivity(), dialog, fileManager);
+ }
+}
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/file/ComponentDataflowHealthCheckExplainer.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/ComponentDataflowHealthCheckExplainer.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/ComponentDataflowHealthCheckExplainer.java
new file mode 100644
index 0000000..cbc046d
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/ComponentDataflowHealthCheckExplainer.java
@@ -0,0 +1,75 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.file;
+
+import static java.util.Collections.sort;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.getDisplayName;
+import static org.apache.taverna.component.ui.util.ComponentHealthCheck.FAILS_PROFILE;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.JComponent;
+import javax.swing.JTextArea;
+
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+import org.apache.taverna.component.ui.util.ComponentHealthCheck;
+
+import net.sf.taverna.t2.visit.VisitKind;
+import net.sf.taverna.t2.visit.VisitReport;
+import net.sf.taverna.t2.workbench.report.explainer.VisitExplainer;
+
+/**
+ * @author alanrw
+ */
+public class ComponentDataflowHealthCheckExplainer implements VisitExplainer {
+ private static final Comparator<SemanticAnnotationProfile> comparator = new Comparator<SemanticAnnotationProfile>() {
+ @Override
+ public int compare(SemanticAnnotationProfile a,
+ SemanticAnnotationProfile b) {
+ return getDisplayName(a.getPredicate()).compareTo(
+ getDisplayName(b.getPredicate()));
+ }
+ };
+
+ @Override
+ public boolean canExplain(VisitKind vk, int resultId) {
+ return vk instanceof ComponentHealthCheck
+ && resultId == FAILS_PROFILE;
+ }
+
+ @Override
+ public JComponent getExplanation(VisitReport vr) {
+ @SuppressWarnings("unchecked")
+ Set<SemanticAnnotationProfile> problemProfiles = (Set<SemanticAnnotationProfile>) vr
+ .getProperty("problemProfiles");
+ List<SemanticAnnotationProfile> sortedList = new ArrayList<>(
+ problemProfiles);
+ sort(sortedList, comparator);
+ StringBuilder text = new StringBuilder();
+ for (SemanticAnnotationProfile profile : sortedList)
+ text.append(getSemanticProfileExplanation(profile)).append("\n");
+ return new JTextArea(text.toString());
+ }
+
+ @Override
+ public JComponent getSolution(VisitReport vr) {
+ return new JTextArea("Correct the semantic annotation");
+ }
+
+ private static String getSemanticProfileExplanation(
+ SemanticAnnotationProfile p) {
+ Integer minOccurs = p.getMinOccurs();
+ Integer maxOccurs = p.getMaxOccurs();
+ String displayName = getDisplayName(p.getPredicate());
+ if (maxOccurs == null)
+ return displayName + " must have at least " + minOccurs + " value";
+ if (minOccurs.equals(maxOccurs))
+ return displayName + " must have " + minOccurs + " value(s)";
+ return displayName + " must have between " + minOccurs + " and "
+ + maxOccurs + " value(s)";
+ }
+}
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/file/ComponentDataflowHealthChecker.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/ComponentDataflowHealthChecker.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/ComponentDataflowHealthChecker.java
new file mode 100644
index 0000000..b9076d5
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/ComponentDataflowHealthChecker.java
@@ -0,0 +1,89 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.file;
+
+import static net.sf.taverna.t2.visit.VisitReport.Status.SEVERE;
+import static org.apache.log4j.Logger.getLogger;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.checkComponent;
+import static org.apache.taverna.component.ui.util.ComponentHealthCheck.FAILS_PROFILE;
+
+import java.util.List;
+import java.util.Set;
+
+import net.sf.taverna.t2.visit.VisitReport;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workflowmodel.health.HealthChecker;
+
+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.Version;
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+import org.apache.taverna.component.ui.util.ComponentHealthCheck;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.core.Workflow;
+
+/**
+ * @author alanrw
+ */
+public class ComponentDataflowHealthChecker implements HealthChecker<Dataflow> {
+ private static final String PROFILE_UNSATISFIED_MSG = "Workflow does not satisfy component profile";
+ private static Logger logger = getLogger(ComponentDataflowHealthChecker.class);
+
+ private FileManager fm;
+ private ComponentHealthCheck visitType = ComponentHealthCheck.getInstance(); //FIXME beaninject?
+ private ComponentFactory factory;
+
+ public void setComponentFactory(ComponentFactory factory) {
+ this.factory = factory;
+ }
+
+ public void setFileManager(FileManager fm) {
+ this.fm = fm;
+ }
+
+ private Version.ID getSource(Object o) {
+ return (Version.ID) fm.getDataflowSource((WorkflowBundle) o);
+ }
+
+ public void checkProfileSatisfied(WorkflowBundle bundle) {
+ //FIXME
+ }
+ @Override
+ public boolean canVisit(Object o) {
+ try {
+ return getSource(o) != null;
+ } catch (IllegalArgumentException e) {
+ // Not open?
+ } catch (ClassCastException e) {
+ // Not dataflow? Not component?
+ }
+ return false;
+ }
+
+ @Override
+ public VisitReport visit(WorkflowBundle dataflow, List<Object> ancestry) {
+ try {
+ Version.ID ident = getSource(dataflow);
+ Family family = factory.getFamily(ident.getRegistryBase(),
+ ident.getFamilyName());
+
+ Set<SemanticAnnotationProfile> problemProfiles = checkComponent(
+ dataflow, family.getComponentProfile());
+ if (problemProfiles.isEmpty())
+ return null;
+
+ VisitReport visitReport = new VisitReport(visitType, dataflow,
+ PROFILE_UNSATISFIED_MSG, FAILS_PROFILE, SEVERE);
+ visitReport.setProperty("problemProfiles", problemProfiles);
+ return visitReport;
+ } catch (ComponentException e) {
+ logger.error(
+ "failed to comprehend profile while checking for match", e);
+ return null;
+ }
+ }
+}
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/file/ComponentOpener.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/ComponentOpener.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/ComponentOpener.java
new file mode 100644
index 0000000..4e07171
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/ComponentOpener.java
@@ -0,0 +1,73 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.file;
+
+import static org.apache.log4j.Logger.getLogger;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import net.sf.taverna.t2.workbench.file.AbstractDataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.DataflowInfo;
+import net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
+
+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.Version;
+import org.apache.taverna.component.api.Version.ID;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * @author alanrw
+ */
+public class ComponentOpener extends AbstractDataflowPersistenceHandler
+ implements DataflowPersistenceHandler {
+ private static Logger logger = getLogger(ComponentOpener.class);
+
+ private ComponentFactory factory;
+ private FileType fileType;
+
+ public void setComponentFactory(ComponentFactory factory) {
+ this.factory = factory;
+ }
+
+ public void setFileType(FileType fileType) {
+ this.fileType = fileType;
+ }
+
+ @Override
+ public DataflowInfo openDataflow(FileType fileType, Object source)
+ throws OpenException {
+ if (!getOpenFileTypes().contains(fileType))
+ throw new IllegalArgumentException("Unsupported file type "
+ + fileType);
+ if (!(source instanceof Version.ID))
+ throw new IllegalArgumentException("Unsupported source type "
+ + source.getClass().getName());
+
+ WorkflowBundle d;
+ try {
+ d = factory.getVersion((ID) source).getImplementation();
+ } catch (ComponentException e) {
+ logger.error("Unable to read dataflow", e);
+ throw new OpenException("Unable to read dataflow", e);
+ }
+ return new DataflowInfo(fileType, source, d, new Date());
+ }
+
+ @Override
+ public List<FileType> getOpenFileTypes() {
+ return Arrays.<FileType> asList(fileType);
+ }
+
+ @Override
+ public List<Class<?>> getOpenSourceTypes() {
+ return Arrays.<Class<?>> asList(Version.ID.class);
+ }
+}
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/file/ComponentSaver.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/ComponentSaver.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/ComponentSaver.java
new file mode 100644
index 0000000..424961a
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/ComponentSaver.java
@@ -0,0 +1,170 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.file;
+
+import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
+import static javax.swing.JOptionPane.OK_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static org.apache.log4j.Logger.getLogger;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.checkComponent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+import net.sf.taverna.t2.workbench.file.AbstractDataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.DataflowInfo;
+import net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.exceptions.SaveException;
+
+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.Family;
+import org.apache.taverna.component.api.Registry;
+import org.apache.taverna.component.api.Version;
+import org.apache.taverna.component.api.profile.SemanticAnnotationProfile;
+import org.apache.taverna.component.ui.serviceprovider.ComponentServiceProvider;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.validation.ValidationReport;
+import uk.org.taverna.scufl2.validation.structural.StructuralValidator;
+
+/**
+ * @author alanrw
+ */
+public class ComponentSaver extends AbstractDataflowPersistenceHandler
+ implements DataflowPersistenceHandler {
+ private static final String UNSATISFIED_PROFILE_WARNING = "The component does not satisfy the profile.\n"
+ + "See validation report.\nDo you still want to save?";
+ private static final Logger logger = getLogger(ComponentSaver.class);
+
+ private ComponentFactory factory;
+ private ComponentServiceProvider provider;
+ private FileType cft;
+
+ public void setComponentFactory(ComponentFactory factory) {
+ this.factory = factory;
+ }
+
+ public void setFileType(FileType fileType) {
+ this.cft = fileType;
+ }
+
+ public void setServiceProvider(ComponentServiceProvider provider) {
+ this.provider = provider;
+ }
+
+ @Override
+ public DataflowInfo saveDataflow(WorkflowBundle bundle, FileType fileType,
+ Object destination) throws SaveException {
+ if (!getSaveFileTypes().contains(fileType))
+ throw new IllegalArgumentException("Unsupported file type "
+ + fileType);
+ if (!(destination instanceof Version.ID))
+ throw new IllegalArgumentException("Unsupported destination type "
+ + destination.getClass().getName());
+
+ ValidationReport structuralValidity = new StructuralValidator()
+ .validate(bundle);
+ if (structuralValidity.detectedProblems())
+ throw new SaveException(
+ "Cannot save a structurally invalid workflow as a component",
+ structuralValidity.getException());
+
+ /*
+ * Saving an invalid dataflow is OK. Validity check is done to get
+ * predicted depth for output (if possible)
+ */
+
+ Version.ID ident = (Version.ID) destination;
+
+ if (ident.getComponentVersion() == -1) {
+ Version.ID newIdent = new Version.Identifier(
+ ident.getRegistryBase(), ident.getFamilyName(),
+ ident.getComponentName(), 0);
+ return new DataflowInfo(cft, newIdent, bundle);
+ }
+
+ Family family;
+ try {
+ Registry registry = factory.getRegistry(ident.getRegistryBase());
+ family = registry.getComponentFamily(ident.getFamilyName());
+ } catch (ComponentException e) {
+ throw new SaveException("Unable to read component", e);
+ }
+
+ Version newVersion = null;
+ try {
+ List<SemanticAnnotationProfile> problemProfiles = new ArrayList<>(
+ checkComponent(bundle, family.getComponentProfile()));
+
+ if (!problemProfiles.isEmpty()) {
+ int answer = showConfirmDialog(null,
+ UNSATISFIED_PROFILE_WARNING, "Profile problem",
+ OK_CANCEL_OPTION);
+ if (answer != OK_OPTION)
+ throw new SaveException("Saving cancelled");
+ }
+
+ JTextArea descriptionArea = new JTextArea(10, 60);
+ descriptionArea.setLineWrap(true);
+ descriptionArea.setWrapStyleWord(true);
+ final JScrollPane descriptionScrollPane = new JScrollPane(
+ descriptionArea);
+ if (ident.getComponentVersion() == 0) {
+ int answer = showConfirmDialog(null, descriptionScrollPane,
+ "Component description", OK_CANCEL_OPTION);
+ if (answer != OK_OPTION)
+ throw new SaveException("Saving cancelled");
+ newVersion = family.createComponentBasedOn(
+ ident.getComponentName(), descriptionArea.getText(),
+ bundle);
+ } else {
+ Component component = family.getComponent(ident
+ .getComponentName());
+ int answer = showConfirmDialog(null, descriptionScrollPane,
+ "Version description", OK_CANCEL_OPTION);
+ if (answer != OK_OPTION)
+ throw new SaveException("Saving cancelled");
+ newVersion = component.addVersionBasedOn(bundle,
+ descriptionArea.getText());
+ }
+ } catch (ComponentException e) {
+ logger.error("Unable to save new version of component", e);
+ throw new SaveException("Unable to save new version of component",
+ e);
+ }
+
+ Version.ID newIdent = new Version.Identifier(ident.getRegistryBase(),
+ ident.getFamilyName(), ident.getComponentName(),
+ newVersion.getVersionNumber());
+ provider.refreshProvidedComponent(ident);
+ return new DataflowInfo(cft, newIdent, bundle);
+ }
+
+ @Override
+ public List<FileType> getSaveFileTypes() {
+ return Arrays.<FileType> asList(cft);
+ }
+
+ @Override
+ public List<Class<?>> getSaveDestinationTypes() {
+ return Arrays.<Class<?>> asList(Version.ID.class);
+ }
+
+ @Override
+ public boolean wouldOverwriteDataflow(WorkflowBundle dataflow,
+ FileType fileType, Object destination, DataflowInfo lastDataflowInfo) {
+ if (!getSaveFileTypes().contains(fileType))
+ throw new IllegalArgumentException("Unsupported file type "
+ + fileType);
+ return false;
+ }
+}
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/file/FileManagerObserver.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/FileManagerObserver.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/FileManagerObserver.java
new file mode 100644
index 0000000..0490874
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/file/FileManagerObserver.java
@@ -0,0 +1,128 @@
+package org.apache.taverna.component.ui.file;
+
+import static java.awt.Color.WHITE;
+import static java.awt.Font.BOLD;
+import static javax.swing.SwingUtilities.invokeLater;
+import static javax.swing.SwingUtilities.isEventDispatchThread;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Insets;
+
+import javax.swing.border.Border;
+
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.workbench.StartupSPI;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.events.FileManagerEvent;
+import net.sf.taverna.t2.workbench.models.graph.svg.SVGGraphController;
+import net.sf.taverna.t2.workbench.views.graph.GraphViewComponent;
+
+import org.apache.batik.swing.JSVGCanvas;
+import org.apache.taverna.component.api.Version;
+import org.apache.taverna.component.ui.util.Utils;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+public class FileManagerObserver implements StartupSPI {
+ private static final Color COLOR = new Color(230, 147, 210);
+
+ private FileManager fileManager;
+ private ColourManager colours;
+ private GraphViewComponent graphView;
+ private Utils utils;
+
+ public void setFileManager(FileManager fileManager) {
+ this.fileManager = fileManager;
+ }
+
+ public void setColourManager(ColourManager colours) {
+ this.colours = colours;
+ }
+
+ public void setGraphView(GraphViewComponent graphView) {
+ this.graphView = graphView;
+ }
+
+ public void setUtils(Utils utils) {
+ this.utils = utils;
+ }
+
+ @Override
+ public boolean startup() {
+ colours.setPreferredColour(
+ "org.apache.taverna.component.registry.Component", COLOR);
+ colours.setPreferredColour(
+ "org.apache.taverna.component.ComponentActivity", COLOR);
+ fileManager.addObserver(new Observer<FileManagerEvent>() {
+ @Override
+ public void notify(Observable<FileManagerEvent> observable,
+ FileManagerEvent event) throws Exception {
+ FileManagerObserverRunnable runnable = new FileManagerObserverRunnable();
+ if (isEventDispatchThread())
+ runnable.run();
+ else
+ invokeLater(runnable);
+ }
+ });
+ return true;
+ }
+
+ @Override
+ public int positionHint() {
+ return 200;
+ }
+
+ public class FileManagerObserverRunnable implements Runnable {
+ @Override
+ public void run() {
+ WorkflowBundle currentDataflow = fileManager.getCurrentDataflow();
+ if (currentDataflow == null)
+ return;
+ SVGGraphController graphController = (SVGGraphController) graphView
+ .getGraphController(currentDataflow.getMainWorkflow());
+ if (graphController == null)
+ return;
+ JSVGCanvas svgCanvas = graphController.getSVGCanvas();
+ Object dataflowSource = fileManager
+ .getDataflowSource(currentDataflow);
+ if (utils.currentDataflowIsComponent())
+ svgCanvas.setBorder(new ComponentBorder(
+ (Version.ID) dataflowSource));
+ else
+ svgCanvas.setBorder(null);
+ svgCanvas.repaint();
+ }
+ }
+
+ static class ComponentBorder implements Border {
+ private final Insets insets = new Insets(25, 0, 0, 0);
+ private final String text;
+
+ public ComponentBorder(Version.ID identification) {
+ text = "Component : " + identification.getComponentName();
+ }
+
+ @Override
+ public Insets getBorderInsets(java.awt.Component c) {
+ return insets;
+ }
+
+ @Override
+ public boolean isBorderOpaque() {
+ return true;
+ }
+
+ @Override
+ public void paintBorder(java.awt.Component c, Graphics g, int x, int y,
+ int width, int height) {
+ g.setColor(COLOR);
+ g.fillRect(x, y, width, 20);
+ g.setFont(g.getFont().deriveFont(BOLD));
+ g.setColor(WHITE);
+ g.drawString(text, x + 5, y + 15);
+ }
+ }
+}
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/localworld/LocalWorld.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/localworld/LocalWorld.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/localworld/LocalWorld.java
new file mode 100644
index 0000000..42bd492
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/localworld/LocalWorld.java
@@ -0,0 +1,92 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.localworld;
+
+import static com.hp.hpl.jena.rdf.model.ModelFactory.createOntologyModel;
+import static org.apache.log4j.Logger.getLogger;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.createTurtle;
+import static org.apache.taverna.component.ui.annotation.SemanticAnnotationUtils.populateModelFromString;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+
+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.rdf.model.Resource;
+
+/**
+ * @author alanrw
+ */
+public class LocalWorld {
+ private static final String FILENAME = "localWorld.ttl";
+ private static final Logger logger = getLogger(LocalWorld.class);
+ protected static final String ENCODING = "TURTLE";
+ private static LocalWorld instance = null;
+
+ private OntModel model;
+
+ public synchronized static LocalWorld getInstance() {
+ if (instance == null)
+ instance = new LocalWorld();
+ return instance;
+ }
+
+ private LocalWorld() {
+ File modelFile = new File(calculateComponentsDirectory(), FILENAME);
+ model = createOntologyModel();
+ if (modelFile.exists())
+ try (Reader in = new InputStreamReader(new FileInputStream(
+ modelFile), "UTF-8")) {
+ model.read(in, null, ENCODING);
+ } catch (IOException e) {
+ logger.error("failed to construct local annotation world", e);
+ }
+ }
+
+ ApplicationConfiguration config;//FIXME beaninject
+
+ public File calculateComponentsDirectory() {
+ return new File(config.getApplicationHomeDir(), "components");
+ }
+
+ public Individual createIndividual(String urlString, OntClass rangeClass) {
+ try {
+ return model.createIndividual(urlString, rangeClass);
+ } finally {
+ saveModel();
+ }
+ }
+
+ private void saveModel() {
+ File modelFile = new File(calculateComponentsDirectory(), FILENAME);
+ try (OutputStream out = new FileOutputStream(modelFile)) {
+ out.write(createTurtle(model).getBytes("UTF-8"));
+ } catch (IOException e) {
+ logger.error("failed to save local annotation world", e);
+ }
+ }
+
+ public List<Individual> getIndividualsOfClass(Resource clazz) {
+ return model.listIndividuals(clazz).toList();
+ }
+
+ public void addModelFromString(String addedModel) {
+ try {
+ populateModelFromString(model, addedModel);
+ } finally {
+ saveModel();
+ }
+ }
+}
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/menu/AbstractContextComponentMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/AbstractContextComponentMenuAction.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/AbstractContextComponentMenuAction.java
new file mode 100644
index 0000000..8a90895
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/AbstractContextComponentMenuAction.java
@@ -0,0 +1,39 @@
+package org.apache.taverna.component.ui.menu;
+
+import java.net.URI;
+
+import org.apache.taverna.component.api.config.ComponentConfig;
+
+import net.sf.taverna.t2.ui.menu.AbstractContextualMenuAction;
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.core.Processor;
+
+public abstract class AbstractContextComponentMenuAction extends AbstractContextualMenuAction {
+ public AbstractContextComponentMenuAction(URI parentId, int positionHint) {
+ super(parentId, positionHint);
+ }
+
+ public AbstractContextComponentMenuAction(URI parentId, int positionHint, URI id) {
+ super(parentId, positionHint, id);
+ }
+
+ protected boolean isComponentActivity(Activity act) {
+ if (act == null)
+ return false;
+ return act.getType().equals(ComponentConfig.URI);
+ }
+
+ protected Activity findActivity() {
+ if (getContextualSelection() == null)
+ return null;
+ Object selection = getContextualSelection().getSelection();
+ if (selection instanceof Processor) {
+ Processor processor = (Processor) selection;
+ return processor.getParent().getParent().getMainProfile()
+ .getProcessorBindings().getByName(processor.getName())
+ .getBoundActivity();
+ } else if (selection instanceof Activity)
+ return (Activity) selection;
+ return null;
+ }
+}
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/menu/ComponentConfigureMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/ComponentConfigureMenuAction.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/ComponentConfigureMenuAction.java
new file mode 100644
index 0000000..effba35
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/ComponentConfigureMenuAction.java
@@ -0,0 +1,63 @@
+package org.apache.taverna.component.ui.menu;
+
+import static javax.swing.Action.NAME;
+import static org.apache.taverna.component.ui.ComponentConstants.ACTIVITY_URI;
+
+import javax.swing.Action;
+
+import org.apache.taverna.component.api.ComponentFactory;
+import org.apache.taverna.component.ui.config.ComponentConfigureAction;
+
+import uk.org.taverna.commons.services.ServiceRegistry;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.activitytools.AbstractConfigureActivityMenuAction;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+
+public class ComponentConfigureMenuAction extends
+ AbstractConfigureActivityMenuAction {
+ public ComponentConfigureMenuAction() {
+ super(ACTIVITY_URI);
+ }
+
+ private ActivityIconManager aim;
+ private ServiceDescriptionRegistry sdr;
+ private EditManager em;
+ private FileManager fm;
+ private ServiceRegistry str;
+ private ComponentFactory factory;
+
+ public void setActivityIconManager(ActivityIconManager aim) {
+ this.aim = aim;
+ }
+
+ public void setServiceDescriptionRegistry(ServiceDescriptionRegistry sdr) {
+ this.sdr = sdr;
+ }
+
+ public void setEditManager(EditManager em) {
+ this.em = em;
+ }
+
+ public void setFileManager(FileManager fm) {
+ this.fm = fm;
+ }
+
+ public void setServiceTypeRegistry(ServiceRegistry str) {
+ this.str = str;
+ }
+
+ public void setComponentFactory(ComponentFactory factory) {
+ this.factory = factory;
+ }
+
+ @Override
+ protected Action createAction() {
+ Action result = new ComponentConfigureAction(findActivity(),
+ getParentFrame(), factory, aim, sdr, em, fm, str);
+ result.putValue(NAME, "Configure component");
+ addMenuDots(result);
+ 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/menu/ComponentMenu.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/ComponentMenu.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/ComponentMenu.java
new file mode 100644
index 0000000..f9fa643
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/ComponentMenu.java
@@ -0,0 +1,27 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.menu;
+
+import static net.sf.taverna.t2.ui.menu.DefaultMenuBar.DEFAULT_MENU_BAR;
+
+import java.net.URI;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenu;
+
+/**
+ * @author alanrw
+ */
+public class ComponentMenu extends AbstractMenu {
+ public static final URI COMPONENT = URI
+ .create("http://taverna.sf.net/2008/t2workbench/menu#component");
+ public static final String TITLE = "Components";
+
+ public ComponentMenu() {
+ super(DEFAULT_MENU_BAR, 950, COMPONENT, makeAction());
+ }
+
+ public static DummyAction makeAction() {
+ return new DummyAction(TITLE);
+ }
+}
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/menu/ComponentSection.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/ComponentSection.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/ComponentSection.java
new file mode 100644
index 0000000..efeadb0
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/ComponentSection.java
@@ -0,0 +1,29 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.menu;
+
+import java.net.URI;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuSection;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ComponentSection extends AbstractMenuSection {
+ public static final String COMPONENT_SECTION = "Components";
+ public static final URI componentSection = URI
+ .create("http://taverna.sf.net/2009/contextMenu/components");
+ public static final URI editSection = URI
+ .create("http://taverna.sf.net/2009/contextMenu/edit");
+
+ public ComponentSection() {
+ super(editSection, 100, componentSection);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return super.isEnabled();
+ }
+}
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/menu/NestedWorkflowCreationDialog.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/NestedWorkflowCreationDialog.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/NestedWorkflowCreationDialog.java
new file mode 100644
index 0000000..0aecacf
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/NestedWorkflowCreationDialog.java
@@ -0,0 +1,628 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.menu;
+
+import static java.awt.BorderLayout.CENTER;
+import static java.awt.BorderLayout.NORTH;
+import static java.awt.BorderLayout.SOUTH;
+import static java.util.Collections.sort;
+import static javax.swing.JOptionPane.WARNING_MESSAGE;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static org.apache.log4j.Logger.getLogger;
+import static org.apache.taverna.component.ui.util.Utils.uniqueName;
+import static uk.org.taverna.scufl2.api.common.Scufl2Tools.NESTED_WORKFLOW;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.AbstractAction;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.ListCellRenderer;
+
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+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.helper.HelpEnabledDialog;
+import net.sf.taverna.t2.workbench.models.graph.GraphController;
+import net.sf.taverna.t2.workbench.views.graph.GraphViewComponent;
+import net.sf.taverna.t2.workflow.edits.AddActivityEdit;
+import net.sf.taverna.t2.workflow.edits.AddActivityInputPortMappingEdit;
+import net.sf.taverna.t2.workflow.edits.AddActivityOutputPortMappingEdit;
+import net.sf.taverna.t2.workflow.edits.AddChildEdit;
+import net.sf.taverna.t2.workflow.edits.AddDataLinkEdit;
+import net.sf.taverna.t2.workflow.edits.AddProcessorInputPortEdit;
+import net.sf.taverna.t2.workflow.edits.AddProcessorOutputPortEdit;
+import net.sf.taverna.t2.workflow.edits.AddWorkflowInputPortEdit;
+import net.sf.taverna.t2.workflow.edits.AddWorkflowOutputPortEdit;
+import net.sf.taverna.t2.workflow.edits.RemoveChildEdit;
+import net.sf.taverna.t2.workflow.edits.RemoveDataLinkEdit;
+import net.sf.taverna.t2.workflow.edits.SetIterationStrategyStackEdit;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.annotation.Annotation;
+import uk.org.taverna.scufl2.api.common.Named;
+import uk.org.taverna.scufl2.api.common.NamedSet;
+import uk.org.taverna.scufl2.api.common.Scufl2Tools;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.core.BlockingControlLink;
+import uk.org.taverna.scufl2.api.core.ControlLink;
+import uk.org.taverna.scufl2.api.core.DataLink;
+import uk.org.taverna.scufl2.api.core.Processor;
+import uk.org.taverna.scufl2.api.core.Workflow;
+import uk.org.taverna.scufl2.api.port.InputActivityPort;
+import uk.org.taverna.scufl2.api.port.InputProcessorPort;
+import uk.org.taverna.scufl2.api.port.InputWorkflowPort;
+import uk.org.taverna.scufl2.api.port.OutputActivityPort;
+import uk.org.taverna.scufl2.api.port.OutputProcessorPort;
+import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;
+import uk.org.taverna.scufl2.api.port.ProcessorPort;
+import uk.org.taverna.scufl2.api.port.ReceiverPort;
+import uk.org.taverna.scufl2.api.port.SenderPort;
+import uk.org.taverna.scufl2.api.profiles.Profile;
+
+/**
+ * @author alanrw
+ */
+public class NestedWorkflowCreationDialog extends HelpEnabledDialog {
+ private static final long serialVersionUID = 727059218457420449L;
+ private static final Logger logger = getLogger(NestedWorkflowCreationDialog.class);
+ private static final Comparator<Processor> processorComparator = new Comparator<Processor>() {
+ @Override
+ public int compare(Processor o1, Processor o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+ };
+ private static final ListCellRenderer<Object> defaultRenderer = new DefaultListCellRenderer();
+ private static final ListCellRenderer<Processor> processorRenderer = new ListCellRenderer<Processor>() {
+ @Override
+ public Component getListCellRendererComponent(
+ JList<? extends Processor> list,
+ Processor value, int index, boolean isSelected,
+ boolean cellHasFocus) {
+ return defaultRenderer.getListCellRendererComponent(list,
+ value.getName(), index, isSelected, cellHasFocus);
+ }
+ };
+
+ private final EditManager em;
+ private final GraphViewComponent graphView;
+ private final List<Processor> includedProcessors = new ArrayList<>();
+ private List<Processor> allProcessors;
+ private final List<Processor> includableProcessors = new ArrayList<>();
+
+ private JList<Processor> includableList = new JList<>();
+ private JList<Processor> includedList = new JList<>();
+ private final Workflow currentDataflow;
+ private JButton excludeButton;
+ private JButton includeButton;
+ private JButton okButton;
+ private JButton resetButton;
+ private JTextField nameField = new JTextField(30);
+
+ public NestedWorkflowCreationDialog(Frame owner, Object o,
+ Workflow dataflow, EditManager em, GraphViewComponent graphView) {
+ super(owner, "Nested workflow creation", true, null);
+ this.em = em;
+ this.graphView = graphView;
+
+ if (o instanceof Processor)
+ includedProcessors.add((Processor) o);
+ this.currentDataflow = dataflow;
+
+ allProcessors = new ArrayList<>(dataflow.getProcessors());
+
+ this.setLayout(new BorderLayout());
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new FlowLayout());
+
+ okButton = new DeselectingButton(new OKAction(this));
+ buttonPanel.add(okButton);
+
+ resetButton = new DeselectingButton(new ResetAction(this));
+ buttonPanel.add(resetButton);
+
+ JButton cancelButton = new DeselectingButton(new CancelAction(this));
+ buttonPanel.add(cancelButton);
+
+ JPanel innerPanel = new JPanel(new BorderLayout());
+ JPanel processorChoice = createProcessorChoicePanel(dataflow);
+ innerPanel.add(processorChoice, CENTER);
+
+ JPanel namePanel = new JPanel(new FlowLayout());
+ namePanel.add(new JLabel("Workflow name: "));
+ nameField.setText("nested");
+ namePanel.add(nameField);
+ innerPanel.add(namePanel, SOUTH);
+
+ this.add(innerPanel, CENTER);
+
+ this.add(buttonPanel, SOUTH);
+ this.pack();
+ this.setSize(new Dimension(500, 800));
+ }
+
+ private JPanel createProcessorChoicePanel(Workflow dataflow) {
+ JPanel result = new JPanel();
+ result.setLayout(new GridLayout(0, 2));
+
+ JPanel includedProcessorsPanel = createIncludedProcessorsPanel();
+ JPanel includableProcessorsPanel = createIncludableProcessorsPanel();
+ result.add(includableProcessorsPanel);
+ result.add(includedProcessorsPanel);
+ updateLists();
+ return result;
+ }
+
+ private JPanel createIncludableProcessorsPanel() {
+ JPanel result = new JPanel();
+ result.setLayout(new BorderLayout());
+ result.add(new JLabel("Possible services"), NORTH);
+ includableList.setModel(new DefaultComboBoxModel<>(new Vector<>(
+ includableProcessors)));
+ includableList.setCellRenderer(processorRenderer);
+ result.add(new JScrollPane(includableList), CENTER);
+
+ includeButton = new DeselectingButton("Include", new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ includedProcessors.addAll(includableList
+ .getSelectedValuesList());
+ calculateIncludableProcessors();
+ updateLists();
+ }
+ });
+
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new FlowLayout());
+ buttonPanel.add(includeButton);
+ result.add(buttonPanel, SOUTH);
+ return result;
+ }
+
+ private void resetLists() {
+ includedProcessors.clear();
+ updateLists();
+ }
+
+ private JPanel createIncludedProcessorsPanel() {
+ JPanel result = new JPanel();
+ result.setLayout(new BorderLayout());
+ result.add(new JLabel("Included services"), NORTH);
+ includedList.setModel(new DefaultComboBoxModel<>(new Vector<>(
+ includedProcessors)));
+ includedList.setCellRenderer(processorRenderer);
+ result.add(new JScrollPane(includedList), CENTER);
+
+ excludeButton = new DeselectingButton("Exclude", new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ includedProcessors.removeAll(includedList
+ .getSelectedValuesList());
+ calculateIncludableProcessors();
+ updateLists();
+ }
+ });
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new FlowLayout());
+ buttonPanel.add(excludeButton);
+
+ result.add(buttonPanel, SOUTH);
+ return result;
+ }
+
+ private void updateLists() {
+ calculateIncludableProcessors();
+ sort(includedProcessors, processorComparator);
+ sort(includableProcessors, processorComparator);
+ includedList.setModel(new DefaultComboBoxModel<>(new Vector<>(
+ includedProcessors)));
+ includableList.setModel(new DefaultComboBoxModel<>(new Vector<>(
+ includableProcessors)));
+ boolean someIncludedProcessors = includedProcessors.size() > 0;
+ excludeButton.setEnabled(someIncludedProcessors);
+ okButton.setEnabled(someIncludedProcessors);
+ resetButton.setEnabled(someIncludedProcessors);
+ boolean someIncludableProcessors = includableProcessors.size() > 0;
+ includeButton.setEnabled(someIncludableProcessors);
+ }
+
+ public void calculateIncludableProcessors() {
+ includableProcessors.clear();
+ if (includedProcessors.isEmpty())
+ includableProcessors.addAll(allProcessors);
+ else
+ for (Processor p : includedProcessors) {
+ considerNearestUpstream(p);
+ considerNearestDownstream(p);
+ }
+ sort(includableProcessors, processorComparator);
+ }
+
+ private void considerNearestDownstream(Processor investigate) {
+ for (BlockingControlLink condition : investigate.controlLinksWaitingFor())
+ considerInclusion(condition.getBlock());
+
+ for (OutputProcessorPort outputPort : investigate.getOutputPorts())
+ for (DataLink datalink : outputPort.getDatalinksFrom()) {
+ ReceiverPort sink = datalink.getSendsTo();
+ if (sink instanceof InputProcessorPort)
+ considerInclusion(((InputProcessorPort) sink).getParent());
+ }
+ }
+
+ private void considerNearestUpstream(Processor investigate) {
+ for (BlockingControlLink condition : investigate.controlLinksBlocking())
+ considerInclusion(condition.getUntilFinished());
+ for (InputProcessorPort inputPort : investigate.getInputPorts())
+ for (DataLink incomingLink : inputPort.getDatalinksTo()) {
+ if (incomingLink == null)
+ continue;
+ SenderPort source = incomingLink.getReceivesFrom();
+ if (source instanceof OutputProcessorPort)
+ considerInclusion(((OutputProcessorPort) source).getParent());
+ }
+ }
+
+ private void considerInclusion(Processor p) {
+ if (!includedProcessors.contains(p)
+ && !includableProcessors.contains(p))
+ includableProcessors.add(p);
+ }
+
+ private void createNestedWorkflow() {
+ final List<Edit<?>> currentWorkflowEditList = new ArrayList<>();
+ Map<Object, Object> oldNewMapping = new HashMap<>();
+ Map<DataLink, String> linkProcessorPortMapping = new HashMap<>();
+ Map<SenderPort, OutputWorkflowPort> outputPortMap = new HashMap<>();
+ Map<ReceiverPort, InputWorkflowPort> inputPortMap = new HashMap<>();
+
+ Profile profile;//FIXME
+ Processor nestingProcessor = createNestingProcessor(currentWorkflowEditList);
+ Workflow nestedDataflow = createNestedDataflow();
+
+ transferProcessors(currentWorkflowEditList, oldNewMapping,
+ nestedDataflow);
+ transferDatalinks(oldNewMapping, linkProcessorPortMapping,
+ outputPortMap, inputPortMap, nestedDataflow);
+ transferConditions(currentWorkflowEditList, oldNewMapping,
+ nestingProcessor);
+ addDataflowToNestingProcessor(nestingProcessor, nestedDataflow, profile);
+ currentWorkflowEditList.add(new AddChildEdit<>(currentDataflow,
+ nestingProcessor));
+ createDatalinkEdits(currentWorkflowEditList, oldNewMapping,
+ linkProcessorPortMapping, nestingProcessor);
+
+ try {
+ GraphController gc = graphView.getGraphController(currentDataflow);
+ gc.setExpandNestedDataflow(nestingProcessor.getActivity(profile), true);
+ em.doDataflowEdit(currentDataflow.getParent(), new CompoundEdit(
+ currentWorkflowEditList));
+ gc.redraw();
+ } catch (EditException e1) {
+ logger.error("failed to manufacture nested workflow", e1);
+ }
+ }
+
+ private void addDataflowToNestingProcessor(Processor nestingProcessor,
+ Workflow nestedDataflow, Profile profile) {
+ Activity da = new Activity();
+ da.setParent(profile);
+ da.createConfiguration(NESTED_WORKFLOW).getJsonAsObjectNode()
+ .put("nestedWorkflow", nestedDataflow.getName());
+ try {
+ new AddActivityEdit(nestingProcessor, da).doEdit();
+ new SetIterationStrategyStackEdit(nestingProcessor, null/*FIXME*/).doEdit();
+ for (InputActivityPort aip : da.getInputPorts()) {
+ InputProcessorPort pip = new InputProcessorPort();
+ pip.setName(aip.getName());
+ pip.setDepth(aip.getDepth());
+ new AddProcessorInputPortEdit(nestingProcessor, pip).doEdit();
+ new AddActivityInputPortMappingEdit(da, pip, aip).doEdit();
+ }
+ for (OutputActivityPort aop : da.getOutputPorts()) {
+ OutputProcessorPort pop = new OutputProcessorPort();
+ pop.setName(aop.getName());
+ pop.setDepth(aop.getDepth());
+ pop.setGranularDepth(aop.getGranularDepth());
+ new AddProcessorOutputPortEdit(nestingProcessor, pop).doEdit();
+ new AddActivityOutputPortMappingEdit(da, pop, aop).doEdit();
+ }
+ } catch (EditException e1) {
+ logger.error("failed to add ports to processor", e1);
+ }
+ }
+
+ private void createDatalinkEdits(List<Edit<?>> editList,
+ Map<Object, Object> oldNewMapping,
+ Map<DataLink, String> linkProcessorPortMapping,
+ Processor nestingProcessor) {
+ for (DataLink dl : currentDataflow.getDataLinks())
+ if (oldNewMapping.containsKey(dl.getReceivesFrom())
+ && oldNewMapping.containsKey(dl.getSendsTo()))
+ // Internal to nested workflow
+ editList.add(new RemoveDataLinkEdit(dl.getParent(), dl));
+ else if (oldNewMapping.containsKey(dl.getReceivesFrom())) {
+ // Coming out of nested workflow
+ OutputProcessorPort nestedPort = nestingProcessor
+ .getOutputPorts().getByName(
+ linkProcessorPortMapping.get(dl));
+ if (nestedPort != null) {
+ DataLink replacementDatalink = new DataLink(nestedPort
+ .getParent().getParent(), nestedPort,
+ dl.getSendsTo());
+ editList.add(new RemoveDataLinkEdit(dl.getParent(), dl));
+ editList.add(new AddDataLinkEdit(nestedPort.getParent()
+ .getParent(), replacementDatalink));
+ }
+ } else if (oldNewMapping.containsKey(dl.getSendsTo())) {
+ // Coming into nested workflow
+ InputProcessorPort nestedPort = nestingProcessor
+ .getInputPorts().getByName(
+ linkProcessorPortMapping.get(dl));
+ if (nestedPort != null) {
+ DataLink replacementDatalink = new DataLink(nestedPort
+ .getParent().getParent(), dl.getReceivesFrom(),
+ nestedPort);
+ editList.add(new RemoveDataLinkEdit(dl.getParent(), dl));
+ editList.add(new AddDataLinkEdit(nestedPort.getParent()
+ .getParent(), replacementDatalink));
+ }
+ }
+ }
+
+ private void transferConditions(List<Edit<?>> editList,
+ Map<Object, Object> oldNewMapping, Processor nestingProcessor) {
+ for (Processor p : currentDataflow.getProcessors()) {
+ boolean isTargetMoved = oldNewMapping.containsKey(p);
+ for (BlockingControlLink c : p.controlLinksWaitingFor()) {
+ Processor pre = c.getUntilFinished();
+ boolean isControlMoved = oldNewMapping.containsKey(pre);
+ if (isTargetMoved && isControlMoved) {
+ // Add in new condition
+ new BlockingControlLink(
+ (Processor) oldNewMapping.get(pre),
+ (Processor) oldNewMapping.get(p));
+ } else if (isTargetMoved) {
+ editList.add(new RemoveChildEdit<>(c.getParent(),c));
+ editList.add(new AddChildEdit<>(c.getParent(),
+ new BlockingControlLink(pre, nestingProcessor)));
+ } else if (isControlMoved) {
+ editList.add(new RemoveChildEdit<>(c.getParent(), c));
+ editList.add(new AddChildEdit<>(c.getParent(),
+ new BlockingControlLink(nestingProcessor, p)));
+ }
+ }
+ }
+ }
+
+ private void transferDatalinks(Map<Object, Object> oldNewMapping,
+ Map<DataLink, String> linkProcessorPortMapping,
+ Map<SenderPort, OutputWorkflowPort> outputPortMap,
+ Map<ReceiverPort, InputWorkflowPort> inputPortMap,
+ Workflow nestedDataflow) {
+ NamedSet<InputWorkflowPort> inputPorts = new NamedSet<>();
+ NamedSet<OutputWorkflowPort> outputPorts = new NamedSet<>();
+
+ for (DataLink dl : currentDataflow.getDataLinks()) {
+ final SenderPort datalinkSource = dl.getReceivesFrom();
+ final ReceiverPort datalinkSink = dl.getSendsTo();
+ if (oldNewMapping.containsKey(datalinkSource)
+ && oldNewMapping.containsKey(datalinkSink)) {
+ // Internal to nested workflow
+ DataLink newDatalink = new DataLink(null,
+ (SenderPort) oldNewMapping.get(datalinkSource),
+ (ReceiverPort) oldNewMapping.get(datalinkSink));
+ try {
+ new AddDataLinkEdit(nestedDataflow, newDatalink).doEdit();
+ } catch (EditException e1) {
+ logger.error("failed to connect datalink", e1);
+ }
+ } else if (oldNewMapping.containsKey(datalinkSource)) {
+ OutputWorkflowPort dop = null;
+ if (!outputPortMap.containsKey(datalinkSource)) {
+ dop = new OutputWorkflowPort(nestedDataflow, uniqueName(
+ datalinkSource.getName(), outputPorts));
+ outputPorts.add(dop);
+ outputPortMap.put(datalinkSource, dop);
+ } else
+ dop = outputPortMap.get(datalinkSource);
+ String portName = dop.getName();
+ // Coming out of nested workflow
+ linkProcessorPortMapping.put(dl, portName);
+ try {
+ new AddWorkflowOutputPortEdit(nestedDataflow, dop).doEdit();
+ DataLink newDatalink = new DataLink(
+ (SenderPort) oldNewMapping.get(datalinkSource),
+ dop.getInternalInputPort());
+ new AddDataLinkEdit(nestedDataflow, newDatalink).doEdit();
+ } catch (EditException e1) {
+ logger.error("failed to add dataflow output", e1);
+ }
+ } else if (oldNewMapping.containsKey(datalinkSink)) {
+ InputWorkflowPort dip = null;
+ if (!inputPortMap.containsKey(datalinkSink)) {
+ dip = new InputWorkflowPort(nestedDataflow, uniqueName(
+ datalinkSink.getName(), inputPorts));
+ inputPorts.add(dip);
+ dip.setDepth(dl.getResolvedDepth());
+ inputPortMap.put(datalinkSink, dip);
+ } else
+ dip = inputPortMap.get(datalinkSink);
+ String portName = dip.getName();
+ // Coming into nested workflow
+ linkProcessorPortMapping.put(dl, portName);
+ try {
+ new AddWorkflowInputPortEdit(nestedDataflow, dip).doEdit();
+ DataLink newDatalink = new DataLink(
+ dip.getInternalOutputPort(),
+ (ReceiverPort) oldNewMapping.get(datalinkSink));
+ new AddDataLinkEdit(nestedDataflow, newDatalink).doEdit();
+ } catch (EditException e1) {
+ logger.error("failed to add dataflow input", e1);
+ }
+ }
+ }
+ }
+
+ private void transferProcessors(List<Edit<?>> editList,
+ Map<Object, Object> oldNewMapping, Workflow nestedDataflow) {
+ for (Processor entity : includedProcessors)
+ try {
+ if (entity instanceof Processor)
+ transferProcessor(editList, oldNewMapping, nestedDataflow,
+ (Processor) entity);
+ /*else if (entity instanceof Merge)
+ //FIXME what to do here? Anything?
+ transferMerge(editList, oldNewMapping, nestedDataflow,
+ (Merge) entity);*/
+ } catch (Exception e1) {
+ logger.error("failed to transfer processor", e1);
+ }
+ }
+
+ /*private void transferMerge(List<Edit<?>> editList,
+ Map<Object, Object> oldNewMapping, Workflow nestedDataflow,
+ Merge merge) throws EditException {
+ editList.add(edits.getRemoveMergeEdit(currentDataflow, merge));
+ Merge newMerge = edits.createMerge(nestedDataflow);
+ edits.getAddMergeEdit(nestedDataflow, newMerge).doEdit();
+ oldNewMapping.put(merge, newMerge);
+ for (MergeInputPort mip : merge.getInputPorts()) {
+ MergeInputPort newMip = edits.createMergeInputPort(newMerge,
+ mip.getName(), mip.getDepth());
+ edits.getAddMergeInputPortEdit(newMerge, newMip).doEdit();
+ oldNewMapping.put(mip, newMip);
+ }
+ oldNewMapping.put(merge.getOutputPort(), newMerge.getOutputPort());
+ }*/
+
+ private void transferProcessor(List<Edit<?>> editList,
+ Map<Object, Object> oldNewMapping, Workflow nestedDataflow,
+ Processor p) throws Exception {
+ editList.add(new RemoveChildEdit<>(currentDataflow, p));
+ Processor newProcessor = (Processor) p.clone();
+ newProcessor.setParent(nestedDataflow);
+ oldNewMapping.put(p, newProcessor);
+ for (InputProcessorPort pip : p.getInputPorts())
+ for (InputProcessorPort newPip : newProcessor.getInputPorts())
+ if (pip.getName().equals(newPip.getName())) {
+ oldNewMapping.put(pip, newPip);
+ break;
+ }
+ for (OutputProcessorPort pop : p.getOutputPorts())
+ for (OutputProcessorPort newPop : newProcessor.getOutputPorts())
+ if (pop.getName().equals(newPop.getName())) {
+ oldNewMapping.put(pop, newPop);
+ break;
+ }
+ }
+
+ private Processor createNestingProcessor(List<Edit<?>> editList) {
+ //TODO check what workflow the new processor is going into
+ Processor nestingProcessor = new Processor(currentDataflow, uniqueName(
+ nameField.getText(), currentDataflow.getProcessors()));
+ if (includedProcessors.size() != 1)
+ return nestingProcessor;
+ Processor includedProcessor = includedProcessors.get(0);
+ for (Annotation a: includedProcessor.getAnnotations()) {
+ Annotation newAnn = (Annotation) a.clone();
+ newAnn.setTarget(nestingProcessor);
+ editList.add(new AddChildEdit<>(a.getParent(), newAnn));
+ }
+ return nestingProcessor;
+ }
+
+ private Workflow createNestedDataflow() {
+ Workflow nestedDataflow = new Workflow(uniqueName(nameField.getText(),
+ currentDataflow.getParent().getWorkflows()));
+ // Set the title of the nested workflow to the name suggested by the user
+ try {
+ new AnnotationTools().setAnnotationString(nestedDataflow,
+ DescriptiveTitle.class, nameField.getText()).doEdit();
+ } catch (EditException ex) {
+ logger.error("failed to put annotation on nested dataflow", ex);
+ }
+ return nestedDataflow;
+ }
+
+ private final class OKAction extends AbstractAction {
+ private static final long serialVersionUID = 6516891432445682857L;
+ private final JDialog dialog;
+
+ private OKAction(JDialog dialog) {
+ super("OK");
+ this.dialog = dialog;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (includedProcessors.isEmpty()) {
+ showMessageDialog(
+ null,
+ "At least one service must be included in the nested workflow",
+ "Nested workflow creation", WARNING_MESSAGE);
+ return;
+ }
+
+ createNestedWorkflow();
+ dialog.setVisible(false);
+ }
+ }
+
+ private final class ResetAction extends AbstractAction {
+ private static final long serialVersionUID = 7296742769289881218L;
+
+ private ResetAction(JDialog dialog) {
+ super("Reset");
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ resetLists();
+ }
+ }
+
+ private final class CancelAction extends AbstractAction {
+ private static final long serialVersionUID = -7842176979437027091L;
+ private final JDialog dialog;
+
+ private CancelAction(JDialog dialog) {
+ super("Cancel");
+ this.dialog = dialog;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ dialog.setVisible(false);
+ }
+ }
+}
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/menu/NestedWorkflowCreatorMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/NestedWorkflowCreatorMenuAction.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/NestedWorkflowCreatorMenuAction.java
new file mode 100644
index 0000000..79f290d
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/NestedWorkflowCreatorMenuAction.java
@@ -0,0 +1,78 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.menu;
+
+import java.awt.Dialog;
+import java.awt.event.ActionEvent;
+import java.net.URI;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import net.sf.taverna.t2.activities.dataflow.servicedescriptions.DataflowActivityIcon;
+import net.sf.taverna.t2.ui.menu.AbstractContextualMenuAction;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+import net.sf.taverna.t2.workbench.views.graph.GraphViewComponent;
+import uk.org.taverna.scufl2.api.core.Processor;
+import uk.org.taverna.scufl2.api.core.Workflow;
+
+/**
+ * @author alanrw
+ */
+public class NestedWorkflowCreatorMenuAction extends
+ AbstractContextualMenuAction {
+ private static final URI configureSection = URI
+ .create("http://taverna.sf.net/2009/contextMenu/configure");
+
+ private SelectionManager sm;
+ private EditManager em;
+ private GraphViewComponent gv;
+
+ public NestedWorkflowCreatorMenuAction() {
+ super(configureSection, 70);
+ }
+
+ public void setEditManager(EditManager editManager) {
+ em = editManager;
+ }
+ public void setGraphView(GraphViewComponent graphView) {
+ gv = graphView;
+ }
+ public void setSelectionManager(SelectionManager selectionManager) {
+ sm = selectionManager;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ Object selection = getContextualSelection().getSelection();
+ if (!super.isEnabled() || selection == null)
+ return false;
+ if (selection instanceof Processor)
+ return true;
+ if (!(selection instanceof Workflow))
+ return false;
+ return !((Workflow) selection).getProcessors().isEmpty();
+ }
+
+ @Override
+ protected Action createAction() {
+ return new AbstractAction("Create nested workflow...",
+ DataflowActivityIcon.getDataflowIcon()) {
+ private static final long serialVersionUID = -3121307982540205215L;
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ createNestedWorkflow();
+ }
+ };
+ }
+
+ private void createNestedWorkflow() {
+ Dialog dialog = new NestedWorkflowCreationDialog(null,
+ getContextualSelection().getSelection(),
+ sm.getSelectedWorkflow(), em, gv);
+ 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/menu/OpenComponentFromComponentActivityAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/OpenComponentFromComponentActivityAction.java b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/OpenComponentFromComponentActivityAction.java
new file mode 100644
index 0000000..2803f04
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/org/apache/taverna/component/ui/menu/OpenComponentFromComponentActivityAction.java
@@ -0,0 +1,66 @@
+/**
+ *
+ */
+package org.apache.taverna.component.ui.menu;
+
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.event.ActionEvent;
+import java.net.MalformedURLException;
+
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
+import net.sf.taverna.t2.workbench.views.graph.GraphViewComponent;
+
+import org.apache.log4j.Logger;
+import org.apache.taverna.component.api.ComponentFactory;
+import org.apache.taverna.component.api.Version;
+import org.apache.taverna.component.ui.ComponentAction;
+import org.apache.taverna.component.ui.ComponentActivityConfigurationBean;
+import org.apache.taverna.component.ui.serviceprovider.ComponentServiceIcon;
+
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * @author alanrw
+ */
+@SuppressWarnings("serial")
+public class OpenComponentFromComponentActivityAction extends ComponentAction {
+ private static Logger logger = getLogger(OpenComponentFromComponentActivityAction.class);
+
+ private final FileManager fileManager;
+ private final ComponentFactory factory;
+ private final FileType fileType;
+
+ public OpenComponentFromComponentActivityAction(FileManager fileManager,
+ ComponentFactory factory, FileType ft,
+ GraphViewComponent graphView, ComponentServiceIcon icon) {
+ super("Open component...", graphView);
+ this.fileManager = fileManager;
+ this.factory = factory;
+ this.fileType = ft;
+ setIcon(icon);
+ }
+
+ private Activity selection;
+
+ @Override
+ public void actionPerformed(ActionEvent ev) {
+ try {
+ Version.ID ident = new ComponentActivityConfigurationBean(
+ selection.getConfiguration(), factory);
+ WorkflowBundle d = fileManager.openDataflow(fileType, ident);
+ markGraphAsBelongingToComponent(d);
+ } catch (OpenException e) {
+ logger.error("failed to open component", e);
+ } catch (MalformedURLException e) {
+ logger.error("bad URL in component description", e);
+ }
+ }
+
+ public void setSelection(Activity selection) {
+ this.selection = selection;
+ }
+}