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 2018/06/29 10:55:12 UTC
[25/27] incubator-taverna-plugin-component git commit: package rename
folders
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreationDialog.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreationDialog.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreationDialog.java
new file mode 100644
index 0000000..3a467fd
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreationDialog.java
@@ -0,0 +1,666 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.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 io.github.taverna_extras.component.ui.util.Utils.uniqueName;
+import static org.apache.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 org.apache.taverna.annotation.annotationbeans.DescriptiveTitle;
+import org.apache.taverna.lang.ui.DeselectingButton;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.annotation.Annotation;
+import org.apache.taverna.scufl2.api.common.Named;
+import org.apache.taverna.scufl2.api.common.NamedSet;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.BlockingControlLink;
+import org.apache.taverna.scufl2.api.core.ControlLink;
+import org.apache.taverna.scufl2.api.core.DataLink;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.port.InputActivityPort;
+import org.apache.taverna.scufl2.api.port.InputProcessorPort;
+import org.apache.taverna.scufl2.api.port.InputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.OutputActivityPort;
+import org.apache.taverna.scufl2.api.port.OutputProcessorPort;
+import org.apache.taverna.scufl2.api.port.OutputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.ProcessorPort;
+import org.apache.taverna.scufl2.api.port.ReceiverPort;
+import org.apache.taverna.scufl2.api.port.SenderPort;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+import org.apache.taverna.workbench.edits.CompoundEdit;
+import org.apache.taverna.workbench.edits.Edit;
+import org.apache.taverna.workbench.edits.EditException;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.helper.HelpEnabledDialog;
+import org.apache.taverna.workbench.models.graph.GraphController;
+import org.apache.taverna.workbench.views.graph.GraphViewComponent;
+import org.apache.taverna.workflow.edits.AddActivityEdit;
+import org.apache.taverna.workflow.edits.AddActivityInputPortMappingEdit;
+import org.apache.taverna.workflow.edits.AddActivityOutputPortMappingEdit;
+import org.apache.taverna.workflow.edits.AddChildEdit;
+import org.apache.taverna.workflow.edits.AddDataLinkEdit;
+import org.apache.taverna.workflow.edits.AddProcessorInputPortEdit;
+import org.apache.taverna.workflow.edits.AddProcessorOutputPortEdit;
+import org.apache.taverna.workflow.edits.AddWorkflowInputPortEdit;
+import org.apache.taverna.workflow.edits.AddWorkflowOutputPortEdit;
+import org.apache.taverna.workflow.edits.RemoveChildEdit;
+import org.apache.taverna.workflow.edits.RemoveDataLinkEdit;
+import org.apache.taverna.workflow.edits.SetIterationStrategyStackEdit;
+import org.apache.taverna.workflowmodel.utils.AnnotationTools;
+
+/**
+ * @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/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreatorMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreatorMenuAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreatorMenuAction.java
new file mode 100644
index 0000000..0cdb2ba
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/NestedWorkflowCreatorMenuAction.java
@@ -0,0 +1,94 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.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 org.apache.taverna.activities.dataflow.servicedescriptions.DataflowActivityIcon;
+
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.ui.menu.AbstractContextualMenuAction;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.selection.SelectionManager;
+import org.apache.taverna.workbench.views.graph.GraphViewComponent;
+
+/**
+ * @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/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityAction.java
new file mode 100644
index 0000000..2bce63a
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityAction.java
@@ -0,0 +1,81 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu;
+
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.event.ActionEvent;
+import java.net.MalformedURLException;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.ComponentFactory;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.ui.ComponentAction;
+import io.github.taverna_extras.component.ui.ComponentActivityConfigurationBean;
+import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.file.FileType;
+import org.apache.taverna.workbench.file.exceptions.OpenException;
+import org.apache.taverna.workbench.views.graph.GraphViewComponent;
+
+/**
+ * @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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityMenuAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityMenuAction.java
new file mode 100644
index 0000000..6f28816
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/OpenComponentFromComponentActivityMenuAction.java
@@ -0,0 +1,104 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import io.github.taverna_extras.component.api.ComponentFactory;
+import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.ui.menu.AbstractContextualMenuAction;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.file.FileType;
+import org.apache.taverna.workbench.selection.SelectionManager;
+import org.apache.taverna.workbench.views.graph.GraphViewComponent;
+
+/**
+ * @author alanrw
+ */
+public class OpenComponentFromComponentActivityMenuAction extends
+ AbstractContextualMenuAction {
+ private static final URI configureSection = URI
+ .create("http://taverna.sf.net/2009/contextMenu/configure");
+
+ private SelectionManager sm;
+ private FileManager fileManager;
+ private ComponentFactory factory;
+ private FileType fileType;
+ private GraphViewComponent graphView;
+ private ComponentServiceIcon icon;
+
+ public OpenComponentFromComponentActivityMenuAction() {
+ super(configureSection, 75);
+ }
+
+ public void setSelectionManager(SelectionManager sm) {
+ this.sm = sm;
+ }
+
+ public void setFileManager(FileManager fileManager) {
+ this.fileManager = fileManager;
+ }
+
+ public void setComponentFactory(ComponentFactory factory) {
+ this.factory = factory;
+ }
+
+ public void setFileType(FileType fileType) {
+ this.fileType = fileType;
+ }
+
+ public void setGraphView(GraphViewComponent graphView) {
+ this.graphView = graphView;
+ }
+
+ public void setIcon(ComponentServiceIcon icon) {
+ this.icon = icon;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return getSelectedActivity() != null;
+ }
+
+ @Override
+ protected Action createAction() {
+ OpenComponentFromComponentActivityAction action = new OpenComponentFromComponentActivityAction(
+ fileManager, factory, fileType, graphView, icon);
+ action.setSelection(getSelectedActivity());
+ return action;
+ }
+
+ private Activity getSelectedActivity() {
+ Object selection = getContextualSelection().getSelection();
+ if (!super.isEnabled() || !(selection instanceof Processor))
+ return null;
+
+ try {
+ return ((Processor) selection).getActivity(sm.getSelectedProfile());
+ } catch (RuntimeException e) {
+ return null;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentAction.java
new file mode 100644
index 0000000..ebb51a8
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentAction.java
@@ -0,0 +1,275 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu;
+
+import static java.awt.BorderLayout.CENTER;
+import static java.awt.BorderLayout.SOUTH;
+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 io.github.taverna_extras.component.api.config.ComponentPropertyNames.COMPONENT_NAME;
+import static io.github.taverna_extras.component.ui.ComponentActivityConfigurationBean.ignorableNames;
+import static io.github.taverna_extras.component.ui.util.Utils.uniqueName;
+import static org.apache.taverna.scufl2.api.common.Scufl2Tools.NESTED_WORKFLOW;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+import javax.swing.JSeparator;
+
+import io.github.taverna_extras.component.api.Component;
+import io.github.taverna_extras.component.api.ComponentFactory;
+import io.github.taverna_extras.component.api.Family;
+import io.github.taverna_extras.component.api.Registry;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.ui.ComponentActivityConfigurationBean;
+import io.github.taverna_extras.component.ui.panel.ComponentChooserPanel;
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import io.github.taverna_extras.component.ui.util.Utils;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.port.InputActivityPort;
+import org.apache.taverna.scufl2.api.port.InputProcessorPort;
+import org.apache.taverna.scufl2.api.port.OutputActivityPort;
+import org.apache.taverna.scufl2.api.port.OutputProcessorPort;
+import org.apache.taverna.workbench.edits.CompoundEdit;
+import org.apache.taverna.workbench.edits.Edit;
+import org.apache.taverna.workbench.edits.EditException;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.selection.SelectionManager;
+import org.apache.taverna.workflow.edits.AddActivityEdit;
+import org.apache.taverna.workflow.edits.AddActivityInputPortMappingEdit;
+import org.apache.taverna.workflow.edits.AddActivityOutputPortMappingEdit;
+import org.apache.taverna.workflow.edits.RemoveActivityEdit;
+import org.apache.taverna.workflow.edits.RenameEdit;
+
+/**
+ * @author alanrw
+ */
+public class ReplaceByComponentAction extends AbstractAction {
+ private static final long serialVersionUID = 7364648399658711574L;
+
+ private final EditManager em;
+ private final ComponentPreference prefs;
+ private final SelectionManager sm;
+ private final ComponentFactory factory;
+ private final Scufl2Tools tools = new Scufl2Tools();
+
+ private Processor selection;
+
+ public ReplaceByComponentAction(ComponentPreference prefs,
+ ComponentFactory factory, EditManager em, SelectionManager sm,
+ ComponentServiceIcon icon) {
+ super("Replace by component...", icon.getIcon());
+ this.prefs = prefs;
+ this.em = em;
+ this.sm = sm;
+ this.factory = factory;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ JPanel overallPanel = new JPanel(new BorderLayout());
+ ComponentChooserPanel panel = new ComponentChooserPanel(prefs);
+ overallPanel.add(panel, CENTER);
+ JPanel checkBoxPanel = new JPanel(new FlowLayout());
+ JCheckBox replaceAllCheckBox = new JCheckBox(
+ "Replace all matching services");
+ checkBoxPanel.add(replaceAllCheckBox);
+ checkBoxPanel.add(new JSeparator());
+ JCheckBox renameServicesCheckBox = new JCheckBox("Rename service(s)");
+ checkBoxPanel.add(renameServicesCheckBox);
+ renameServicesCheckBox.setSelected(true);
+ overallPanel.add(checkBoxPanel, SOUTH);
+ int answer = showConfirmDialog(null, overallPanel, "Component choice",
+ OK_CANCEL_OPTION);
+ if (answer == OK_OPTION)
+ doReplace(panel.getChosenRegistry(), panel.getChosenFamily(),
+ replaceAllCheckBox.isSelected(),
+ renameServicesCheckBox.isSelected(),
+ panel.getChosenComponent());
+ }
+
+ private void doReplace(Registry chosenRegistry, Family chosenFamily,
+ boolean replaceAll, boolean rename, Component chosenComponent) {
+ Version chosenVersion = chosenComponent.getComponentVersionMap().get(
+ chosenComponent.getComponentVersionMap().lastKey());
+ Version.ID ident = new Version.Identifier(
+ chosenRegistry.getRegistryBase(), chosenFamily.getName(),
+ chosenComponent.getName(), chosenVersion.getVersionNumber());
+
+ ComponentActivityConfigurationBean cacb = new ComponentActivityConfigurationBean(
+ ident, factory);
+
+ try {
+ if (replaceAll) {
+ Activity baseActivity = selection.getActivity(sm
+ .getSelectedProfile());
+ URI activityType = baseActivity.getType();
+ String configString = getConfigString(baseActivity);
+
+ replaceAllMatchingActivities(activityType, cacb, configString,
+ rename, sm.getSelectedWorkflow());
+ } else
+ replaceActivity(cacb, selection, rename,
+ sm.getSelectedWorkflow());
+ } catch (Exception e) {
+ showMessageDialog(
+ null,
+ "Failed to replace nested workflow with component: "
+ + e.getMessage(), "Component Problem",
+ ERROR_MESSAGE);
+ }
+ }
+
+ private String getConfigString(Activity baseActivity) {
+ return baseActivity.getConfiguration().getJsonAsString();
+ }
+
+ private void replaceAllMatchingActivities(URI activityType,
+ ComponentActivityConfigurationBean cacb, String configString,
+ boolean rename, Workflow d) throws IntermediateException {
+ for (Processor p : d.getProcessors()) {
+ Activity a = p.getActivity(sm.getSelectedProfile());
+ if (a.getType().equals(activityType)
+ && getConfigString(a).equals(configString))
+ replaceActivity(cacb, p, rename, d);
+ else if (a.getType().equals(NESTED_WORKFLOW))
+ replaceAllMatchingActivities(activityType, cacb, configString,
+ rename,
+ tools.nestedWorkflowForProcessor(p, a.getParent()));
+ }
+ }
+
+ private void replaceActivity(ComponentActivityConfigurationBean cacb,
+ Processor p, boolean rename, Workflow d) throws IntermediateException {
+ final Activity originalActivity = p.getActivity(sm.getSelectedProfile());
+ final List<Edit<?>> currentWorkflowEditList = new ArrayList<>();
+
+ Activity replacementActivity = new Activity();
+ try {
+ URI configType;
+ replacementActivity.createConfiguration(configType);
+
+ replacementActivity.configure(cacb);
+ //FIXME
+ } catch (Exception e) {
+ throw new IntermediateException(
+ "Unable to configure component", e);
+ }
+ if (originalActivity.getInputPorts().size() != replacementActivity
+ .getInputPorts().size())
+ throw new IntermediateException(
+ "Component does not have matching ports", null);
+
+ int replacementOutputSize = replacementActivity.getOutputPorts().size();
+ int originalOutputSize = originalActivity.getOutputPorts().size();
+ for (String name : ignorableNames) {
+ if (originalActivity.getOutputPorts().getByName(name) != null)
+ originalOutputSize--;
+ if (replacementActivity.getOutputPorts().getByName(name) != null)
+ replacementOutputSize--;
+ }
+
+ int sizeDifference = replacementOutputSize - originalOutputSize;
+ if (sizeDifference != 0)
+ throw new IntermediateException(
+ "Component does not have matching ports", null);
+
+ for (InputActivityPort aip : originalActivity.getInputPorts()) {
+ String aipName = aip.getName();
+ int aipDepth = aip.getDepth();
+ InputActivityPort caip = replacementActivity.getInputPorts().getByName(aipName);
+ if ((caip == null) || (caip.getDepth() != aipDepth))
+ throw new RuntimeException("Original input port "
+ + aipName + " is not matched");
+ }
+ for (OutputActivityPort aop : originalActivity.getOutputPorts()) {
+ String aopName = aop.getName();
+ int aopDepth = aop.getDepth();
+ OutputActivityPort caop = replacementActivity.getOutputPorts().getByName(aopName);
+ if ((caop == null || aopDepth != caop.getDepth())
+ && !ignorableNames.contains(aopName))
+ throw new IntermediateException(
+ "Original output port " + aopName + " is not matched", null);
+ }
+
+ for (InputProcessorPort pip : p.getInputPorts()) {
+ InputActivityPort iap = replacementActivity.getInputPorts()
+ .getByName(pip.getName());
+ if (iap == null)
+ iap = new InputActivityPort(replacementActivity, pip.getName());
+ currentWorkflowEditList.add(new AddActivityInputPortMappingEdit(
+ replacementActivity, pip, iap));
+ }
+
+ for (OutputProcessorPort pop : p.getOutputPorts()) {
+ OutputActivityPort oap = replacementActivity.getOutputPorts()
+ .getByName(pop.getName());
+ if (oap == null)
+ oap = new OutputActivityPort(replacementActivity, pop.getName());
+ currentWorkflowEditList.add(new AddActivityOutputPortMappingEdit(
+ replacementActivity, pop, oap));
+ }
+
+ currentWorkflowEditList
+ .add(new AddActivityEdit(p, replacementActivity));
+ currentWorkflowEditList
+ .add(new RemoveActivityEdit(p, originalActivity));
+
+ if (rename) {
+ String possibleName = replacementActivity.getConfiguration()
+ .getJsonAsObjectNode().get(COMPONENT_NAME).textValue();
+ currentWorkflowEditList.add(new RenameEdit<>(p, uniqueName(
+ possibleName, d.getProcessors())));
+ }
+ try {
+ em.doDataflowEdit(d.getParent(), new CompoundEdit(
+ currentWorkflowEditList));
+ } catch (EditException e) {
+ throw new IntermediateException(
+ "Unable to replace with component", e);
+ }
+ }
+
+ public void setSelection(Processor selection) {
+ this.selection = selection;
+ }
+
+ @SuppressWarnings("serial")
+ private static class IntermediateException extends Exception {
+ IntermediateException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentMenuAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentMenuAction.java
new file mode 100644
index 0000000..470ad40
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/ReplaceByComponentMenuAction.java
@@ -0,0 +1,87 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import io.github.taverna_extras.component.api.ComponentFactory;
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.ui.menu.AbstractContextualMenuAction;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.selection.SelectionManager;
+
+/**
+ * @author alanrw
+ */
+public class ReplaceByComponentMenuAction extends AbstractContextualMenuAction {
+ private static final URI configureSection = URI
+ .create("http://taverna.sf.net/2009/contextMenu/configure");
+
+ private ComponentPreference preferences;
+ private EditManager editManager;
+ private SelectionManager selectionManager;
+ private ComponentFactory factory;
+ private ComponentServiceIcon icon;
+
+ public ReplaceByComponentMenuAction() {
+ super(configureSection, 75);
+ }
+
+ public void setPreferences(ComponentPreference preferences) {
+ this.preferences = preferences;
+ }
+
+ public void setEditManager(EditManager editManager) {
+ this.editManager = editManager;
+ }
+
+ public void setSelectionManager(SelectionManager selectionManager) {
+ this.selectionManager = selectionManager;
+ }
+
+ public void setComponentFactory(ComponentFactory factory) {
+ this.factory = factory;
+ }
+
+ public void setIcon(ComponentServiceIcon icon) {
+ this.icon = icon;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ Object selection = getContextualSelection().getSelection();
+ if (!super.isEnabled())
+ return false;
+ return (selection instanceof Processor);
+ }
+
+ @Override
+ protected Action createAction() {
+ ReplaceByComponentAction action = new ReplaceByComponentAction(
+ preferences, factory, editManager, selectionManager, icon);
+ action.setSelection((Processor) getContextualSelection().getSelection());
+ return action;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/AbstractComponentMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/AbstractComponentMenuAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/AbstractComponentMenuAction.java
new file mode 100644
index 0000000..671e190
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/AbstractComponentMenuAction.java
@@ -0,0 +1,31 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import static io.github.taverna_extras.component.ui.menu.component.ComponentMenuSection.COMPONENT_SECTION;
+
+import java.net.URI;
+import org.apache.taverna.ui.menu.AbstractMenuAction;
+
+abstract class AbstractComponentMenuAction extends AbstractMenuAction {
+ public AbstractComponentMenuAction(int positionHint, URI id) {
+ super(COMPONENT_SECTION, positionHint, id);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseAction.java
new file mode 100644
index 0000000..da22a60
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseAction.java
@@ -0,0 +1,73 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import io.github.taverna_extras.component.ui.util.Utils;
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.file.events.FileManagerEvent;
+
+/**
+ * @author alanrw
+ */
+public class ComponentCloseAction extends AbstractAction implements
+ Observer<FileManagerEvent> {
+ private static final long serialVersionUID = -153986599735293879L;
+ private static final String CLOSE_COMPONENT = "Close component";
+ @SuppressWarnings("unused")
+ private static Logger logger = getLogger(ComponentCloseAction.class);
+
+ private Action closeAction;
+ private final Utils utils;
+
+ public ComponentCloseAction(Action closeWorkflowAction, FileManager fm,
+ ComponentServiceIcon icon, Utils utils) {
+ super(CLOSE_COMPONENT, icon.getIcon());
+ closeAction = closeWorkflowAction;
+ this.utils = utils;
+ fm.addObserver(this);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ closeAction.actionPerformed(arg0);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return utils.currentDataflowIsComponent();
+ }
+
+ @Override
+ public void notify(Observable<FileManagerEvent> sender,
+ FileManagerEvent message) throws Exception {
+ setEnabled(utils.currentDataflowIsComponent());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseMenuAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseMenuAction.java
new file mode 100644
index 0000000..6c40a5f
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCloseMenuAction.java
@@ -0,0 +1,66 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import io.github.taverna_extras.component.ui.util.Utils;
+import org.apache.taverna.workbench.file.FileManager;
+
+/**
+ * @author alanrw
+ */
+public class ComponentCloseMenuAction extends AbstractComponentMenuAction {
+ private static final URI CLOSE_COMPONENT_URI = URI
+ .create("http://taverna.sf.net/2008/t2workbench/menu#componentClose");
+
+ private Action action;
+ private FileManager fm;
+ private ComponentServiceIcon icon;
+ private Utils utils;
+
+ public ComponentCloseMenuAction() {
+ super(1000, CLOSE_COMPONENT_URI);
+ }
+
+ public void setCloseWorkflowAction(Action action) {
+ this.action = action;
+ }
+
+ public void setFileManager(FileManager fm) {
+ this.fm = fm;
+ }
+
+ public void setIcon(ComponentServiceIcon icon) {
+ this.icon = icon;
+ }
+
+ public void setUtils(Utils utils) {
+ this.utils = utils;
+ }
+
+ @Override
+ protected Action createAction() {
+ return new ComponentCloseAction(action, fm, icon, utils);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyAction.java
new file mode 100644
index 0000000..676a6c9
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyAction.java
@@ -0,0 +1,164 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import static java.awt.GridBagConstraints.BOTH;
+import static java.awt.GridBagConstraints.WEST;
+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.log4j.Logger.getLogger;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JPanel;
+import javax.swing.border.TitledBorder;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.Component;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.Family;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.api.profile.Profile;
+import io.github.taverna_extras.component.ui.panel.ComponentChoiceMessage;
+import io.github.taverna_extras.component.ui.panel.ComponentChooserPanel;
+import io.github.taverna_extras.component.ui.panel.ProfileChoiceMessage;
+import io.github.taverna_extras.component.ui.panel.RegistryAndFamilyChooserPanel;
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceProviderConfig;
+import io.github.taverna_extras.component.ui.util.Utils;
+import org.apache.taverna.lang.observer.Observable;
+import org.apache.taverna.lang.observer.Observer;
+
+/**
+ * @author alanrw
+ */
+public class ComponentCopyAction extends AbstractAction {
+ private static final long serialVersionUID = -4440978712410081685L;
+ private static final Logger logger = getLogger(ComponentCopyAction.class);
+ private static final String COPY_COMPONENT = "Copy component...";
+
+ private final ComponentPreference prefs;
+ private final Utils utils;
+
+ public ComponentCopyAction(ComponentPreference pref, ComponentServiceIcon icon, Utils utils) {
+ super(COPY_COMPONENT, icon.getIcon());
+ this.prefs = pref;
+ this.utils = utils;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ JPanel overallPanel = new JPanel();
+ overallPanel.setLayout(new GridBagLayout());
+
+ GridBagConstraints gbc = new GridBagConstraints();
+
+ ComponentChooserPanel source = new ComponentChooserPanel(prefs);
+ source.setBorder(new TitledBorder("Source component"));
+
+ gbc.insets = new Insets(0, 5, 0, 5);
+ gbc.gridx = 0;
+ gbc.gridy = 0;
+ gbc.anchor = WEST;
+ gbc.fill = BOTH;
+ gbc.gridwidth = 2;
+ gbc.weightx = 1;
+ overallPanel.add(source, gbc);
+
+ final RegistryAndFamilyChooserPanel target = new RegistryAndFamilyChooserPanel(prefs);
+ target.setBorder(new TitledBorder("Target family"));
+ gbc.gridy++;
+ overallPanel.add(target, gbc);
+
+ source.addObserver(new Observer<ComponentChoiceMessage>() {
+ @Override
+ public void notify(Observable<ComponentChoiceMessage> sender,
+ ComponentChoiceMessage message) throws Exception {
+ Profile componentProfile = null;
+ Family componentFamily = message.getComponentFamily();
+ if (componentFamily != null)
+ componentProfile = componentFamily.getComponentProfile();
+ ProfileChoiceMessage profileMessage = new ProfileChoiceMessage(
+ componentProfile);
+ target.notify(null, profileMessage);
+ }
+ });
+
+ int answer = showConfirmDialog(null, overallPanel, "Copy Component",
+ OK_CANCEL_OPTION);
+ if (answer == OK_OPTION)
+ doCopy(source.getChosenComponent(), target.getChosenFamily());
+ }
+
+ private void doCopy(Component sourceComponent, Family targetFamily) {
+ if (sourceComponent == null) {
+ showMessageDialog(null, "Unable to determine source component",
+ "Component Copy Problem", ERROR_MESSAGE);
+ return;
+ } else if (targetFamily == null) {
+ showMessageDialog(null, "Unable to determine target family",
+ "Component Copy Problem", ERROR_MESSAGE);
+ return;
+ }
+
+ try {
+ String componentName = sourceComponent.getName();
+ boolean alreadyUsed = targetFamily.getComponent(componentName) != null;
+ if (alreadyUsed)
+ showMessageDialog(null, componentName + " is already used",
+ "Duplicate component name", ERROR_MESSAGE);
+ else {
+ Version targetVersion = doCopy(sourceComponent, targetFamily,
+ componentName);
+ try {
+ utils.refreshComponentServiceProvider(new ComponentServiceProviderConfig(
+ targetVersion.getID()).getConfiguration());
+ } catch (Exception e) {
+ logger.error(e);
+ }
+ }
+ } catch (ComponentException e) {
+ logger.error("failed to copy component", e);
+ showMessageDialog(null,
+ "Unable to create component: " + e.getMessage(),
+ "Component Copy Problem", ERROR_MESSAGE);
+ }
+ }
+
+ private Version doCopy(Component sourceComponent, Family targetFamily,
+ String componentName) throws ComponentException {
+ return targetFamily
+ .createComponentBasedOn(
+ componentName,
+ sourceComponent.getDescription(),
+ sourceComponent
+ .getComponentVersionMap()
+ .get(sourceComponent.getComponentVersionMap()
+ .lastKey()).getImplementation());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyMenuAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyMenuAction.java
new file mode 100644
index 0000000..3c6db63
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCopyMenuAction.java
@@ -0,0 +1,61 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+import java.net.URI;
+
+import javax.swing.Action;
+
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import io.github.taverna_extras.component.ui.util.Utils;
+
+/**
+ * @author alanrw
+ */
+public class ComponentCopyMenuAction extends AbstractComponentMenuAction {
+ private static final URI COPY_COMPONENT_URI = URI
+ .create("http://taverna.sf.net/2008/t2workbench/menu#componentCopy");
+
+ private ComponentPreference prefs;
+ private ComponentServiceIcon icon;
+ private Utils utils;
+
+ public ComponentCopyMenuAction() {
+ super(800, COPY_COMPONENT_URI);
+ }
+
+ public void setIcon(ComponentServiceIcon icon) {
+ this.icon = icon;
+ }
+
+ public void setPreferences(ComponentPreference prefs) {//FIXME beaninject
+ this.prefs = prefs;
+ }
+
+ public void setUtils(Utils utils) {
+ this.utils = utils;
+ }
+
+ @Override
+ protected Action createAction() {
+ return new ComponentCopyAction(prefs, icon, utils);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCreatorSupport.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCreatorSupport.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCreatorSupport.java
new file mode 100644
index 0000000..ffe26d8
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentCreatorSupport.java
@@ -0,0 +1,257 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+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.log4j.Logger.getLogger;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.Component;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.ComponentFactory;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.ui.ComponentActivityConfigurationBean;
+import io.github.taverna_extras.component.ui.panel.RegistryAndFamilyChooserComponentEntryPanel;
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceProviderConfig;
+import io.github.taverna_extras.component.ui.util.Utils;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.DataLink;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.port.InputProcessorPort;
+import org.apache.taverna.scufl2.api.port.InputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.OutputProcessorPort;
+import org.apache.taverna.scufl2.api.port.OutputWorkflowPort;
+import org.apache.taverna.workbench.edits.CompoundEdit;
+import org.apache.taverna.workbench.edits.Edit;
+import org.apache.taverna.workbench.edits.EditException;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.file.FileType;
+import org.apache.taverna.workbench.file.exceptions.SaveException;
+import org.apache.taverna.workbench.selection.SelectionManager;
+import org.apache.taverna.workflow.edits.AddActivityEdit;
+import org.apache.taverna.workflow.edits.AddActivityInputPortMappingEdit;
+import org.apache.taverna.workflow.edits.AddActivityOutputPortMappingEdit;
+import org.apache.taverna.workflow.edits.AddDataLinkEdit;
+import org.apache.taverna.workflow.edits.AddProcessorEdit;
+import org.apache.taverna.workflow.edits.AddWorkflowInputPortEdit;
+import org.apache.taverna.workflow.edits.AddWorkflowOutputPortEdit;
+import org.apache.taverna.workflow.edits.RemoveActivityEdit;
+import org.apache.taverna.workflow.edits.RenameEdit;
+import org.apache.taverna.workflowmodel.processor.activity.NestedDataflow;
+import org.apache.taverna.workflowmodel.utils.Tools;
+
+public class ComponentCreatorSupport {
+ private static final Logger logger = getLogger(ComponentCreatorSupport.class);
+
+ private ComponentFactory factory;
+ private FileManager fm;
+ private EditManager em;
+ private ComponentPreference prefs;
+ private FileType ft;
+ private SelectionManager sm;
+
+ public void setComponentFactory(ComponentFactory factory) {
+ this.factory = factory;
+ }
+
+ public void setPreferences(ComponentPreference pref) {
+ this.prefs = pref;
+ }
+
+ public void setFileManager(FileManager fm) {
+ this.fm = fm;
+ }
+
+ public void setEditManager(EditManager em) {
+ this.em = em;
+ }
+
+ public void setFileType(FileType ft) {
+ this.ft = ft;
+ }
+
+ public void setSelectionManager(SelectionManager sm) {
+ this.sm = sm;
+ }
+
+ public class CopiedProcessor {
+ Processor processor;
+ Map<String,Workflow> requiredSubworkflows;
+ }
+
+ void moveComponentActivityIntoPlace(Activity toReplace, Processor contextProcessor,
+ Activity replacingActivity) throws EditException {
+ List<Edit<?>> editsToDo = new ArrayList<>();
+ for (InputProcessorPort pip : contextProcessor.getInputPorts())
+ editsToDo.add(new AddActivityInputPortMappingEdit(toReplace, pip, null/*FIXME*/));
+ for (OutputProcessorPort pop : contextProcessor.getOutputPorts())
+ editsToDo.add(new AddActivityOutputPortMappingEdit(toReplace, pop, null/*FIXME*/));
+ editsToDo.add(new RemoveActivityEdit(contextProcessor, toReplace));
+ editsToDo.add(new AddActivityEdit(contextProcessor, replacingActivity));
+ em.doDataflowEdit(contextProcessor.getParent().getParent(),
+ new CompoundEdit(editsToDo));
+ }
+
+ void connectNewProcessor(Workflow d, Processor newProcessor)
+ throws EditException {
+ List<Edit<?>> editsToDo = new ArrayList<>();
+
+ for (InputProcessorPort pip : newProcessor.getInputPorts()) {
+ InputWorkflowPort dip = new InputWorkflowPort(d, pip.getName());
+ // FIXME How to set depth?
+ editsToDo.add(new AddWorkflowInputPortEdit(d, dip));
+ editsToDo.add(new AddDataLinkEdit(d, new DataLink(d, dip, pip)));
+ }
+
+ for (OutputProcessorPort pop : newProcessor.getOutputPorts()) {
+ OutputWorkflowPort dop = new OutputWorkflowPort(d, pop.getName());
+ // TODO How to indicate depth?
+ editsToDo.add(new AddWorkflowOutputPortEdit(d, dop));
+ editsToDo.add(new AddDataLinkEdit(d, new DataLink(d, pop, dop)));
+ }
+ em.doDataflowEdit(d.getParent(), new CompoundEdit(editsToDo));
+ }
+
+ public ComponentActivityConfigurationBean saveWorkflowAsComponent(
+ WorkflowBundle d, Version.ID ident) throws SaveException, IOException,
+ ComponentException {
+ if (ident == null)
+ return null;
+
+ createInitialComponent(d, ident);
+
+ Utils.refreshComponentServiceProvider(new ComponentServiceProviderConfig(
+ ident));
+ return new ComponentActivityConfigurationBean(ident, factory);
+ }
+
+ public ComponentActivityConfigurationBean saveWorkflowAsComponent(
+ Workflow d, Version.ID ident) throws SaveException, IOException,
+ ComponentException {
+ WorkflowBundle b = new WorkflowBundle();
+ ((Workflow)d.clone()).setParent(b);
+ //FIXME also must copy profile parts!
+ return saveWorkflowAsComponent(b, ident);
+ }
+
+ Version.ID getNewComponentIdentification(String defaultName) {
+ RegistryAndFamilyChooserComponentEntryPanel panel = new RegistryAndFamilyChooserComponentEntryPanel(prefs);
+ panel.setComponentName(defaultName);
+ int result = showConfirmDialog(null, panel, "Component location",
+ OK_CANCEL_OPTION);
+ if (result != OK_OPTION)
+ return null;
+
+ Version.ID ident = panel.getComponentVersionIdentification();
+ if (ident == null) {
+ showMessageDialog(null,
+ "Not enough information to create component",
+ "Component creation problem", ERROR_MESSAGE);
+ return null;
+ }
+
+ try {
+ Component existingComponent = factory.getComponent(ident);
+ if (existingComponent != null) {
+ showMessageDialog(null,
+ "Component with this name already exists",
+ "Component creation problem", ERROR_MESSAGE);
+ return null;
+ }
+ } catch (ComponentException e) {
+ logger.error("failed to search registry", e);
+ showMessageDialog(null,
+ "Problem searching registry: " + e.getMessage(),
+ "Component creation problem", ERROR_MESSAGE);
+ return null;
+ }
+ return ident;
+ }
+
+ CopiedProcessor copyProcessor(Processor p) throws IOException {
+ CopiedProcessor copy = new CopiedProcessor();
+ copy.processor = ProcessorXMLSerializer.getInstance().processorToXML(p);
+ copy.requiredSubworkflows = new HashMap<>();
+ rememberSubworkflows(p, copy);
+ return copy;
+ }
+
+ void rememberSubworkflows(Processor p, CopiedProcessor copy) {
+ for (Activity a : p.getActivity(sm.getSelectedProfile()))
+ if (a instanceof NestedDataflow) {
+ NestedDataflow da = (NestedDataflow) a;
+ Workflow df = da.getNestedDataflow();
+ if (!copy.requiredSubworkflows.containsKey(df.getIdentifier())) {
+ copy.requiredSubworkflows.put(df.getIdentifier(),
+ DataflowXMLSerializer.getInstance()
+ .serializeDataflow(df));
+ for (Processor sp : df.getProcessors())
+ rememberSubworkflows(sp, copy);
+ }
+ }
+ }
+
+ public Processor pasteProcessor(CopiedProcessor copy, Workflow d)
+ throws
+ ClassNotFoundException, InstantiationException,
+ IllegalAccessException, EditException {
+ Processor result = ProcessorXMLDeserializer.getInstance()
+ .deserializeProcessor(copy.processor, copy.requiredSubworkflows);
+ if (result == null)
+ return null;
+
+ String newName = Tools.uniqueProcessorName(result.getName(), d);
+
+ List<Edit<?>> editList = new ArrayList<>();
+ if (!newName.equals(result.getName()))
+ editList.add(new RenameEdit<>(result, newName));
+ editList.add(new AddProcessorEdit(d, result));
+ em.doDataflowEdit(d.getParent(), new CompoundEdit(editList));
+
+ return result;
+ }
+
+ public Version.ID createInitialComponent(WorkflowBundle d, Version.ID ident)
+ throws ComponentException {
+ try {
+ fm.saveDataflow(d, ft, ident, false);
+
+ em.doDataflowEdit(d, new RenameEdit<>(d, d.getName()));
+ } catch (SaveException | IllegalStateException | EditException e) {
+ throw new ComponentException(e);
+ }
+ return ident;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentDeleteAction.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentDeleteAction.java b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentDeleteAction.java
new file mode 100644
index 0000000..72141c9
--- /dev/null
+++ b/taverna-component-activity-ui/src/main/java/io/github/taverna_extras/component/ui/menu/component/ComponentDeleteAction.java
@@ -0,0 +1,143 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package io.github.taverna_extras.component.ui.menu.component;
+
+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.YES_NO_OPTION;
+import static javax.swing.JOptionPane.YES_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.awt.event.ActionEvent;
+import java.util.concurrent.ExecutionException;
+
+import javax.swing.AbstractAction;
+import javax.swing.SwingWorker;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.Component;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.ui.panel.ComponentChooserPanel;
+import io.github.taverna_extras.component.ui.preference.ComponentPreference;
+import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceIcon;
+import io.github.taverna_extras.component.ui.serviceprovider.ComponentServiceProviderConfig;
+import io.github.taverna_extras.component.ui.util.Utils;
+
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.workbench.file.FileManager;
+
+/**
+ * @author alanrw
+ */
+public class ComponentDeleteAction extends AbstractAction {
+ private static final String COMPONENT_PROBLEM_TITLE = "Component Problem";
+ private static final String CONFIRM_MSG = "Are you sure you want to delete %s?";
+ private static final String CONFIRM_TITLE = "Delete Component Confirmation";
+ private static final String DELETE_COMPONENT_LABEL = "Delete component...";
+ private static final String DELETE_FAILED_TITLE = "Component Deletion Error";
+ private static final String FAILED_MSG = "Unable to delete %s: %s";
+ private static final String OPEN_COMPONENT_MSG = "The component is open";
+ private static final String TITLE = "Component choice";
+ private static final String WHAT_COMPONENT_MSG = "Unable to determine component";
+ private static final long serialVersionUID = -2992743162132614936L;
+ private static final Logger logger = getLogger(ComponentDeleteAction.class);
+
+ private final FileManager fm;
+ private final ComponentPreference prefs;
+ private final Utils utils;
+
+ public ComponentDeleteAction(FileManager fm, ComponentPreference prefs,
+ ComponentServiceIcon icon, Utils utils) {
+ super(DELETE_COMPONENT_LABEL, icon.getIcon());
+ this.fm = fm;
+ this.prefs = prefs;
+ this.utils = utils;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent evt) {
+ ComponentChooserPanel panel = new ComponentChooserPanel(prefs);
+ int answer = showConfirmDialog(null, panel, TITLE, OK_CANCEL_OPTION);
+ if (answer == OK_OPTION)
+ doDelete(panel.getChosenComponent());
+ }
+
+ private void doDelete(final Component chosenComponent) {
+ if (chosenComponent == null) {
+ showMessageDialog(null, WHAT_COMPONENT_MSG,
+ COMPONENT_PROBLEM_TITLE, ERROR_MESSAGE);
+ } else if (componentIsInUse(chosenComponent)) {
+ showMessageDialog(null, OPEN_COMPONENT_MSG,
+ COMPONENT_PROBLEM_TITLE, ERROR_MESSAGE);
+ } else if (showConfirmDialog(null,
+ format(CONFIRM_MSG, chosenComponent.getName()), CONFIRM_TITLE,
+ YES_NO_OPTION) == YES_OPTION)
+ new SwingWorker<Configuration, Object>() {
+ @Override
+ protected Configuration doInBackground() throws Exception {
+ return deleteComponent(chosenComponent);
+ }
+
+ @Override
+ protected void done() {
+ refresh(chosenComponent, this);
+ }
+ }.execute();
+ }
+
+ private Configuration deleteComponent(Component component)
+ throws ComponentException {
+ ComponentServiceProviderConfig config = new ComponentServiceProviderConfig(
+ component.getFamily());
+ component.delete();
+ return config.getConfiguration();
+ }
+
+ protected void refresh(Component component,
+ SwingWorker<Configuration, Object> worker) {
+ try {
+ utils.refreshComponentServiceProvider(worker.get());
+ } catch (ExecutionException e) {
+ logger.error("failed to delete component", e.getCause());
+ showMessageDialog(
+ null,
+ format(FAILED_MSG, component.getName(), e.getCause()
+ .getMessage()), DELETE_FAILED_TITLE, ERROR_MESSAGE);
+ } catch (InterruptedException e) {
+ logger.warn("interrupted during component deletion", e);
+ }
+ }
+
+ private boolean componentIsInUse(Component component) {
+ for (WorkflowBundle d : fm.getOpenDataflows()) {
+ Object dataflowSource = fm.getDataflowSource(d);
+ if (dataflowSource instanceof Version.ID
+ && ((Version.ID) dataflowSource).mostlyEqualTo(component))
+ return true;
+ }
+ return false;
+ }
+}