You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/03/20 15:22:46 UTC
[32/51] [abbrv] [partial] incubator-taverna-workbench git commit:
taverna-workbench-* -> taverna-*
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/DefaultGraphEventManager.java
----------------------------------------------------------------------
diff --git a/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/DefaultGraphEventManager.java b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/DefaultGraphEventManager.java
new file mode 100644
index 0000000..d434e48
--- /dev/null
+++ b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/DefaultGraphEventManager.java
@@ -0,0 +1,271 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.models.graph;
+
+import static javax.swing.SwingUtilities.convertPointFromScreen;
+import static javax.swing.SwingUtilities.invokeLater;
+import static net.sf.taverna.t2.workbench.models.graph.GraphController.PortStyle.ALL;
+import static net.sf.taverna.t2.workbench.models.graph.GraphController.PortStyle.NONE;
+
+import java.awt.Component;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.net.URI;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import net.sf.taverna.t2.ui.menu.MenuManager;
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.common.Scufl2Tools;
+import uk.org.taverna.scufl2.api.core.Processor;
+import uk.org.taverna.scufl2.api.profiles.ProcessorBinding;
+
+/**
+ * Manager for handling UI events on GraphElements.
+ *
+ * @author David Withers
+ */
+public class DefaultGraphEventManager implements GraphEventManager {
+ private static final URI NESTED_WORKFLOW_URI = URI
+ .create("http://ns.taverna.org.uk/2010/activity/nested-workflow");
+
+ private GraphController graphController;
+ private Component component;
+ private JPopupMenu menu;
+ private MenuManager menuManager;
+
+ private Scufl2Tools scufl2Tools = new Scufl2Tools();
+
+ /**
+ * Constructs a new instance of GraphEventManager.
+ *
+ * @param graphController
+ * @param component
+ * component to use when displaying popup menus
+ */
+ public DefaultGraphEventManager(GraphController graphController, Component component,
+ MenuManager menuManager) {
+ this.graphController = graphController;
+ this.component = component;
+ this.menuManager = menuManager;
+ }
+
+ @Override
+ public void mouseClicked(final GraphElement graphElement, short button, boolean altKey,
+ boolean ctrlKey, boolean metaKey, final int x, final int y, int screenX, int screenY) {
+ Object dataflowObject = graphElement.getWorkflowBean();
+
+ // For both left and right click - add to selection model
+ if (graphController.getDataflowSelectionModel() != null)
+ graphController.getDataflowSelectionModel().addSelection(dataflowObject);
+
+ if ((button != 2) && !ctrlKey)return;
+
+ // If this was a right click - show a pop-up as well
+ if (dataflowObject == null)
+ menu = menuManager.createContextMenu(graphController.getWorkflow(),
+ graphController.getWorkflow(), component);
+ else {
+ menu = menuManager.createContextMenu(graphController.getWorkflow(),
+ dataflowObject, component);
+ if (dataflowObject instanceof Processor) {
+ final Processor processor = (Processor) dataflowObject;
+ ProcessorBinding processorBinding = scufl2Tools
+ .processorBindingForProcessor(processor,
+ graphController.getProfile());
+ final Activity activity = processorBinding.getBoundActivity();
+ if (menu == null)
+ menu = new JPopupMenu();
+ if (graphElement instanceof GraphNode) {
+ defineMenuForGraphElement(graphElement, x, y, processor,
+ activity);
+ } else if (graphElement instanceof Graph) {
+ defineMenuForGraphBackground(activity);
+ }
+ }
+ }
+
+ if (menu != null) {
+ final Point p = new Point(screenX, screenY);
+ convertPointFromScreen(p, component);
+ invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ menu.show(component, p.x, p.y);
+ }
+ });
+ }
+ }
+
+ @SuppressWarnings("serial")
+ private void defineMenuForGraphBackground(final Activity activity) {
+ if (activity.getType().equals(NESTED_WORKFLOW_URI)) {
+ menu.addSeparator();
+ menu.add(new JMenuItem(new AbstractAction("Hide nested workflow") {
+ @Override
+ public void actionPerformed(ActionEvent ev) {
+ graphController.setExpandNestedDataflow(activity, false);
+ graphController.redraw();
+ }
+ }));
+ }
+ }
+
+ @SuppressWarnings("serial")
+ private void defineMenuForGraphElement(final GraphElement graphElement,
+ final int x, final int y, final Processor processor,
+ final Activity activity) {
+ if (graphController.getPortStyle(processor).equals(NONE)) {
+ menu.addSeparator();
+ menu.add(new JMenuItem(new AbstractAction("Show ports") {
+ @Override
+ public void actionPerformed(ActionEvent ev) {
+ graphController.setPortStyle(processor, ALL);
+ graphController.redraw();
+ }
+ }));
+ } else if (graphController.getPortStyle(processor).equals(ALL)) {
+ menu.addSeparator();
+ menu.add(new JMenuItem(new AbstractAction("Hide ports") {
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ graphController.setPortStyle(processor, NONE);
+ graphController.redraw();
+ }
+ }));
+ }
+
+ if (activity.getType().equals(NESTED_WORKFLOW_URI)) {
+ menu.addSeparator();
+ menu.add(new JMenuItem(new AbstractAction("Show nested workflow") {
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ graphController.setExpandNestedDataflow(activity, true);
+ graphController.redraw();
+ }
+ }));
+ }
+
+ menu.addSeparator();
+
+ GraphNode graphNode = (GraphNode) graphElement;
+
+ List<GraphNode> sourceNodes = graphNode.getSourceNodes();
+ if (sourceNodes.size() == 1) {
+ final GraphNode sourceNode = sourceNodes.get(0);
+ if (sourceNode.getLabel() != null) {
+ menu.add(new JMenuItem(new AbstractAction("Link from output '"
+ + sourceNode.getLabel() + "'") {
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ graphController.startEdgeCreation(sourceNode,
+ new Point(x, y));
+ }
+ }));
+ }
+ } else if (sourceNodes.size() > 0) {
+ JMenu linkMenu = new JMenu("Link from output...");
+ menu.add(linkMenu);
+ for (final GraphNode sourceNode : sourceNodes) {
+ linkMenu.add(new JMenuItem(new AbstractAction(sourceNode
+ .getLabel()) {
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ graphController.startEdgeCreation(sourceNode,
+ new Point(x, y));
+ }
+ }));
+ }
+ }
+
+ List<GraphNode> sinkNodes = graphNode.getSinkNodes();
+ if (sinkNodes.size() == 1) {
+ final GraphNode sinkNode = sinkNodes.get(0);
+ if (sinkNode.getLabel() != null) {
+ menu.add(new JMenuItem(new AbstractAction("Link to input '"
+ + sinkNode.getLabel() + "'") {
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ graphController.startEdgeCreation(sinkNode, new Point(
+ x, y));
+ }
+ }));
+ }
+ } else if (sinkNodes.size() > 0) {
+ JMenu linkMenu = new JMenu("Link to input...");
+ menu.add(linkMenu);
+ for (final GraphNode sinkNode : sinkNodes) {
+ linkMenu.add(new JMenuItem(new AbstractAction(sinkNode
+ .getLabel()) {
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ graphController.startEdgeCreation(sinkNode, new Point(
+ x, y));
+ }
+ }));
+ }
+ }
+ }
+
+ @Override
+ public void mouseDown(GraphElement graphElement, short button,
+ boolean altKey, boolean ctrlKey, boolean metaKey, int x, int y,
+ int screenX, int screenY) {
+ if (button == 0)
+ graphController.startEdgeCreation(graphElement, new Point(x, y));
+ }
+
+ @Override
+ public void mouseUp(GraphElement graphElement, short button,
+ boolean altKey, boolean ctrlKey, boolean metaKey, final int x,
+ final int y, int screenX, int screenY) {
+ if (button == 0)
+ graphController.stopEdgeCreation(graphElement, new Point(screenX,
+ screenY));
+ }
+
+ @Override
+ public void mouseMoved(GraphElement graphElement, short button,
+ boolean altKey, boolean ctrlKey, boolean metaKey, int x, int y,
+ int screenX, int screenY) {
+ graphController.moveEdgeCreationTarget(graphElement, new Point(x, y));
+ }
+
+ @Override
+ public void mouseOver(GraphElement graphElement, short button,
+ boolean altKey, boolean ctrlKey, boolean metaKey, int x, int y,
+ int screenX, int screenY) {
+ if (graphElement.getWorkflowBean() != null)
+ graphElement.setActive(true);
+ }
+
+ @Override
+ public void mouseOut(GraphElement graphElement, short button,
+ boolean altKey, boolean ctrlKey, boolean metaKey, int x, int y,
+ int screenX, int screenY) {
+ if (graphElement.getWorkflowBean() != null)
+ graphElement.setActive(false);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/DotWriter.java
----------------------------------------------------------------------
diff --git a/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/DotWriter.java b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/DotWriter.java
new file mode 100644
index 0000000..07cdbad
--- /dev/null
+++ b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/DotWriter.java
@@ -0,0 +1,253 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.models.graph;
+
+import static java.lang.String.format;
+import static net.sf.taverna.t2.workbench.models.graph.Graph.Alignment.HORIZONTAL;
+import static net.sf.taverna.t2.workbench.models.graph.Graph.Alignment.VERTICAL;
+import static net.sf.taverna.t2.workbench.models.graph.GraphElement.LineStyle.NONE;
+import static net.sf.taverna.t2.workbench.models.graph.GraphShapeElement.Shape.RECORD;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.List;
+
+import net.sf.taverna.t2.workbench.models.graph.Graph.Alignment;
+
+/**
+ * Writer for creating a graphical representation of a Graph in the DOT language.
+ *
+ * @author David Withers
+ */
+public class DotWriter {
+ private static final String EOL = System.getProperty("line.separator");
+
+ private Writer writer;
+
+ /**
+ * Constructs a new instance of DotWriter.
+ *
+ * @param writer
+ */
+ public DotWriter(Writer writer) {
+ this.writer = writer;
+ }
+
+ /**
+ * Writes a graphical representation of a Graph in the DOT language to a Writer.
+ *
+ * @param graph
+ * @throws IOException
+ */
+ public void writeGraph(Graph graph) throws IOException {
+ writeLine("digraph \"" + graph.getId() + "\" {");
+
+ // Overall graph style
+ writeLine(" graph [");
+ writeLine(" bgcolor=\"" + getHexValue(graph.getFillColor()) + "\"");
+ writeLine(" color=\"black\"");
+ writeLine(" fontsize=\"10\"");
+ writeLine(" labeljust=\"left\"");
+ writeLine(" clusterrank=\"local\"");
+ writeLine(" ranksep=\"0.22\"");
+ writeLine(" nodesep=\"0.05\"");
+ // Set left to right view if alignment is horizontal
+ if (graph.getAlignment().equals(HORIZONTAL))
+ writeLine(" rankdir=\"LR\"");
+ writeLine(" ]");
+
+ // Overall node style
+ writeLine(" node [");
+ writeLine(" fontname=\"Helvetica\"");
+ writeLine(" fontsize=\"10\"");
+ writeLine(" fontcolor=\"black\"");
+ writeLine(" shape=\"record\"");
+ writeLine(" height=\"0\"");
+ writeLine(" width=\"0\"");
+ writeLine(" color=\"black\"");
+ writeLine(" fillcolor=\"lightgoldenrodyellow\"");
+ writeLine(" style=\"filled\"");
+ writeLine(" ];");
+
+ // Overall edge style
+ writeLine(" edge [");
+ writeLine(" fontname=\"Helvetica\"");
+ writeLine(" fontsize=\"8\"");
+ writeLine(" fontcolor=\"black\"");
+ writeLine(" color=\"black\"");
+ writeLine(" ];");
+
+ for (GraphNode node : graph.getNodes()) {
+ if (node.isExpanded())
+ writeSubGraph(node.getGraph(), " ");
+ else
+ writeNode(node, graph.getAlignment(), " ");
+ }
+
+ for (Graph subGraph : graph.getSubgraphs())
+ writeSubGraph(subGraph, " ");
+
+ for (GraphEdge edge : graph.getEdges())
+ writeEdges(edge, graph.getAlignment(), " ");
+
+ writeLine("}");
+ }
+
+ private void writeSubGraph(Graph graph, String indent) throws IOException {
+ writeLine(format("%ssubgraph \"cluster_%s\" {", indent, graph.getId()));
+ writeLine(format("%s rank=\"same\"", indent));
+
+ StringBuilder style = new StringBuilder();
+ if (graph.getFillColor() != null) {
+ writeLine(format("%s fillcolor=\"%s\"", indent,
+ getHexValue(graph.getFillColor())));
+ style.append("filled");
+ }
+ if (graph.getLineStyle() != null) {
+ style.append(style.length() == 0 ? "" : ",");
+ if (graph.getLineStyle().equals(NONE))
+ style.append("invis");
+ else
+ style.append(graph.getLineStyle().toString().toLowerCase());
+ }
+ writeLine(format("%s style=\"%s\"", indent, style));
+
+ if (graph.getLabel() != null)
+ writeLine(format("%s label=\"%s\"", indent, graph.getLabel()));
+
+ for(GraphNode node : graph.getNodes()) {
+ if (node.isExpanded())
+ writeSubGraph(node.getGraph(), indent + " ");
+ else
+ writeNode(node, graph.getAlignment(), indent + " ");
+ }
+
+ for (Graph subGraph : graph.getSubgraphs())
+ writeSubGraph(subGraph, indent + " ");
+
+ for (GraphEdge edge : graph.getEdges())
+ writeEdges(edge, graph.getAlignment(), indent + " ");
+
+ writeLine(indent + "}");
+ }
+
+ private void writeEdges(GraphEdge edge, Alignment alignment, String indent) throws IOException {
+ GraphNode source = edge.getSource();
+ GraphNode sink = edge.getSink();
+ String sourceId = "\"" + source.getId() + "\"";
+ String sinkId = "\"" + sink.getId() + "\"";
+
+ if (source.getParent() instanceof GraphNode) {
+ GraphNode parent = (GraphNode) source.getParent();
+ sourceId = "\"" + parent.getId() + "\":" + sourceId;
+ }
+ if (sink.getParent() instanceof GraphNode) {
+ GraphNode parent = (GraphNode) sink.getParent();
+ sinkId = "\"" + parent.getId() + "\":" + sinkId;
+ }
+ /*
+ * the compass point is required with newer versions of dot (e.g.
+ * 2.26.3) but is not compatible with older versions (e.g. 1.3)
+ */
+ if (alignment.equals(HORIZONTAL)) {
+ sourceId = sourceId + ":e";
+ sinkId = sinkId + ":w";
+ } else {
+ sourceId = sourceId + ":s";
+ sinkId = sinkId + ":n";
+ }
+ writeLine(format("%s%s -> %s [", indent, sourceId, sinkId));
+ writeLine(format("%s arrowhead=\"%s\"", indent, edge
+ .getArrowHeadStyle().toString().toLowerCase()));
+ writeLine(format("%s, arrowtail=\"%s\"", indent, edge
+ .getArrowTailStyle().toString().toLowerCase()));
+ if (edge.getColor() != null)
+ writeLine(format("%s color=\"%s\"", indent,
+ getHexValue(edge.getColor())));
+ writeLine(format("%s]", indent));
+ }
+
+ private void writeNode(GraphNode node, Alignment alignment, String indent) throws IOException {
+ writeLine(format("%s\"%s\" [", indent, node.getId()));
+
+ StringBuilder style = new StringBuilder();
+ if (node.getFillColor() != null) {
+ writeLine(format("%s fillcolor=\"%s\"", indent,
+ getHexValue(node.getFillColor())));
+ style.append("filled");
+ }
+ if (node.getLineStyle() != null) {
+ style.append(style.length() == 0 ? "" : ",");
+ style.append(node.getLineStyle().toString().toLowerCase());
+ }
+ writeLine(format("%s style=\"%s\"", indent, style));
+
+ writeLine(format("%s shape=\"%s\"", indent, node.getShape().toString().toLowerCase()));
+ writeLine(format("%s width=\"%s\"", indent, node.getWidth() / 72f));
+ writeLine(format("%s height=\"%s\"", indent, node.getHeight() / 72f));
+
+ if (node.getShape().equals(RECORD)) {
+ StringBuilder labelString = new StringBuilder();
+ if (alignment.equals(VERTICAL)) {
+ labelString.append("{{");
+ addNodeLabels(node.getSinkNodes(), labelString);
+ labelString.append("}|").append(node.getLabel()).append("|{");
+ addNodeLabels(node.getSourceNodes(), labelString);
+ labelString.append("}}");
+ } else {
+ labelString.append(node.getLabel()).append("|{{");
+ addNodeLabels(node.getSinkNodes(), labelString);
+ labelString.append("}|{");
+ addNodeLabels(node.getSourceNodes(), labelString);
+ labelString.append("}}");
+ }
+ writeLine(format("%s label=\"%s\"", indent, labelString));
+ } else {
+ writeLine(format("%s label=\"%s\"", indent, node.getLabel()));
+ }
+
+ writeLine(format("%s];", indent));
+ }
+
+ private void addNodeLabels(List<GraphNode> nodes, StringBuilder labelString) {
+ String sep = "";
+ for (GraphNode node : nodes)
+ if (node.getLabel() != null) {
+ labelString.append(sep);
+ labelString.append("<");
+ labelString.append(node.getId());
+ labelString.append(">");
+ labelString.append(node.getLabel());
+ sep = "|";
+ }
+ }
+
+ private String getHexValue(Color color) {
+ return format("#%02x%02x%02x", color.getRed(), color.getGreen(),
+ color.getBlue());
+ }
+
+ private void writeLine(String line) throws IOException {
+ writer.write(line);
+ writer.write(EOL);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/Graph.java
----------------------------------------------------------------------
diff --git a/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/Graph.java b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/Graph.java
new file mode 100644
index 0000000..0ff3852
--- /dev/null
+++ b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/Graph.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.models.graph;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A graph model of a dataflow.
+ *
+ * @author David Withers
+ */
+public class Graph extends GraphShapeElement {
+ public enum Alignment {
+ HORIZONTAL, VERTICAL
+ }
+
+ private List<GraphNode> nodes = new ArrayList<>();
+ private Set<GraphEdge> edges = new HashSet<>();
+ private Set<Graph> subgraphs = new HashSet<>();
+ private Alignment alignment = Alignment.VERTICAL;
+
+ /**
+ * Constructs a Graph that uses the specified GraphEventManager to handle
+ * any user generated events on GraphElements.
+ *
+ * @param eventManager
+ */
+ public Graph(GraphController graphController) {
+ super(graphController);
+ }
+
+ /**
+ * Adds an edge to the Graph and sets its parent to be this Graph.
+ *
+ * @param edge
+ * the edge to add
+ */
+ public void addEdge(GraphEdge edge) {
+ edge.setParent(this);
+ edges.add(edge);
+ }
+
+ /**
+ * Adds a node to the Graph and sets its parent to be this Graph.
+ *
+ * @param node
+ * the node to add
+ */
+ public void addNode(GraphNode node) {
+ node.setParent(this);
+ nodes.add(node);
+ }
+
+ /**
+ * Adds a subgraph to the Graph and sets its parent to be this Graph.
+ *
+ * @param subgraph
+ * the subgraph to add
+ */
+ public void addSubgraph(Graph subgraph) {
+ subgraph.setParent(this);
+ subgraphs.add(subgraph);
+ }
+
+ /**
+ * Returns the alignment of the Graph.
+ *
+ * @return the alignment of the Graph
+ */
+ public Alignment getAlignment() {
+ return alignment;
+ }
+
+ /**
+ * Returns the edges contained in the Graph.
+ *
+ * @return the edges contained in the Graph
+ */
+ public Set<GraphEdge> getEdges() {
+ return Collections.unmodifiableSet(edges);
+ }
+
+ /**
+ * Returns the nodes contained in the Graph.
+ *
+ * @return the nodes contained in the Graph
+ */
+ public List<GraphNode> getNodes() {
+ return Collections.unmodifiableList(nodes);
+ }
+
+ /**
+ * Returns the subgraphs contained in the Graph.
+ *
+ * @return the subgraphs contained in the Graph
+ */
+ public Set<Graph> getSubgraphs() {
+ return Collections.unmodifiableSet(subgraphs);
+ }
+
+ /**
+ * Removes an edge from the Graph.
+ *
+ * @param edge
+ * the edge to remove
+ * @return true if the edge is removed from the Graph
+ */
+ public boolean removeEdge(GraphEdge edge) {
+ return edges.remove(edge);
+ }
+
+ /**
+ * Removes a node from the Graph.
+ *
+ * @param node
+ * the node to remove
+ * @return true if the node is removed from the Graph
+ */
+ public boolean removeNode(GraphNode node) {
+ return nodes.remove(node);
+ }
+
+ /**
+ * Removes a subgraph from the Graph.
+ *
+ * @param subgraph
+ * the subgraph to remove
+ * @return true if the subgraph is removed from the Graph
+ */
+ public boolean removeSubgraph(Graph subgraph) {
+ return subgraphs.remove(subgraph);
+ }
+
+ /**
+ * Sets the alignment of the Graph.
+ *
+ * @param alignment
+ * the new alignment
+ */
+ public void setAlignment(Alignment alignment) {
+ this.alignment = alignment;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphColorManager.java
----------------------------------------------------------------------
diff --git a/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphColorManager.java b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphColorManager.java
new file mode 100644
index 0000000..1f44076
--- /dev/null
+++ b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphColorManager.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.models.graph;
+
+import java.awt.Color;
+import java.lang.reflect.InvocationTargetException;
+
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+import uk.org.taverna.scufl2.api.activity.Activity;
+
+/**
+ * Manages the colour of elements in a graph.
+ *
+ * @author David Withers
+ * @author Start Owen
+ */
+public class GraphColorManager {
+ private static final String BEANSHELL = "http://ns.taverna.org.uk/2010/activity/beanshell";
+ private static final String LOCALWORKER = "http://ns.taverna.org.uk/2010/activity/localworker";
+
+ private static Color[] subGraphFillColors = new Color[] {
+ Color.decode("#ffffff"), Color.decode("#f0f8ff"),
+ Color.decode("#faebd7"), Color.decode("#f5f5dc") };
+
+ /**
+ * Returns the colour associated with the Activity.
+ *
+ * For unknown activities Color.WHITE is returned.
+ *
+ * For {@link LocalworkerActivity} which have been user configured use the
+ * BeanshellActivity colour
+ *
+ * @return the colour associated with the Activity
+ */
+ public static Color getFillColor(Activity activity, ColourManager colourManager) {
+ try {
+ if (activity.getType().equals(LOCALWORKER)) {
+ // To avoid compile time dependency - read isAltered property as bean
+ if (Boolean.TRUE.equals(PropertyUtils.getProperty(activity, "altered"))) {
+ Color colour = colourManager.getPreferredColour(BEANSHELL);
+ return colour;
+ }
+ }
+ } catch (IllegalAccessException | InvocationTargetException
+ | NoSuchMethodException e) {
+ }
+ Color colour = colourManager.getPreferredColour(activity.getType().toASCIIString());
+ return colour;
+ }
+
+ public static Color getSubGraphFillColor(int depth) {
+ return subGraphFillColors[depth % subGraphFillColors.length];
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphController.java
----------------------------------------------------------------------
diff --git a/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphController.java b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphController.java
new file mode 100644
index 0000000..0fb87a4
--- /dev/null
+++ b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphController.java
@@ -0,0 +1,1276 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.models.graph;
+
+import static javax.swing.JOptionPane.PLAIN_MESSAGE;
+import static javax.swing.JOptionPane.showInputDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.ui.menu.MenuManager;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+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.models.graph.Graph.Alignment;
+import net.sf.taverna.t2.workbench.models.graph.GraphEdge.ArrowStyle;
+import net.sf.taverna.t2.workbench.models.graph.GraphElement.LineStyle;
+import net.sf.taverna.t2.workbench.models.graph.GraphShapeElement.Shape;
+import net.sf.taverna.t2.workbench.selection.DataflowSelectionModel;
+import net.sf.taverna.t2.workbench.selection.events.DataflowSelectionMessage;
+import net.sf.taverna.t2.workflow.edits.AddDataLinkEdit;
+import net.sf.taverna.t2.workflow.edits.RemoveDataLinkEdit;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.common.NamedSet;
+import uk.org.taverna.scufl2.api.common.Scufl2Tools;
+import uk.org.taverna.scufl2.api.common.WorkflowBean;
+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.InputPort;
+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.OutputPort;
+import uk.org.taverna.scufl2.api.port.OutputProcessorPort;
+import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;
+import uk.org.taverna.scufl2.api.port.Port;
+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.port.WorkflowPort;
+import uk.org.taverna.scufl2.api.profiles.ProcessorBinding;
+import uk.org.taverna.scufl2.api.profiles.Profile;
+
+/**
+ * @author David Withers
+ */
+public abstract class GraphController implements
+ Observer<DataflowSelectionMessage> {
+ public enum PortStyle {
+ ALL {
+ @Override
+ Shape inputShape() {
+ return Shape.INVHOUSE;
+ }
+
+ @Override
+ Shape outputShape() {
+ return Shape.HOUSE;
+ }
+
+ @Override
+ Shape processorShape() {
+ return Shape.RECORD;
+ }
+ },
+ BOUND {
+ @Override
+ Shape inputShape() {
+ return Shape.INVHOUSE;
+ }
+
+ @Override
+ Shape outputShape() {
+ return Shape.HOUSE;
+ }
+
+ @Override
+ Shape processorShape() {
+ return Shape.RECORD;
+ }
+ },
+ NONE {
+ @Override
+ Shape inputShape() {
+ return Shape.BOX;
+ }
+
+ @Override
+ Shape outputShape() {
+ return Shape.BOX;
+ }
+
+ @Override
+ Shape processorShape() {
+ return Shape.BOX;
+ }
+ },
+ BLOB {
+ @Override
+ Shape inputShape() {
+ return Shape.CIRCLE;
+ }
+
+ @Override
+ Shape outputShape() {
+ return Shape.CIRCLE;
+ }
+
+ @Override
+ Shape processorShape() {
+ return Shape.CIRCLE;
+ }
+ };
+
+ abstract Shape inputShape();
+
+ abstract Shape outputShape();
+
+ abstract Shape processorShape();
+
+ Shape mergeShape() {
+ return Shape.CIRCLE;
+ }
+ }
+
+ private static Logger logger = Logger.getLogger(GraphController.class);
+
+ private Map<String, GraphElement> idToElement = new HashMap<>();
+ private Map<WorkflowBean, GraphElement> workflowToGraph = new HashMap<>();
+ private Map<Port, GraphNode> ports = new HashMap<>();
+ private Map<Graph, GraphNode> inputControls = new HashMap<>();
+ private Map<Graph, GraphNode> outputControls = new HashMap<>();
+ private Map<Port, Port> nestedWorkflowPorts = new HashMap<>();
+ private Map<WorkflowPort, ProcessorPort> workflowPortToProcessorPort = new HashMap<>();
+ private Map<Port, Processor> portToProcessor = new HashMap<>();
+
+ private EditManager editManager;
+ private final Workflow workflow;
+ private final Profile profile;
+ private DataflowSelectionModel dataflowSelectionModel;
+ private GraphEventManager graphEventManager;
+ private Component componentForPopups;
+
+ // graph settings
+ private PortStyle portStyle = PortStyle.NONE;
+ private Map<Processor, PortStyle> processorPortStyle = new HashMap<>();
+ private Alignment alignment = Alignment.VERTICAL;
+ private boolean expandNestedDataflows = true;
+ private Map<Activity, Boolean> dataflowExpansion = new HashMap<>();
+ protected Map<String, GraphElement> graphElementMap = new HashMap<>();
+ protected GraphElement edgeCreationSource, edgeCreationSink;
+ protected GraphEdge edgeMoveElement;
+ protected boolean edgeCreationFromSource = false;
+ protected boolean edgeCreationFromSink = false;
+ private Graph graph;
+ private boolean interactive;
+ private final ColourManager colourManager;
+
+ private Scufl2Tools scufl2Tools = new Scufl2Tools();
+
+ public GraphController(Workflow workflow, Profile profile,
+ boolean interactive, Component componentForPopups,
+ EditManager editManager, MenuManager menuManager,
+ ColourManager colourManager) {
+ this(workflow, profile, interactive, componentForPopups,
+ Alignment.VERTICAL, PortStyle.NONE, editManager, menuManager,
+ colourManager);
+ }
+
+ public GraphController(Workflow workflow, Profile profile,
+ boolean interactive, Component componentForPopups,
+ Alignment alignment, PortStyle portStyle, EditManager editManager,
+ MenuManager menuManager, ColourManager colourManager) {
+ this.workflow = workflow;
+ this.profile = profile;
+ this.interactive = interactive;
+ this.componentForPopups = componentForPopups;
+ this.alignment = alignment;
+ this.portStyle = portStyle;
+ this.editManager = editManager;
+ this.colourManager = colourManager;
+ this.graphEventManager = new DefaultGraphEventManager(this,
+ componentForPopups, menuManager);
+ graph = generateGraph();
+ }
+
+ public abstract Graph createGraph();
+
+ public abstract GraphNode createGraphNode();
+
+ public abstract GraphEdge createGraphEdge();
+
+ public void mapElement(String id, GraphElement element) {
+ idToElement.put(id, element);
+ }
+
+ public GraphElement getElement(String id) {
+ return idToElement.get(id);
+ }
+
+ public Graph getGraph() {
+ return graph;
+ }
+
+ public abstract void redraw();
+
+ /**
+ * Generates a graph model of a dataflow.
+ *
+ * @return
+ */
+ public Graph generateGraph() {
+ workflowToGraph.clear();
+ ports.clear();
+ inputControls.clear();
+ outputControls.clear();
+ nestedWorkflowPorts.clear();
+ workflowPortToProcessorPort.clear();
+ graphElementMap.clear();
+ portToProcessor.clear();
+ return generateGraph(workflow, "", workflow.getName(), 0);
+ }
+
+ private Graph generateGraph(Workflow dataflow, String prefix, String name,
+ int depth) {
+ Graph graph = createGraph();
+ graph.setId(prefix + name);
+ graph.setAlignment(getAlignment());
+ if (getPortStyle().equals(PortStyle.BLOB) || depth == 0)
+ graph.setLabel("");
+ else
+ graph.setLabel(name);
+ graph.setFillColor(GraphColorManager.getSubGraphFillColor(depth));
+ if (depth == 0)
+ graph.setLineStyle(LineStyle.NONE);
+ else
+ graph.setLineStyle(LineStyle.SOLID);
+ graph.setColor(Color.BLACK);
+ graph.setShape(Shape.BOX);
+
+ if (depth == 0)
+ graph.setWorkflowBean(dataflow);
+ if (interactive)
+ graph.setWorkflowBean(dataflow);
+
+ // processors
+ for (Processor processor : dataflow.getProcessors())
+ graph.addNode(generateProcessorNode(processor, graph.getId(), depth));
+
+ // dataflow outputs
+ NamedSet<OutputWorkflowPort> outputPorts = dataflow.getOutputPorts();
+ if (outputPorts.size() > 0 || depth > 0)
+ graph.addSubgraph(generateOutputsGraph(outputPorts, graph.getId(),
+ graph, depth));
+
+ // dataflow inputs
+ NamedSet<InputWorkflowPort> inputPorts = dataflow.getInputPorts();
+ if (inputPorts.size() > 0 || depth > 0)
+ graph.addSubgraph(generateInputsGraph(inputPorts, graph.getId(),
+ graph, depth));
+
+ // datalinks
+ for (DataLink datalink : dataflow.getDataLinks()) {
+ GraphEdge edge = generateDataLinkEdge(datalink, depth);
+ if (edge != null)
+ graph.addEdge(edge);
+ }
+
+ // controlLinks
+ for (ControlLink controlLink : dataflow.getControlLinks())
+ if (controlLink instanceof BlockingControlLink) {
+ GraphEdge edge = generateControlLinkEdge(
+ (BlockingControlLink) controlLink, depth);
+ if (edge != null)
+ graph.addEdge(edge);
+ }
+
+ graphElementMap.put(graph.getId(), graph);
+ return graph;
+ }
+
+ public void transformGraph(Graph oldGraph, Graph newGraph) {
+ oldGraph.setAlignment(newGraph.getAlignment());
+ transformGraphElement(oldGraph, newGraph);
+ List<GraphEdge> oldEdges = new ArrayList<>(oldGraph.getEdges());
+ List<GraphEdge> newEdges = new ArrayList<>(newGraph.getEdges());
+ for (GraphEdge oldEdge : oldEdges) {
+ int index = newEdges.indexOf(oldEdge);
+ if (index >= 0) {
+ GraphEdge newEdge = newEdges.remove(index);
+ oldEdge.setPath(newEdge.getPath());
+ workflowToGraph.put(oldEdge.getWorkflowBean(), oldEdge);
+ } else
+ oldGraph.removeEdge(oldEdge);
+ }
+ List<GraphNode> newNodes = new ArrayList<>(newGraph.getNodes());
+ List<GraphNode> oldNodes = new ArrayList<>(oldGraph.getNodes());
+ for (GraphNode oldNode : oldNodes) {
+ int index = newNodes.indexOf(oldNode);
+ if (index >= 0) {
+ GraphNode newNode = newNodes.remove(index);
+ oldNode.setExpanded(newNode.isExpanded());
+ List<GraphNode> newSourceNodes = new ArrayList<>(
+ newNode.getSourceNodes());
+ List<GraphNode> oldSourceNodes = new ArrayList<>(
+ oldNode.getSourceNodes());
+ for (GraphNode oldSourceNode : oldSourceNodes) {
+ int sourceNodeIndex = newSourceNodes.indexOf(oldSourceNode);
+ if (sourceNodeIndex >= 0) {
+ GraphNode newSourceNode = newSourceNodes
+ .remove(sourceNodeIndex);
+ transformGraphElement(oldSourceNode, newSourceNode);
+ } else
+ oldNode.removeSourceNode(oldSourceNode);
+ }
+ for (GraphNode sourceNode : newSourceNodes)
+ oldNode.addSourceNode(sourceNode);
+ List<GraphNode> newSinkNodes = new ArrayList<>(
+ newNode.getSinkNodes());
+ List<GraphNode> oldSinkNodes = new ArrayList<>(
+ oldNode.getSinkNodes());
+ for (GraphNode oldSinkNode : oldSinkNodes) {
+ int sinkNodeIndex = newSinkNodes.indexOf(oldSinkNode);
+ if (sinkNodeIndex >= 0) {
+ GraphNode newSinkNode = newSinkNodes
+ .remove(sinkNodeIndex);
+ transformGraphElement(oldSinkNode, newSinkNode);
+ } else
+ oldNode.removeSinkNode(oldSinkNode);
+ }
+ for (GraphNode sinkNode : newSinkNodes)
+ oldNode.addSinkNode(sinkNode);
+ Graph oldSubGraph = oldNode.getGraph();
+ Graph newSubGraph = newNode.getGraph();
+ if (oldSubGraph != null && newSubGraph != null)
+ transformGraph(oldSubGraph, newSubGraph);
+ transformGraphElement(oldNode, newNode);
+ } else
+ oldGraph.removeNode(oldNode);
+ }
+ List<Graph> newSubGraphs = new ArrayList<>(newGraph.getSubgraphs());
+ List<Graph> oldSubGraphs = new ArrayList<>(oldGraph.getSubgraphs());
+ for (Graph oldSubGraph : oldSubGraphs) {
+ int index = newSubGraphs.indexOf(oldSubGraph);
+ if (index >= 0) {
+ Graph newSubGraph = newSubGraphs.remove(index);
+ transformGraph(oldSubGraph, newSubGraph);
+ } else
+ oldGraph.removeSubgraph(oldSubGraph);
+ }
+ for (GraphNode node : newNodes)
+ oldGraph.addNode(node);
+ for (Graph graph : newSubGraphs)
+ oldGraph.addSubgraph(graph);
+ for (GraphEdge newEdge : newEdges)
+ oldGraph.addEdge(newEdge);
+ }
+
+ public void transformGraphElement(GraphShapeElement oldGraphElement,
+ GraphShapeElement newGraphElement) {
+ oldGraphElement.setWorkflowBean(newGraphElement.getWorkflowBean());
+ oldGraphElement.setShape(newGraphElement.getShape());
+ oldGraphElement.setSize(newGraphElement.getSize());
+ oldGraphElement.setPosition(newGraphElement.getPosition());
+ oldGraphElement.setLabel(newGraphElement.getLabel());
+ oldGraphElement.setLabelPosition(newGraphElement.getLabelPosition());
+ oldGraphElement.setLineStyle(newGraphElement.getLineStyle());
+ oldGraphElement.setOpacity(newGraphElement.getOpacity());
+ oldGraphElement.setVisible(newGraphElement.isVisible());
+ oldGraphElement.setColor(newGraphElement.getColor());
+ oldGraphElement.setFillColor(newGraphElement.getFillColor());
+ workflowToGraph.put(oldGraphElement.getWorkflowBean(), oldGraphElement);
+ }
+
+ public void filterGraph(Set<?> dataflowEntities) {
+ Set<GraphElement> graphElements = new HashSet<>();
+ for (Entry<WorkflowBean, GraphElement> entry : workflowToGraph
+ .entrySet())
+ if (!dataflowEntities.contains(entry.getKey()))
+ graphElements.add(entry.getValue());
+ filterGraph(getGraph(), graphElements);
+ }
+
+ private void filterGraph(Graph graph, Set<GraphElement> graphElements) {
+ for (GraphNode node : graph.getNodes()) {
+ node.setFiltered(graphElements.contains(node));
+ Graph subgraph = node.getGraph();
+ if (subgraph != null)
+ if (graphElements.contains(subgraph)) {
+ removeFilter(subgraph);
+ subgraph.setFiltered(true);
+ } else {
+ subgraph.setFiltered(false);
+ filterGraph(subgraph, graphElements);
+ }
+ }
+ for (GraphEdge edge : graph.getEdges())
+ edge.setFiltered(graphElements.contains(edge));
+ for (Graph subgraph : graph.getSubgraphs())
+ if (graphElements.contains(subgraph)) {
+ removeFilter(subgraph);
+ subgraph.setFiltered(true);
+ } else {
+ subgraph.setFiltered(false);
+ filterGraph(subgraph, graphElements);
+ }
+ }
+
+ public void removeFilter() {
+ for (Entry<WorkflowBean, GraphElement> entry : workflowToGraph
+ .entrySet())
+ entry.getValue().setFiltered(false);
+ }
+
+ private void removeFilter(Graph graph) {
+ for (GraphNode node : graph.getNodes()) {
+ node.setOpacity(1f);
+ Graph subgraph = node.getGraph();
+ if (subgraph != null) {
+ subgraph.setFiltered(false);
+ removeFilter(subgraph);
+ }
+ }
+ for (GraphEdge edge : graph.getEdges())
+ edge.setFiltered(false);
+ for (Graph subgraph : graph.getSubgraphs()) {
+ subgraph.setFiltered(false);
+ removeFilter(subgraph);
+ }
+ }
+
+ private GraphEdge generateControlLinkEdge(BlockingControlLink condition,
+ int depth) {
+ GraphEdge edge = null;
+ GraphElement source = workflowToGraph.get(condition.getUntilFinished());
+ GraphElement sink = workflowToGraph.get(condition.getBlock());
+ if (source != null && sink != null) {
+ edge = createGraphEdge();
+ if (source instanceof Graph)
+ edge.setSource(outputControls.get(source));
+ else if (source instanceof GraphNode)
+ edge.setSource((GraphNode) source);
+ if (sink instanceof Graph)
+ edge.setSink(inputControls.get(sink));
+ else if (sink instanceof GraphNode)
+ edge.setSink((GraphNode) sink);
+ String sourceId = edge.getSource().getId();
+ String sinkId = edge.getSink().getId();
+ edge.setId(sourceId + "->" + sinkId);
+ edge.setLineStyle(LineStyle.SOLID);
+ edge.setColor(Color.decode("#505050"));
+ edge.setFillColor(null);
+ edge.setArrowHeadStyle(ArrowStyle.DOT);
+ if (depth == 0)
+ edge.setWorkflowBean(condition);
+ if (interactive)
+ edge.setWorkflowBean(condition);
+ workflowToGraph.put(condition, edge);
+ graphElementMap.put(edge.getId(), edge);
+ }
+ return edge;
+ }
+
+ private GraphEdge generateDataLinkEdge(DataLink datalink, int depth) {
+ GraphEdge edge = null;
+ Port sourcePort = datalink.getReceivesFrom();
+ Port sinkPort = datalink.getSendsTo();
+ if (nestedWorkflowPorts.containsKey(sourcePort))
+ sourcePort = nestedWorkflowPorts.get(sourcePort);
+ if (nestedWorkflowPorts.containsKey(sinkPort))
+ sinkPort = nestedWorkflowPorts.get(sinkPort);
+ GraphNode sourceNode = ports.get(sourcePort);
+ GraphNode sinkNode = ports.get(sinkPort);
+ if (sourceNode != null && sinkNode != null) {
+ edge = createGraphEdge();
+ edge.setSource(sourceNode);
+ edge.setSink(sinkNode);
+
+ StringBuilder id = new StringBuilder();
+ if (sourceNode.getParent() instanceof GraphNode) {
+ id.append(sourceNode.getParent().getId());
+ id.append(":");
+ id.append(sourceNode.getId());
+ } else
+ id.append(sourceNode.getId());
+ id.append("->");
+ if (sinkNode.getParent() instanceof GraphNode) {
+ id.append(sinkNode.getParent().getId());
+ id.append(":");
+ id.append(sinkNode.getId());
+ } else
+ id.append(sinkNode.getId());
+ edge.setId(id.toString());
+ edge.setLineStyle(LineStyle.SOLID);
+ edge.setColor(Color.BLACK);
+ edge.setFillColor(Color.BLACK);
+ if (depth == 0)
+ edge.setWorkflowBean(datalink);
+ if (interactive)
+ edge.setWorkflowBean(datalink);
+ workflowToGraph.put(datalink, edge);
+ graphElementMap.put(edge.getId(), edge);
+ }
+ return edge;
+ }
+
+ private Graph generateInputsGraph(NamedSet<InputWorkflowPort> inputPorts,
+ String prefix, Graph graph, int depth) {
+ Graph inputs = createGraph();
+ inputs.setId(prefix + "sources");
+ inputs.setColor(Color.BLACK);
+ inputs.setFillColor(null);
+ inputs.setShape(Shape.BOX);
+ inputs.setLineStyle(LineStyle.DOTTED);
+ if (getPortStyle().equals(PortStyle.BLOB))
+ inputs.setLabel("");
+ else
+ inputs.setLabel("Workflow input ports");
+
+ GraphNode triangle = createGraphNode();
+ triangle.setId(prefix + "WORKFLOWINTERNALSOURCECONTROL");
+ triangle.setLabel("");
+ triangle.setShape(Shape.TRIANGLE);
+ triangle.setSize(new Dimension((int) (0.2f * 72), (int) ((Math.sin(Math
+ .toRadians(60)) * 0.2) * 72)));
+ triangle.setFillColor(Color.decode("#ff4040"));
+ triangle.setColor(Color.BLACK);
+ triangle.setLineStyle(LineStyle.SOLID);
+ inputs.addNode(triangle);
+ inputControls.put(graph, triangle);
+
+ for (InputWorkflowPort inputWorkflowPort : inputPorts) {
+ GraphNode inputNode = createGraphNode();
+ inputNode.setId(prefix + "WORKFLOWINTERNALSOURCE_"
+ + inputWorkflowPort.getName());
+ if (getPortStyle().equals(PortStyle.BLOB)) {
+ inputNode.setLabel("");
+ inputNode.setSize(new Dimension((int) (0.3f * 72),
+ (int) (0.3f * 72)));
+ } else
+ inputNode.setLabel(inputWorkflowPort.getName());
+ inputNode.setShape(getPortStyle().inputShape());
+ inputNode.setColor(Color.BLACK);
+ inputNode.setLineStyle(LineStyle.SOLID);
+ inputNode.setFillColor(Color.decode("#8ed6f0"));
+ if (depth == 0)
+ inputNode.setInteractive(true);
+ if (interactive)
+ inputNode.setInteractive(true);
+ if (depth < 2) {
+ inputNode.setWorkflowBean(inputWorkflowPort);
+ if (workflowPortToProcessorPort.containsKey(inputWorkflowPort)) {
+ ProcessorPort port = workflowPortToProcessorPort
+ .get(inputWorkflowPort);
+ inputNode.setWorkflowBean(port);
+ workflowToGraph.put(port, inputNode);
+ } else {
+ inputNode.setWorkflowBean(inputWorkflowPort);
+ workflowToGraph.put(inputWorkflowPort, inputNode);
+ }
+ }
+ ports.put(inputWorkflowPort, inputNode);
+ inputs.addNode(inputNode);
+ graphElementMap.put(inputNode.getId(), inputNode);
+ }
+ return inputs;
+ }
+
+ private Graph generateOutputsGraph(
+ NamedSet<OutputWorkflowPort> outputPorts, String prefix,
+ Graph graph, int depth) {
+ Graph outputs = createGraph();
+ outputs.setId(prefix + "sinks");
+ outputs.setColor(Color.BLACK);
+ outputs.setFillColor(null);
+ outputs.setShape(Shape.BOX);
+ outputs.setLineStyle(LineStyle.DOTTED);
+ if (getPortStyle().equals(PortStyle.BLOB))
+ outputs.setLabel("");
+ else
+ outputs.setLabel("Workflow output ports");
+
+ GraphNode triangle = createGraphNode();
+ triangle.setId(prefix + "WORKFLOWINTERNALSINKCONTROL");
+ triangle.setLabel("");
+ triangle.setShape(Shape.INVTRIANGLE);
+ triangle.setSize(new Dimension((int) (0.2f * 72), (int) ((Math.sin(Math
+ .toRadians(60)) * 0.2) * 72)));
+ triangle.setFillColor(Color.decode("#66cd00"));
+ triangle.setColor(Color.BLACK);
+ triangle.setLineStyle(LineStyle.SOLID);
+ outputs.addNode(triangle);
+ outputControls.put(graph, triangle);
+
+ for (OutputWorkflowPort outputWorkflowPort : outputPorts) {
+ GraphNode outputNode = createGraphNode();
+ outputNode.setId(prefix + "WORKFLOWINTERNALSINK_"
+ + outputWorkflowPort.getName());
+ if (getPortStyle().equals(PortStyle.BLOB)) {
+ outputNode.setLabel("");
+ outputNode.setSize(new Dimension((int) (0.3f * 72),
+ (int) (0.3f * 72)));
+ } else
+ outputNode.setLabel(outputWorkflowPort.getName());
+ outputNode.setShape(getPortStyle().outputShape());
+ outputNode.setColor(Color.BLACK);
+ outputNode.setLineStyle(LineStyle.SOLID);
+ outputNode.setFillColor(Color.decode("#8ed6f0"));
+ if (depth == 0)
+ outputNode.setInteractive(true);
+ if (interactive)
+ outputNode.setInteractive(true);
+ if (depth < 2) {
+ if (workflowPortToProcessorPort.containsKey(outputWorkflowPort)) {
+ ProcessorPort port = workflowPortToProcessorPort
+ .get(outputWorkflowPort);
+ outputNode.setWorkflowBean(port);
+ workflowToGraph.put(port, outputNode);
+ } else {
+ outputNode.setWorkflowBean(outputWorkflowPort);
+ workflowToGraph.put(outputWorkflowPort, outputNode);
+ }
+ }
+ ports.put(outputWorkflowPort, outputNode);
+ outputs.addNode(outputNode);
+ graphElementMap.put(outputNode.getId(), outputNode);
+ }
+ return outputs;
+ }
+
+ private GraphNode generateProcessorNode(Processor processor, String prefix,
+ int depth) {
+ // Blatantly ignoring any other activities for now
+ ProcessorBinding processorBinding = scufl2Tools
+ .processorBindingForProcessor(processor, profile);
+ Activity activity = processorBinding.getBoundActivity();
+ @SuppressWarnings("unused")
+ URI activityType = activity.getType();
+
+ GraphNode node = createGraphNode();
+ node.setId(prefix + processor.getName());
+ if (getPortStyle().equals(PortStyle.BLOB)) {
+ node.setLabel("");
+ node.setSize(new Dimension((int) (0.3f * 72), (int) (0.3f * 72)));
+ } else
+ node.setLabel(processor.getName());
+ node.setShape(getPortStyle(processor).processorShape());
+ node.setColor(Color.BLACK);
+ node.setLineStyle(LineStyle.SOLID);
+ // if (activityType.equals(URI.create(NonExecutableActivity.URI))) {
+ // if (activityType.equals(URI.create(DisabledActivity.URI))) {
+ // node.setFillColor(GraphColorManager
+ // .getFillColor(((DisabledActivity) activity)
+ // .getActivity(), colourManager));
+ // } else {
+ // node.setFillColor(GraphColorManager
+ // .getFillColor(activityType, colourManager));
+ // }
+ // node.setOpacity(0.3f);
+ // } else
+ node.setFillColor(GraphColorManager.getFillColor(activity,
+ colourManager));
+
+ // check whether the nested workflow processors should be clickable or
+ // not, if top level workflow then should be clickable regardless
+ if (depth == 0) {
+ node.setInteractive(true);
+ node.setWorkflowBean(processor);
+ }
+ if (interactive) {
+ node.setInteractive(true);
+ node.setWorkflowBean(processor);
+ }
+
+ if (scufl2Tools.containsNestedWorkflow(processor, profile)
+ && expandNestedDataflow(activity)) {
+ Workflow subDataflow = scufl2Tools.nestedWorkflowForProcessor(
+ processor, profile);
+
+ NamedSet<InputWorkflowPort> inputWorkflowPorts = subDataflow
+ .getInputPorts();
+ for (InputActivityPort inputActivityPort : activity.getInputPorts()) {
+ InputWorkflowPort inputWorkflowPort = inputWorkflowPorts
+ .getByName(inputActivityPort.getName());
+ InputProcessorPort inputProcessorPort = scufl2Tools
+ .processorPortBindingForPort(inputActivityPort, profile)
+ .getBoundProcessorPort();
+ nestedWorkflowPorts.put(inputProcessorPort, inputWorkflowPort);
+ workflowPortToProcessorPort.put(inputWorkflowPort,
+ inputProcessorPort);
+ processorBinding.getInputPortBindings();
+ }
+
+ NamedSet<OutputWorkflowPort> outputWorkflowPorts = subDataflow
+ .getOutputPorts();
+ for (OutputActivityPort outputActivityPort : activity
+ .getOutputPorts()) {
+ OutputWorkflowPort outputWorkflowPort = outputWorkflowPorts
+ .getByName(outputActivityPort.getName());
+ OutputProcessorPort outputProcessorPort = scufl2Tools
+ .processorPortBindingForPort(outputActivityPort,
+ profile).getBoundProcessorPort();
+ nestedWorkflowPorts
+ .put(outputProcessorPort, outputWorkflowPort);
+ workflowPortToProcessorPort.put(outputWorkflowPort,
+ outputProcessorPort);
+ }
+
+ Graph subGraph = generateGraph(subDataflow, prefix,
+ processor.getName(), depth + 1);
+ // TODO why does this depth matter?
+ if (depth == 0)
+ subGraph.setWorkflowBean(processor);
+ if (interactive)
+ subGraph.setWorkflowBean(processor);
+ node.setGraph(subGraph);
+ node.setExpanded(true);
+
+ workflowToGraph.put(processor, subGraph);
+ } else {
+ graphElementMap.put(node.getId(), node);
+ workflowToGraph.put(processor, node);
+ }
+
+ NamedSet<InputProcessorPort> inputPorts = processor.getInputPorts();
+ if (inputPorts.size() == 0) {
+ GraphNode portNode = createGraphNode();
+ portNode.setShape(Shape.BOX);
+ portNode.setColor(Color.BLACK);
+ portNode.setFillColor(node.getFillColor());
+ portNode.setLineStyle(LineStyle.SOLID);
+ node.addSinkNode(portNode);
+ } else
+ for (InputPort inputPort : inputPorts) {
+ GraphNode portNode = createGraphNode();
+ portNode.setId("i" + inputPort.getName().replaceAll("\\.", ""));
+ portNode.setLabel(inputPort.getName());
+ portNode.setShape(Shape.BOX);
+ portNode.setColor(Color.BLACK);
+ portNode.setFillColor(node.getFillColor());
+ portNode.setLineStyle(LineStyle.SOLID);
+ if (depth == 0)
+ portNode.setWorkflowBean(inputPort);
+ if (interactive)
+ portNode.setWorkflowBean(inputPort);
+ if (!node.isExpanded())
+ workflowToGraph.put(inputPort, portNode);
+ ports.put(inputPort, portNode);
+ node.addSinkNode(portNode);
+ graphElementMap.put(portNode.getId(), portNode);
+ // portToActivity.put(inputPort, activity);
+ portToProcessor.put(inputPort, processor);
+ }
+
+ NamedSet<OutputProcessorPort> outputPorts = processor.getOutputPorts();
+ if (outputPorts.size() == 0) {
+ GraphNode portNode = createGraphNode();
+ portNode.setShape(Shape.BOX);
+ portNode.setColor(Color.BLACK);
+ portNode.setFillColor(node.getFillColor());
+ portNode.setLineStyle(LineStyle.SOLID);
+ node.addSourceNode(portNode);
+ } else
+ for (OutputPort outputPort : outputPorts) {
+ GraphNode portNode = createGraphNode();
+ portNode.setId("o" + outputPort.getName().replaceAll("\\.", ""));
+ portNode.setLabel(outputPort.getName());
+ portNode.setShape(Shape.BOX);
+ portNode.setColor(Color.BLACK);
+ portNode.setFillColor(node.getFillColor());
+ portNode.setLineStyle(LineStyle.SOLID);
+ if (depth == 0)
+ portNode.setWorkflowBean(outputPort);
+ if (interactive)
+ portNode.setWorkflowBean(outputPort);
+ if (!node.isExpanded())
+ workflowToGraph.put(outputPort, portNode);
+ ports.put(outputPort, portNode);
+ node.addSourceNode(portNode);
+ graphElementMap.put(portNode.getId(), portNode);
+ // portToActivity.put(outputPort, activity);
+ portToProcessor.put(outputPort, processor);
+ }
+
+ return node;
+ }
+
+ /**
+ * Returns the dataflow.
+ *
+ * @return the dataflow
+ */
+ public Workflow getWorkflow() {
+ return workflow;
+ }
+
+ public Profile getProfile() {
+ return profile;
+ }
+
+ /**
+ * Returns the dataflowSelectionModel.
+ *
+ * @return the dataflowSelectionModel
+ */
+ public DataflowSelectionModel getDataflowSelectionModel() {
+ return dataflowSelectionModel;
+ }
+
+ /**
+ * Sets the dataflowSelectionModel.
+ *
+ * @param dataflowSelectionModel
+ * the new dataflowSelectionModel
+ */
+ public void setDataflowSelectionModel(
+ DataflowSelectionModel dataflowSelectionModel) {
+ if (this.dataflowSelectionModel != null)
+ this.dataflowSelectionModel.removeObserver(this);
+ this.dataflowSelectionModel = dataflowSelectionModel;
+ this.dataflowSelectionModel.addObserver(this);
+ }
+
+ /**
+ * Sets the proportion of the node's jobs that have been completed.
+ *
+ * @param nodeId
+ * the id of the node
+ * @param complete
+ * the proportion of the nodes's jobs that have been completed, a
+ * value between 0.0 and 1.0
+ */
+ public void setNodeCompleted(String nodeId, float complete) {
+ if (graphElementMap.containsKey(nodeId)) {
+ GraphElement graphElement = graphElementMap.get(nodeId);
+ graphElement.setCompleted(complete);
+ }
+ }
+
+ public void setEdgeActive(String edgeId, boolean active) {
+ }
+
+ /**
+ * Returns the alignment.
+ *
+ * @return the alignment
+ */
+ public Alignment getAlignment() {
+ return alignment;
+ }
+
+ /**
+ * Returns the portStyle.
+ *
+ * @return the portStyle
+ */
+ public PortStyle getPortStyle() {
+ return portStyle;
+ }
+
+ /**
+ * Returns the portStyle for a processor.
+ *
+ * @return the portStyle for a processor
+ */
+ public PortStyle getPortStyle(Processor processor) {
+ if (processorPortStyle.containsKey(processor))
+ return processorPortStyle.get(processor);
+ return portStyle;
+ }
+
+ /**
+ * Sets the alignment.
+ *
+ * @param alignment
+ * the new alignment
+ */
+ public void setAlignment(Alignment alignment) {
+ this.alignment = alignment;
+ }
+
+ /**
+ * Sets the portStyle.
+ *
+ * @param style
+ * the new portStyle
+ */
+ public void setPortStyle(PortStyle portStyle) {
+ this.portStyle = portStyle;
+ processorPortStyle.clear();
+ }
+
+ /**
+ * Sets the portStyle for a processor.
+ *
+ * @param style
+ * the new portStyle for the processor
+ */
+ public void setPortStyle(Processor processor, PortStyle portStyle) {
+ processorPortStyle.put(processor, portStyle);
+ }
+
+ /**
+ * Shut down any processing and update threads related to this controller.
+ *
+ */
+ public void shutdown() {
+ }
+
+ /**
+ * Returns true if the default is to expand nested workflows.
+ *
+ * @return true if the default is to expand nested workflows
+ */
+ public boolean expandNestedDataflows() {
+ return expandNestedDataflows;
+ }
+
+ /**
+ * Returns true if the nested dataflow should be expanded.
+ *
+ * @param dataflow
+ * @return true if the nested dataflow should be expanded
+ */
+ public boolean expandNestedDataflow(Activity dataflow) {
+ if (dataflowExpansion.containsKey(dataflow))
+ return dataflowExpansion.get(dataflow);
+ return expandNestedDataflows;
+ }
+
+ /**
+ * Sets the default for expanding nested workflows.
+ *
+ * @param expand
+ * the default for expanding nested workflows
+ */
+ public void setExpandNestedDataflows(boolean expand) {
+ dataflowExpansion.clear();
+ this.expandNestedDataflows = expand;
+ }
+
+ /**
+ * Sets whether the nested dataflow should be expanded.
+ *
+ * @param expand
+ * whether the nested dataflow should be expanded
+ * @param dataflow
+ * the nested dataflow
+ */
+ public void setExpandNestedDataflow(Activity dataflow, boolean expand) {
+ dataflowExpansion.put(dataflow, expand);
+ }
+
+ private boolean isSingleOutputProcessor(Object dataflowObject) {
+ boolean result = false;
+ if (dataflowObject instanceof Processor) {
+ Processor processor = (Processor) dataflowObject;
+ result = processor.getOutputPorts().size() == 1;
+ }
+ return result;
+ }
+
+ public boolean startEdgeCreation(GraphElement graphElement, Point point) {
+ if (!edgeCreationFromSource && !edgeCreationFromSink) {
+ Object dataflowObject = graphElement.getWorkflowBean();
+ if (dataflowObject instanceof ReceiverPort) {
+ edgeCreationSink = graphElement;
+ edgeCreationFromSink = true;
+ } else if (dataflowObject instanceof SenderPort
+ || isSingleOutputProcessor(dataflowObject)) {
+ edgeCreationSource = graphElement;
+ edgeCreationFromSource = true;
+ } else if (graphElement instanceof GraphEdge) {
+ GraphEdge edge = (GraphEdge) graphElement;
+ edgeCreationSource = edge.getSource();
+ edgeCreationFromSource = true;
+ edgeMoveElement = edge;
+ }
+ }
+ return edgeCreationFromSource || edgeCreationFromSink;
+ }
+
+ public boolean moveEdgeCreationTarget(GraphElement graphElement, Point point) {
+ boolean edgeValid = false;
+ Object dataflowObject = graphElement.getWorkflowBean();
+ if (edgeCreationFromSink) {
+ if (graphElement instanceof GraphNode) {
+ Object sinkObject = edgeCreationSink.getWorkflowBean();
+ if (dataflowObject instanceof OutputPort) {
+ Processor sourceProcessor = portToProcessor
+ .get(dataflowObject);
+ if (sourceProcessor != null) {
+ Processor sinkProcessor = null;
+ if (sinkObject instanceof Processor)
+ sinkProcessor = (Processor) sinkObject;
+ else if (portToProcessor.containsKey(sinkObject))
+ sinkProcessor = portToProcessor.get(sinkObject);
+ if (sinkProcessor != null) {
+ Set<Processor> possibleSinkProcessors = scufl2Tools
+ .possibleDownStreamProcessors(workflow,
+ sourceProcessor);
+ if (possibleSinkProcessors.contains(sinkProcessor)) {
+ edgeCreationSource = graphElement;
+ edgeValid = true;
+ }
+ }
+ if (sinkObject instanceof OutputWorkflowPort) {
+ edgeCreationSource = graphElement;
+ edgeValid = true;
+ }
+ }
+ } else if (dataflowObject instanceof InputWorkflowPort) {
+ edgeCreationSource = graphElement;
+ edgeValid = true;
+ } else if (dataflowObject instanceof Processor) {
+ Processor sourceProcessor = (Processor) dataflowObject;
+ Processor sinkProcessor = null;
+ if (sinkObject instanceof Processor)
+ sinkProcessor = (Processor) sinkObject;
+ else if (portToProcessor.containsKey(sinkObject))
+ sinkProcessor = portToProcessor.get(sinkObject);
+ if (sinkProcessor != null) {
+ Set<Processor> possibleSinkProcessors = scufl2Tools
+ .possibleDownStreamProcessors(workflow,
+ sourceProcessor);
+ if (possibleSinkProcessors.contains(sinkProcessor)) {
+ edgeCreationSource = graphElement;
+ edgeValid = true;
+ }
+ }
+ if (sinkObject instanceof OutputWorkflowPort) {
+ edgeCreationSource = graphElement;
+ edgeValid = true;
+ }
+ }
+ }
+ if (!edgeValid)
+ edgeCreationSource = null;
+ } else if (edgeCreationFromSource) {
+ if (graphElement instanceof GraphNode) {
+ Object sourceObject = edgeCreationSource.getWorkflowBean();
+ if (dataflowObject instanceof InputPort) {
+ Processor sinkProcessor = portToProcessor
+ .get(dataflowObject);
+ if (sinkProcessor != null) {
+ Processor sourceProcessor = null;
+ if (sourceObject instanceof Processor)
+ sourceProcessor = (Processor) sourceObject;
+ else if (portToProcessor.containsKey(sourceObject))
+ sourceProcessor = portToProcessor.get(sourceObject);
+ if (sourceProcessor != null) {
+ Set<Processor> possibleSourceProcessors = scufl2Tools
+ .possibleUpStreamProcessors(workflow,
+ sinkProcessor);
+ if (possibleSourceProcessors
+ .contains(sourceProcessor)) {
+ edgeCreationSink = graphElement;
+ edgeValid = true;
+ }
+ }
+ if (sourceObject instanceof InputWorkflowPort) {
+ edgeCreationSink = graphElement;
+ edgeValid = true;
+ }
+ }
+ } else if (dataflowObject instanceof OutputWorkflowPort) {
+ if (sourceObject != null) {
+ edgeCreationSink = graphElement;
+ edgeValid = true;
+ }
+ } else if (dataflowObject instanceof Processor) {
+ Processor sinkProcessor = (Processor) dataflowObject;
+ Processor sourceProcessor = null;
+ if (sourceObject instanceof Processor)
+ sourceProcessor = (Processor) sourceObject;
+ else if (portToProcessor.containsKey(sourceObject))
+ sourceProcessor = portToProcessor.get(sourceObject);
+ if (sourceProcessor != null) {
+ Set<Processor> possibleSourceProcessors = scufl2Tools
+ .possibleUpStreamProcessors(workflow,
+ sinkProcessor);
+ if (possibleSourceProcessors.contains(sourceProcessor)) {
+ edgeCreationSink = graphElement;
+ edgeValid = true;
+ }
+ }
+ if (sourceObject instanceof InputWorkflowPort) {
+ edgeCreationSink = graphElement;
+ edgeValid = true;
+ }
+ }
+ }
+ if (!edgeValid)
+ edgeCreationSink = null;
+ }
+ return edgeValid;
+ }
+
+ public boolean stopEdgeCreation(GraphElement graphElement, Point point) {
+ boolean edgeCreated = false;
+ if (edgeCreationSource != null && edgeCreationSink != null) {
+ SenderPort source = null;
+ ReceiverPort sink = null;
+ Object sourceDataflowObject = edgeCreationSource.getWorkflowBean();
+ Object sinkDataflowObject = edgeCreationSink.getWorkflowBean();
+ if (sourceDataflowObject instanceof SenderPort)
+ source = (SenderPort) sourceDataflowObject;
+ else if (sourceDataflowObject instanceof Processor) {
+ Processor processor = (Processor) sourceDataflowObject;
+ source = showPortOptions(processor.getOutputPorts(), "output",
+ componentForPopups, point);
+ }
+ if (sinkDataflowObject instanceof ReceiverPort)
+ sink = (ReceiverPort) sinkDataflowObject;
+ else if (sinkDataflowObject instanceof Processor) {
+ Processor processor = (Processor) sinkDataflowObject;
+ sink = showPortOptions(processor.getInputPorts(), "input",
+ componentForPopups, point);
+ }
+ if (source != null && sink != null) {
+ Edit<?> edit = null;
+ if (edgeMoveElement == null) {
+ DataLink dataLink = new DataLink();
+ dataLink.setReceivesFrom(source);
+ dataLink.setSendsTo(sink);
+ edit = new AddDataLinkEdit(workflow, dataLink);
+ } else {
+ Object existingSink = edgeMoveElement.getSink()
+ .getWorkflowBean();
+ if (existingSink != sink) {
+ List<Edit<?>> editList = new ArrayList<Edit<?>>();
+ DataLink existingDataLink = (DataLink) edgeMoveElement
+ .getWorkflowBean();
+ DataLink newDataLink = new DataLink();
+ newDataLink.setReceivesFrom(existingDataLink
+ .getReceivesFrom());
+ newDataLink.setSendsTo(sink);
+ editList.add(new RemoveDataLinkEdit(workflow,
+ existingDataLink));
+ editList.add(new AddDataLinkEdit(workflow, newDataLink));
+ edit = new CompoundEdit(editList);
+ }
+ }
+ try {
+ if (edit != null) {
+ editManager.doDataflowEdit(workflow.getParent(), edit);
+ edgeCreated = true;
+ }
+ } catch (EditException e) {
+ logger.debug("Failed to create datalink from '"
+ + source.getName() + "' to '" + sink.getName()
+ + "'");
+ }
+ }
+ }
+ edgeCreationSource = null;
+ edgeCreationSink = null;
+ edgeMoveElement = null;
+ edgeCreationFromSource = false;
+ edgeCreationFromSink = false;
+
+ return edgeCreated;
+ }
+
+ private <T extends Port> T showPortOptions(NamedSet<T> ports,
+ String portType, Component component, Point point) {
+ T result = null;
+ if (ports.size() == 0) {
+ showMessageDialog(component, "Service has no " + portType
+ + " ports to connect to");
+ } else if (ports.size() == 1)
+ result = ports.first();
+ else {
+ Object[] portNames = ports.getNames().toArray();
+ String portName = (String) showInputDialog(component, "Select an "
+ + portType + " port", "Port Chooser", PLAIN_MESSAGE, null,
+ portNames, portNames[0]);
+ if (portName != null)
+ result = ports.getByName(portName);
+ }
+ return result;
+
+ }
+
+ public void resetSelection() {
+ if (dataflowSelectionModel != null)
+ for (Object dataflowElement : dataflowSelectionModel.getSelection()) {
+ GraphElement graphElement = workflowToGraph
+ .get(dataflowElement);
+ if (graphElement != null)
+ graphElement.setSelected(true);
+ }
+ }
+
+ public void setIteration(String nodeId, int iteration) {
+ if (graphElementMap.containsKey(nodeId)) {
+ GraphElement graphElement = graphElementMap.get(nodeId);
+ graphElement.setIteration(iteration);
+ }
+ }
+
+ public void setErrors(String nodeId, int errors) {
+ if (graphElementMap.containsKey(nodeId)) {
+ GraphElement graphElement = graphElementMap.get(nodeId);
+ graphElement.setErrors(errors);
+ }
+ }
+
+ @Override
+ public void notify(Observable<DataflowSelectionMessage> sender,
+ DataflowSelectionMessage message) throws Exception {
+ GraphElement graphElement = workflowToGraph.get(message.getElement());
+ if (graphElement != null)
+ graphElement.setSelected(message.getType().equals(
+ DataflowSelectionMessage.Type.ADDED));
+ }
+
+ /**
+ * Returns the GraphEventManager.
+ *
+ * @return the GraphEventManager
+ */
+ public GraphEventManager getGraphEventManager() {
+ return graphEventManager;
+ }
+
+ /**
+ * Sets the GraphEventManager.
+ *
+ * @param graphEventManager
+ * the new GraphEventManager
+ */
+ public void setGraphEventManager(GraphEventManager graphEventManager) {
+ this.graphEventManager = graphEventManager;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphEdge.java
----------------------------------------------------------------------
diff --git a/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphEdge.java b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphEdge.java
new file mode 100644
index 0000000..d1348d2
--- /dev/null
+++ b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphEdge.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.models.graph;
+
+import java.awt.Point;
+import java.util.List;
+
+/**
+ * An edge connecting two nodes in a graph.
+ *
+ * @author David Withers
+ */
+public class GraphEdge extends GraphElement {
+ public enum ArrowStyle {NONE, NORMAL, DOT}
+
+ private GraphNode source;
+ private GraphNode sink;
+ private ArrowStyle arrowHeadStyle = ArrowStyle.NORMAL;
+ private ArrowStyle arrowTailStyle = ArrowStyle.NONE;
+ private List<Point> path;
+
+ /**
+ * Constructs a new instance of Edge.
+ *
+ */
+ public GraphEdge(GraphController graphController) {
+ super(graphController);
+ }
+
+ /**
+ * Returns the source.
+ *
+ * @return the source
+ */
+ public GraphNode getSource() {
+ return source;
+ }
+
+ /**
+ * Sets the source.
+ *
+ * @param source the new source
+ */
+ public void setSource(GraphNode source) {
+ this.source = source;
+ }
+
+ /**
+ * Returns the sink.
+ *
+ * @return the sink
+ */
+ public GraphNode getSink() {
+ return sink;
+ }
+
+ /**
+ * Sets the sink.
+ *
+ * @param sink the new sink
+ */
+ public void setSink(GraphNode sink) {
+ this.sink = sink;
+ }
+
+ /**
+ * Returns the arrowHeadStyle.
+ *
+ * @return the arrowHeadStyle
+ */
+ public ArrowStyle getArrowHeadStyle() {
+ return arrowHeadStyle;
+ }
+
+ /**
+ * Sets the arrowHeadStyle.
+ *
+ * @param arrowHeadStyle the new arrowHeadStyle
+ */
+ public void setArrowHeadStyle(ArrowStyle arrowHeadStyle) {
+ this.arrowHeadStyle = arrowHeadStyle;
+ }
+
+ /**
+ * Returns the arrowTailStyle.
+ *
+ * @return the arrowTailStyle
+ */
+ public ArrowStyle getArrowTailStyle() {
+ return arrowTailStyle;
+ }
+
+ /**
+ * Sets the arrowTailStyle.
+ *
+ * @param arrowTailStyle the new arrowTailStyle
+ */
+ public void setArrowTailStyle(ArrowStyle arrowTailStyle) {
+ this.arrowTailStyle = arrowTailStyle;
+ }
+
+ /**
+ * Returns the path.
+ *
+ * @return the path
+ */
+ public List<Point> getPath() {
+ return path;
+ }
+
+ /**
+ * Sets the path.
+ *
+ * @param path the new path
+ */
+ public void setPath(List<Point> path) {
+ this.path = path;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphElement.java
----------------------------------------------------------------------
diff --git a/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphElement.java b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphElement.java
new file mode 100644
index 0000000..8bb7bc8
--- /dev/null
+++ b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphElement.java
@@ -0,0 +1,430 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.models.graph;
+
+import java.awt.Color;
+import java.awt.Point;
+
+import uk.org.taverna.scufl2.api.common.WorkflowBean;
+
+/**
+ * An element of a graph.
+ *
+ * @author David Withers
+ */
+public abstract class GraphElement {
+ public enum LineStyle {
+ NONE, SOLID, DOTTED
+ }
+
+ private String id;
+ private String label;
+ private Point labelPosition;
+ private LineStyle lineStyle = LineStyle.SOLID;
+ private Color color = Color.BLACK;
+ private Color fillColor;
+ private float opacity = 1f;
+ private GraphElement parent;
+ private boolean selected;
+ private boolean active;
+ private boolean interactive;
+ private boolean visible = true;
+ private boolean filtered;
+ private WorkflowBean workflowBean;
+ protected GraphController graphController;
+ protected float completed;
+ protected int iteration;
+ protected int errors;
+
+ protected GraphElement(GraphController graphController) {
+ this.graphController = graphController;
+ }
+
+ /**
+ * Returns the eventManager.
+ *
+ * @return the eventManager
+ */
+ public GraphEventManager getEventManager() {
+ if (graphController != null) {
+ return graphController.getGraphEventManager();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the workflowBean.
+ *
+ * @return the workflowBean
+ */
+ public WorkflowBean getWorkflowBean() {
+ return workflowBean;
+ }
+
+ /**
+ * Sets the workflowBean.
+ *
+ * @param workflowBean
+ * the new workflowBean
+ */
+ public void setWorkflowBean(WorkflowBean workflowBean) {
+ this.workflowBean = workflowBean;
+ }
+
+ /**
+ * Returns the parent.
+ *
+ * @return the parent
+ */
+ public GraphElement getParent() {
+ return parent;
+ }
+
+ /**
+ * Sets the parent.
+ *
+ * @param parent
+ * the new parent
+ */
+ protected void setParent(GraphElement parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Returns the label.
+ *
+ * @return the label
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Sets the label.
+ *
+ * @param label
+ * the new label
+ */
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ /**
+ * Returns the labelPosition.
+ *
+ * @return the labelPosition
+ */
+ public Point getLabelPosition() {
+ return labelPosition;
+ }
+
+ /**
+ * Sets the labelPosition.
+ *
+ * @param labelPosition
+ * the new labelPosition
+ */
+ public void setLabelPosition(Point labelPosition) {
+ this.labelPosition = labelPosition;
+ }
+
+ /**
+ * Returns the id.
+ *
+ * @return the id
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the id.
+ *
+ * @param id
+ * the new id
+ */
+ public void setId(String id) {
+ if (graphController != null) {
+ graphController.mapElement(id, this);
+ }
+ this.id = id;
+ }
+
+ /**
+ * Returns the colour.
+ *
+ * @return the colour
+ */
+ public Color getColor() {
+ return color;
+ }
+
+ /**
+ * Sets the colour.
+ *
+ * @param color
+ * the new colour
+ */
+ public void setColor(Color color) {
+ this.color = color;
+ }
+
+ /**
+ * Returns the fillColor.
+ *
+ * @return the fillColor
+ */
+ public Color getFillColor() {
+ return fillColor;
+ }
+
+ /**
+ * Sets the fillColor.
+ *
+ * @param fillColor
+ * the new fillColor
+ */
+ public void setFillColor(Color fillColor) {
+ this.fillColor = fillColor;
+ }
+
+ /**
+ * Returns the lineStyle.
+ *
+ * @return the lineStyle
+ */
+ public LineStyle getLineStyle() {
+ return lineStyle;
+ }
+
+ /**
+ * Sets the lineStyle.
+ *
+ * @param lineStyle
+ * the new lineStyle
+ */
+ public void setLineStyle(LineStyle lineStyle) {
+ this.lineStyle = lineStyle;
+ }
+
+ @Override
+ public String toString() {
+ return id + "[" + label + "]";
+ }
+
+ /**
+ * Returns the selected.
+ *
+ * @return the selected
+ */
+ public boolean isSelected() {
+ return selected;
+ }
+
+ /**
+ * Sets the selected.
+ *
+ * @param selected
+ * the new selected
+ */
+ public void setSelected(boolean selected) {
+ this.selected = selected;
+ }
+
+ /**
+ * Returns the iteration.
+ *
+ * @return the value of iteration
+ */
+ public int getIteration() {
+ return iteration;
+ }
+
+ /**
+ * Sets the iteration.
+ *
+ * @param iteration
+ * the new value for iteration
+ */
+ public void setIteration(int iteration) {
+ this.iteration = iteration;
+ }
+
+ /**
+ * Returns the errors.
+ *
+ * @return the value of errors
+ */
+ public int getErrors() {
+ return errors;
+ }
+
+ /**
+ * Sets the errors.
+ *
+ * @param errors
+ * the new value for errors
+ */
+ public void setErrors(int errors) {
+ this.errors = errors;
+ }
+
+ /**
+ * Returns the completed.
+ *
+ * @return the value of completed
+ */
+ public float getCompleted() {
+ return completed;
+ }
+
+ /**
+ * Sets the completed value.
+ *
+ * @param completed
+ */
+ public void setCompleted(float completed) {
+ this.completed = completed;
+ }
+
+ /**
+ * Returns <code>true</code> if the element is active. The default value is
+ * <code>false</code>.
+ *
+ * @return <code>true</code> if the element is active
+ */
+ public boolean isActive() {
+ return active;
+ }
+
+ /**
+ * Sets the value of active.
+ *
+ * @param active
+ * the new active
+ */
+ public void setActive(boolean active) {
+ this.active = active;
+ }
+
+ /**
+ * Returns <code>true</code> if the element is interactive. The default
+ * value is <code>false</code>.
+ *
+ * @return <code>true</code> if the element is interactive
+ */
+ public boolean isInteractive() {
+ return interactive;
+ }
+
+ /**
+ * Sets the value of interactive.
+ *
+ * @param interactive
+ * the new interactive
+ */
+ public void setInteractive(boolean interactive) {
+ this.interactive = interactive;
+ }
+
+ /**
+ * Returns <code>true</code> if the element is visible. The default value is
+ * <code>true</code>.
+ *
+ * @return <code>true</code> if the element is visible
+ */
+ public boolean isVisible() {
+ return visible;
+ }
+
+ /**
+ * Sets whether the element is visible.
+ *
+ * @param visible
+ * the new value for visible
+ */
+ public void setVisible(boolean visible) {
+ this.visible = visible;
+ }
+
+ /**
+ * Returns the opacity value. The default value is 1.0
+ *
+ * @return the opacity value
+ */
+ public float getOpacity() {
+ return opacity;
+ }
+
+ /**
+ * Sets the opacity of the element. Must be a value between 0.0 and 1.0.
+ *
+ * @param opacity
+ * the new opacity value
+ */
+ public void setOpacity(float opacity) {
+ this.opacity = opacity;
+ }
+
+ /**
+ * Returns <code>true</code> if the element is filtered.
+ *
+ * @return <code>true</code> if the element is filtered
+ */
+ public boolean isFiltered() {
+ return filtered;
+ }
+
+ /**
+ * Sets the value of filtered.
+ *
+ * @param filtered
+ * the new value for filtered
+ */
+ public void setFiltered(boolean filtered) {
+ this.filtered = filtered;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+
+ // Equality by id
+ GraphElement other = (GraphElement) obj;
+ if (id == null)
+ return (other.id == null);
+ return id.equals(other.id);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphEventManager.java
----------------------------------------------------------------------
diff --git a/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphEventManager.java b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphEventManager.java
new file mode 100644
index 0000000..a6b9b0e
--- /dev/null
+++ b/taverna-graph-model/src/main/java/net/sf/taverna/t2/workbench/models/graph/GraphEventManager.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.models.graph;
+
+public interface GraphEventManager {
+ void mouseClicked(GraphElement graphElement, short button, boolean altKey,
+ boolean ctrlKey, boolean metaKey, int x, int y, int screenX,
+ int screenY);
+
+ void mouseDown(GraphElement graphElement, short button, boolean altKey,
+ boolean ctrlKey, boolean metaKey, int x, int y, int screenX,
+ int screenY);
+
+ void mouseUp(GraphElement graphElement, short button, boolean altKey,
+ boolean ctrlKey, boolean metaKey, final int x, final int y,
+ int screenX, int screenY);
+
+ void mouseMoved(GraphElement graphElement, short button, boolean altKey,
+ boolean ctrlKey, boolean metaKey, int x, int y, int screenX,
+ int screenY);
+
+ void mouseOver(GraphElement graphElement, short button, boolean altKey,
+ boolean ctrlKey, boolean metaKey, int x, int y, int screenX,
+ int screenY);
+
+ void mouseOut(GraphElement graphElement, short button, boolean altKey,
+ boolean ctrlKey, boolean metaKey, int x, int y, int screenX,
+ int screenY);
+}