http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraph.java ---------------------------------------------------------------------- diff --git a/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraph.java b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraph.java new file mode 100644 index 0000000..1b1df78 --- /dev/null +++ b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraph.java @@ -0,0 +1,439 @@ +/******************************************************************************* + * 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 org.apache.taverna.workbench.models.graph.svg; + +import static org.apache.taverna.workbench.models.graph.svg.SVGGraphSettings.COMPLETED_COLOUR; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.animate; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.calculatePoints; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.createAnimationElement; +import static org.apache.batik.util.CSSConstants.CSS_BLACK_VALUE; +import static org.apache.batik.util.CSSConstants.CSS_NONE_VALUE; +import static org.apache.batik.util.SVGConstants.SVG_ANIMATE_TAG; +import static org.apache.batik.util.SVGConstants.SVG_ANIMATE_TRANSFORM_TAG; +import static org.apache.batik.util.SVGConstants.SVG_CLICK_EVENT_TYPE; +import static org.apache.batik.util.SVGConstants.SVG_END_VALUE; +import static org.apache.batik.util.SVGConstants.SVG_FILL_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_FONT_FAMILY_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_FONT_SIZE_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_MIDDLE_VALUE; +import static org.apache.batik.util.SVGConstants.SVG_MOUSEMOVE_EVENT_TYPE; +import static org.apache.batik.util.SVGConstants.SVG_MOUSEUP_EVENT_TYPE; +import static org.apache.batik.util.SVGConstants.SVG_NONE_VALUE; +import static org.apache.batik.util.SVGConstants.SVG_POINTS_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_STROKE_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_TRANSFORM_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.TRANSFORM_TRANSLATE; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Point; + +import org.apache.taverna.workbench.models.graph.Graph; +import org.apache.taverna.workbench.models.graph.GraphEdge; +import org.apache.taverna.workbench.models.graph.GraphNode; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseClickEventListener; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseMovedEventListener; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseOutEventListener; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseOverEventListener; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseUpEventListener; + +import org.apache.batik.dom.svg.SVGOMAnimationElement; +import org.apache.batik.dom.svg.SVGOMGElement; +import org.apache.batik.dom.svg.SVGOMPolygonElement; +import org.apache.batik.dom.svg.SVGOMTextElement; +import org.w3c.dom.Text; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.svg.SVGElement; + +/** + * SVG representation of a graph. + * + * @author David Withers + */ +public class SVGGraph extends Graph { + private SVGGraphController graphController; + private SVGGraphElementDelegate delegate; + private SVGMouseClickEventListener mouseClickAction; + private SVGMouseMovedEventListener mouseMovedAction; + private SVGMouseUpEventListener mouseUpAction; + @SuppressWarnings("unused") + private SVGMouseOverEventListener mouseOverAction; + @SuppressWarnings("unused") + private SVGMouseOutEventListener mouseOutAction; + private SVGOMGElement mainGroup, labelGroup; + private SVGOMPolygonElement polygon, completedPolygon; + private SVGOMTextElement label, iteration, error; + private Text labelText, iterationText, errorsText; + private SVGOMAnimationElement animateShape, animatePosition, animateLabel; + + public SVGGraph(SVGGraphController graphController) { + super(graphController); + this.graphController = graphController; + + mouseClickAction = new SVGMouseClickEventListener(this); + mouseMovedAction = new SVGMouseMovedEventListener(this); + mouseUpAction = new SVGMouseUpEventListener(this); + mouseOverAction = new SVGMouseOverEventListener(this); + mouseOutAction = new SVGMouseOutEventListener(this); + + mainGroup = graphController.createGElem(); + mainGroup.setAttribute(SVG_FONT_SIZE_ATTRIBUTE, "10"); + mainGroup.setAttribute(SVG_FONT_FAMILY_ATTRIBUTE, "Helvetica"); + mainGroup.setAttribute(SVG_STROKE_ATTRIBUTE, CSS_BLACK_VALUE); + mainGroup.setAttribute(SVG_STROKE_DASHARRAY_ATTRIBUTE, CSS_NONE_VALUE); + mainGroup.setAttribute(SVG_STROKE_WIDTH_ATTRIBUTE, "1"); + mainGroup.setAttribute(SVG_FILL_ATTRIBUTE, CSS_NONE_VALUE); + + EventTarget t = (EventTarget) mainGroup; + t.addEventListener(SVG_CLICK_EVENT_TYPE, mouseClickAction, false); + t.addEventListener(SVG_MOUSEMOVE_EVENT_TYPE, mouseMovedAction, false); + t.addEventListener(SVG_MOUSEUP_EVENT_TYPE, mouseUpAction, false); + // t.addEventListener(SVGConstants.SVG_MOUSEOVER_EVENT_TYPE, mouseOverAction, false); + // t.addEventListener(SVGConstants.SVG_MOUSEOUT_EVENT_TYPE, mouseOutAction, false); + + polygon = graphController.createPolygon(); + mainGroup.appendChild(polygon); + + completedPolygon = graphController.createPolygon(); + completedPolygon.setAttribute(SVG_POINTS_ATTRIBUTE, + calculatePoints(getShape(), 0, 0)); + completedPolygon.setAttribute(SVG_FILL_ATTRIBUTE, COMPLETED_COLOUR); + // completedPolygon.setAttribute(SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE, "0.8"); + // completedPolygon.setAttribute(SVG_STROKE_ATTRIBUTE, SVG_NONE_VALUE); + mainGroup.appendChild(completedPolygon); + + labelText = graphController.createText(""); + label = graphController.createText(labelText); + label.setAttribute(SVG_TEXT_ANCHOR_ATTRIBUTE, SVG_MIDDLE_VALUE); + label.setAttribute(SVG_FILL_ATTRIBUTE, CSS_BLACK_VALUE); + label.setAttribute(SVG_STROKE_ATTRIBUTE, SVG_NONE_VALUE); + labelGroup = graphController.createGElem(); + labelGroup.appendChild(label); + mainGroup.appendChild(labelGroup); + + iterationText = graphController.createText(""); + iteration = graphController.createText(iterationText); + iteration.setAttribute(SVG_TEXT_ANCHOR_ATTRIBUTE, SVG_END_VALUE); + iteration.setAttribute(SVG_FONT_SIZE_ATTRIBUTE, "6"); + iteration.setAttribute(SVG_FONT_FAMILY_ATTRIBUTE, "sans-serif"); + iteration.setAttribute(SVG_FILL_ATTRIBUTE, CSS_BLACK_VALUE); + iteration.setAttribute(SVG_STROKE_ATTRIBUTE, SVG_NONE_VALUE); + polygon.appendChild(iteration); + + errorsText = graphController.createText(""); + error = graphController.createText(errorsText); + error.setAttribute(SVG_TEXT_ANCHOR_ATTRIBUTE, SVG_END_VALUE); + error.setAttribute(SVG_FONT_SIZE_ATTRIBUTE, "6"); + error.setAttribute(SVG_FONT_FAMILY_ATTRIBUTE, "sans-serif"); + error.setAttribute(SVG_FILL_ATTRIBUTE, CSS_BLACK_VALUE); + error.setAttribute(SVG_STROKE_ATTRIBUTE, SVG_NONE_VALUE); + polygon.appendChild(error); + + animateShape = createAnimationElement(graphController, SVG_ANIMATE_TAG, + SVG_POINTS_ATTRIBUTE, null); + + animatePosition = createAnimationElement(graphController, + SVG_ANIMATE_TRANSFORM_TAG, SVG_TRANSFORM_ATTRIBUTE, + TRANSFORM_TRANSLATE); + + animateLabel = createAnimationElement(graphController, + SVG_ANIMATE_TRANSFORM_TAG, SVG_TRANSFORM_ATTRIBUTE, + TRANSFORM_TRANSLATE); + + delegate = new SVGGraphElementDelegate(graphController, this, mainGroup); + } + + public SVGElement getSVGElement() { + return mainGroup; + } + + @Override + public void addEdge(GraphEdge edge) { + if (edge instanceof SVGGraphEdge) { + final SVGGraphEdge svgGraphEdge = (SVGGraphEdge) edge; + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + float opacity = svgGraphEdge.getOpacity(); + svgGraphEdge.setOpacity(0); + mainGroup.appendChild(svgGraphEdge.getSVGElement()); + svgGraphEdge.setOpacity(opacity); + } + }); + } + super.addEdge(edge); + } + + @Override + public void addNode(GraphNode node) { + super.addNode(node); + if (node instanceof SVGGraphNode) { + final SVGGraphNode svgGraphNode = (SVGGraphNode) node; + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + float opacity = svgGraphNode.getOpacity(); + svgGraphNode.setOpacity(0); + mainGroup.appendChild(svgGraphNode.getSVGElement()); + svgGraphNode.setOpacity(opacity); + } + }); + } + } + + @Override + public void addSubgraph(Graph subgraph) { + super.addSubgraph(subgraph); + if (subgraph instanceof SVGGraph) { + final SVGGraph svgGraph = (SVGGraph) subgraph; + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + float opacity = svgGraph.getOpacity(); + svgGraph.setOpacity(0); + mainGroup.appendChild(svgGraph.getSVGElement()); + svgGraph.setOpacity(opacity); + } + }); + } + } + + @Override + public boolean removeEdge(GraphEdge edge) { + if (edge instanceof SVGGraphEdge) { + final SVGGraphEdge svgGraphEdge = (SVGGraphEdge) edge; + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + mainGroup.removeChild(svgGraphEdge.getSVGElement()); + } + }); + } + return super.removeEdge(edge); + } + + @Override + public boolean removeNode(GraphNode node) { + if (node instanceof SVGGraphNode) { + final SVGGraphNode svgGraphNode = (SVGGraphNode) node; + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + mainGroup.removeChild(svgGraphNode.getSVGElement()); + } + }); + } + return super.removeNode(node); + } + + @Override + public boolean removeSubgraph(Graph subgraph) { + if (subgraph instanceof SVGGraph) { + final SVGGraph svgGraph = (SVGGraph) subgraph; + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + mainGroup.removeChild(svgGraph.getSVGElement()); + } + }); + } + return super.removeSubgraph(subgraph); + } + + @Override + public void setPosition(final Point position) { + final Point oldPosition = getPosition(); + if (position != null && !position.equals(oldPosition)) { + super.setPosition(position); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (graphController.isAnimatable()) + animate(animatePosition, polygon, + graphController.getAnimationSpeed(), + oldPosition.x + ", " + oldPosition.y, + position.x + ", " + position.y); + else + polygon.setAttribute(SVG_TRANSFORM_ATTRIBUTE, + "translate(" + position.x + " " + position.y + + ")"); + } + }); + } + } + + @Override + public void setSize(final Dimension size) { + final Dimension oldSize = getSize(); + if (size != null && !size.equals(oldSize)) { + super.setSize(size); + updateShape(oldSize.width, oldSize.height); + } + } + + @Override + public void setShape(Shape shape) { + final Dimension oldSize = getSize(); + final Shape currentShape = getShape(); + if (shape != null && !shape.equals(currentShape)) { + super.setShape(shape); + updateShape(oldSize.width, oldSize.height); + } + } + + @Override + public void setLabel(final String label) { + super.setLabel(label); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + labelText.setData(label); + } + }); + } + + @Override + public void setLabelPosition(final Point labelPosition) { + final Point oldLabelPosition = getLabelPosition(); + if (labelPosition != null && !labelPosition.equals(oldLabelPosition)) { + super.setLabelPosition(labelPosition); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (graphController.isAnimatable() + && oldLabelPosition != null) + animate(animateLabel, labelGroup, + graphController.getAnimationSpeed(), + oldLabelPosition.x + ", " + oldLabelPosition.y, + labelPosition.x + ", " + labelPosition.y); + else + labelGroup.setAttribute(SVG_TRANSFORM_ATTRIBUTE, + "translate(" + labelPosition.x + " " + + labelPosition.y + ")"); + } + }); + } + } + + @Override + public void setIteration(final int iteration) { + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (iteration > 0) + iterationText.setData(String.valueOf(iteration)); + else + iterationText.setData(""); + } + }); + } + + @Override + public void setCompleted(final float complete) { + super.setCompleted(complete); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + Dimension size = getSize(); + Point position = getPosition(); + completedPolygon.setAttribute( + SVG_POINTS_ATTRIBUTE, + calculatePoints(getShape(), + (int) (size.width * complete), size.height)); + completedPolygon.setAttribute(SVG_TRANSFORM_ATTRIBUTE, + "translate(" + position.x + " " + position.y + ")"); + } + }); + } + + private void updateShape(final int oldWidth, final int oldHeight) { + if (getShape() != null && getWidth() > 0f && getHeight() > 0f) { + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (graphController.isAnimatable()) + animate(animateShape, + polygon, + graphController.getAnimationSpeed(), + calculatePoints(getShape(), oldWidth, oldHeight), + calculatePoints(getShape(), getWidth(), + getHeight())); + else { + polygon.setAttribute( + SVG_POINTS_ATTRIBUTE, + calculatePoints(getShape(), getWidth(), + getHeight())); + iteration.setAttribute(SVG_TRANSFORM_ATTRIBUTE, + "translate(" + (getWidth() - 1.5) + " 5.5)"); + error.setAttribute(SVG_TRANSFORM_ATTRIBUTE, + "translate(" + (getWidth() - 1.5) + " " + + (getHeight() - 1) + ")"); + } + } + }); + } + } + + @Override + public void setSelected(final boolean selected) { + delegate.setSelected(selected); + super.setSelected(selected); + } + + @Override + public void setLineStyle(final LineStyle lineStyle) { + delegate.setLineStyle(lineStyle); + super.setLineStyle(lineStyle); + } + + @Override + public void setColor(final Color color) { + delegate.setColor(color); + super.setColor(color); + } + + @Override + public void setFillColor(final Color fillColor) { + delegate.setFillColor(fillColor); + super.setFillColor(fillColor); + } + + @Override + public void setVisible(final boolean visible) { + delegate.setVisible(visible); + super.setVisible(visible); + } + + @Override + public void setFiltered(final boolean filtered) { + delegate.setFiltered(filtered); + super.setFiltered(filtered); + } + + @Override + public void setOpacity(final float opacity) { + delegate.setOpacity(opacity); + super.setOpacity(opacity); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphController.java ---------------------------------------------------------------------- diff --git a/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphController.java b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphController.java new file mode 100644 index 0000000..7eb6453 --- /dev/null +++ b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphController.java @@ -0,0 +1,552 @@ +/******************************************************************************* + * 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 org.apache.taverna.workbench.models.graph.svg; + +import static java.awt.Color.BLACK; +import static java.awt.Color.GREEN; +import static java.lang.Float.parseFloat; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.animate; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.calculateAngle; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.createAnimationElement; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.createSVGDocument; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.getDot; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.getHexValue; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.svgNS; +import static org.apache.batik.util.SVGConstants.SVG_ANIMATE_TAG; +import static org.apache.batik.util.SVGConstants.SVG_ELLIPSE_TAG; +import static org.apache.batik.util.SVGConstants.SVG_FILL_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_FONT_FAMILY_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_FONT_SIZE_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_G_TAG; +import static org.apache.batik.util.SVGConstants.SVG_LINE_TAG; +import static org.apache.batik.util.SVGConstants.SVG_PATH_TAG; +import static org.apache.batik.util.SVGConstants.SVG_POINTS_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_POLYGON_TAG; +import static org.apache.batik.util.SVGConstants.SVG_RECT_TAG; +import static org.apache.batik.util.SVGConstants.SVG_STYLE_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_TEXT_TAG; +import static org.apache.batik.util.SVGConstants.SVG_TRANSFORM_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_VIEW_BOX_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_X1_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_X2_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_Y1_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_Y2_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_Y_ATTRIBUTE; + +import java.awt.Color; +import java.awt.Point; +import java.awt.Rectangle; +import java.io.IOException; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.apache.taverna.ui.menu.MenuManager; +import org.apache.taverna.workbench.configuration.colour.ColourManager; +import org.apache.taverna.workbench.configuration.workbench.WorkbenchConfiguration; +import org.apache.taverna.workbench.edits.EditManager; +import org.apache.taverna.workbench.models.graph.DotWriter; +import org.apache.taverna.workbench.models.graph.Graph; +import org.apache.taverna.workbench.models.graph.Graph.Alignment; +import org.apache.taverna.workbench.models.graph.GraphController; +import org.apache.taverna.workbench.models.graph.GraphEdge; +import org.apache.taverna.workbench.models.graph.GraphElement; +import org.apache.taverna.workbench.models.graph.GraphNode; +import org.apache.taverna.workbench.models.graph.dot.GraphLayout; + +import org.apache.batik.bridge.UpdateManager; +import org.apache.batik.dom.svg.SVGOMAnimationElement; +import org.apache.batik.dom.svg.SVGOMEllipseElement; +import org.apache.batik.dom.svg.SVGOMGElement; +import org.apache.batik.dom.svg.SVGOMPathElement; +import org.apache.batik.dom.svg.SVGOMPolygonElement; +import org.apache.batik.dom.svg.SVGOMRectElement; +import org.apache.batik.dom.svg.SVGOMTextElement; +import org.apache.batik.swing.JSVGCanvas; +import org.apache.batik.swing.gvt.GVTTreeRendererAdapter; +import org.apache.batik.swing.gvt.GVTTreeRendererEvent; +import org.apache.log4j.Logger; +import org.w3c.dom.Element; +import org.w3c.dom.Text; +import org.w3c.dom.svg.SVGDocument; +import org.w3c.dom.svg.SVGElement; +import org.w3c.dom.svg.SVGPoint; +import org.w3c.dom.svg.SVGSVGElement; + +import org.apache.taverna.scufl2.api.core.Workflow; +import org.apache.taverna.scufl2.api.profiles.Profile; + +public class SVGGraphController extends GraphController { + private static final Logger logger = Logger.getLogger(SVGGraphController.class); + @SuppressWarnings("unused") + private static final Timer timer = new Timer("SVG Graph controller timer", true); + private static final String dotErrorMessage = "Cannot draw diagram(s)\n" + + "\n" + + "Install dot as described\n" + + "at http://www.taverna.org.uk\n" + + "and specify its location\n" + + "in the workbench preferences"; + + private Map<String, List<SVGGraphEdge>> datalinkMap = new HashMap<>(); + private final JSVGCanvas svgCanvas; + private SVGDocument svgDocument; + private GraphLayout graphLayout = new GraphLayout(); + private EdgeLine edgeLine; + private UpdateManager updateManager; + private ExecutorService executor = Executors.newFixedThreadPool(1); + private boolean drawingDiagram = false; + private int animationSpeed; + private Rectangle bounds, oldBounds; + private SVGOMAnimationElement animateBounds; + private boolean dotMissing = false; + private final WorkbenchConfiguration workbenchConfiguration; + + public SVGGraphController(Workflow dataflow, Profile profile, + boolean interactive, JSVGCanvas svgCanvas, EditManager editManager, + MenuManager menuManager, ColourManager colourManager, + WorkbenchConfiguration workbenchConfiguration) { + super(dataflow, profile, interactive, svgCanvas, editManager, + menuManager, colourManager); + this.svgCanvas = svgCanvas; + this.workbenchConfiguration = workbenchConfiguration; + installUpdateManager(); + layoutSVGDocument(svgCanvas.getBounds()); + svgCanvas.setDocument(getSVGDocument()); + } + + public SVGGraphController(Workflow dataflow, Profile profile, + boolean interactive, JSVGCanvas svgCanvas, Alignment alignment, + PortStyle portStyle, EditManager editManager, + MenuManager menuManager, ColourManager colourManager, + WorkbenchConfiguration workbenchConfiguration) { + super(dataflow, profile, interactive, svgCanvas, alignment, portStyle, + editManager, menuManager, colourManager); + this.svgCanvas = svgCanvas; + this.workbenchConfiguration = workbenchConfiguration; + installUpdateManager(); + layoutSVGDocument(svgCanvas.getBounds()); + svgCanvas.setDocument(getSVGDocument()); + } + + private void installUpdateManager() { + svgCanvas.addGVTTreeRendererListener(new GVTTreeRendererAdapter() { + @Override + public void gvtRenderingCompleted(GVTTreeRendererEvent ev) { + setUpdateManager(svgCanvas.getUpdateManager()); + } + }); + } + + @Override + public GraphEdge createGraphEdge() { + return new SVGGraphEdge(this); + } + + @Override + public Graph createGraph() { + return new SVGGraph(this); + } + + @Override + public GraphNode createGraphNode() { + return new SVGGraphNode(this); + } + + public JSVGCanvas getSVGCanvas() { + return svgCanvas; + } + + public synchronized SVGDocument getSVGDocument() { + if (svgDocument == null) + svgDocument = createSVGDocument(); + return svgDocument; + } + + @Override + public void redraw() { + Graph graph = generateGraph(); + Rectangle actualBounds = layoutGraph(graph, svgCanvas.getBounds()); + setBounds(actualBounds); + transformGraph(getGraph(), graph); + } + + private void layoutSVGDocument(Rectangle bounds) { + animateBounds = createAnimationElement(this, SVG_ANIMATE_TAG, + SVG_VIEW_BOX_ATTRIBUTE, null); + updateManager = null; + datalinkMap.clear(); + + Graph graph = getGraph(); + if (graph instanceof SVGGraph) { + SVGGraph svgGraph = (SVGGraph) graph; + SVGSVGElement svgElement = getSVGDocument().getRootElement(); + SVGElement graphElement = svgGraph.getSVGElement(); + svgElement.appendChild(graphElement); + + setBounds(layoutGraph(graph, bounds)); + + edgeLine = EdgeLine.createAndAdd(getSVGDocument(), this); + } + drawingDiagram = true; + } + + public Rectangle layoutGraph(Graph graph, Rectangle bounds) { + Rectangle actualBounds = null; + bounds = new Rectangle(bounds); + StringWriter stringWriter = new StringWriter(); + DotWriter dotWriter = new DotWriter(stringWriter); + try { + dotWriter.writeGraph(graph); + String layout = getDot(stringWriter.toString(), workbenchConfiguration); + if (layout.isEmpty()) + logger.warn("Invalid dot returned"); + else + actualBounds = graphLayout.layoutGraph(this, graph, layout, bounds); + } catch (IOException e) { + outputMessage(dotErrorMessage); + setDotMissing(true); + logger.warn("Couldn't generate dot"); + } + return actualBounds; + } + + private void setDotMissing(boolean b) { + this.dotMissing = b; + } + + public boolean isDotMissing() { + return dotMissing; + } + + public void setBounds(final Rectangle bounds) { + oldBounds = this.bounds; + this.bounds = bounds; + updateSVGDocument(new Runnable() { + @Override + public void run() { + SVGSVGElement svgElement = getSVGDocument().getRootElement(); + if (isAnimatable() && oldBounds != null) { + String from = "0 0 " + oldBounds.width + " " + + oldBounds.height; + String to = "0 0 " + bounds.width + " " + bounds.height; + animate(animateBounds, svgElement, getAnimationSpeed(), + from, to); + } else if ((svgElement != null) && (bounds != null)) + svgElement.setAttribute(SVG_VIEW_BOX_ATTRIBUTE, + "0 0 " + String.valueOf(bounds.width) + " " + + String.valueOf(bounds.height)); + } + }); + } + + private void outputMessage(final String message) { + SVGSVGElement svgElement = getSVGDocument().getRootElement(); + String[] parts = message.split("\n"); + int initialPosition = 200; + for (int i = 0; i < parts.length; i++) { + Text errorsText = createText(parts[i]); + SVGOMTextElement error = (SVGOMTextElement) createElement(SVG_TEXT_TAG); + error.setAttribute(SVG_Y_ATTRIBUTE, + Integer.toString(initialPosition + i * 60)); + error.setAttribute(SVG_FONT_SIZE_ATTRIBUTE, "20"); + error.setAttribute(SVG_FONT_FAMILY_ATTRIBUTE, "sans-serif"); + error.setAttribute(SVG_FILL_ATTRIBUTE, "red"); + error.appendChild(errorsText); + svgElement.appendChild(error); + } + bounds = new Rectangle(300, parts.length * 60 + 200); + svgCanvas.setDocument(getSVGDocument()); + } + + public void setUpdateManager(UpdateManager updateManager) { + this.updateManager = updateManager; + drawingDiagram = false; + resetSelection(); + } + + @Override + public boolean startEdgeCreation(GraphElement graphElement, Point point) { + boolean alreadyStarted = edgeCreationFromSource || edgeCreationFromSink; + boolean started = super.startEdgeCreation(graphElement, point); + if (!alreadyStarted && started) { + if (edgeMoveElement instanceof SVGGraphEdge) { + SVGGraphEdge svgGraphEdge = (SVGGraphEdge) edgeMoveElement; + SVGPoint sourcePoint = svgGraphEdge.getPathElement() + .getPointAtLength(0f); + edgeLine.setSourcePoint(new Point((int) sourcePoint.getX(), + (int) sourcePoint.getY())); + } else + edgeLine.setSourcePoint(point); + edgeLine.setTargetPoint(point); + edgeLine.setColour(Color.BLACK); + // edgeLine.setVisible(true); + } + return started; + } + + @Override + public boolean moveEdgeCreationTarget(GraphElement graphElement, Point point) { + boolean linkValid = super.moveEdgeCreationTarget(graphElement, point); + if (edgeMoveElement instanceof SVGGraphEdge) + ((SVGGraphEdge) edgeMoveElement).setVisible(false); + if (edgeCreationFromSink) { + edgeLine.setSourcePoint(point); + if (linkValid) + edgeLine.setColour(GREEN); + else + edgeLine.setColour(BLACK); + edgeLine.setVisible(true); + } else if (edgeCreationFromSource) { + edgeLine.setTargetPoint(point); + if (linkValid) + edgeLine.setColour(GREEN); + else + edgeLine.setColour(BLACK); + edgeLine.setVisible(true); + } + return linkValid; + } + + @Override + public boolean stopEdgeCreation(GraphElement graphElement, Point point) { + GraphEdge movedEdge = edgeMoveElement; + boolean edgeCreated = super.stopEdgeCreation(graphElement, point); + if (!edgeCreated && movedEdge instanceof SVGGraphEdge) + ((SVGGraphEdge) movedEdge).setVisible(true); + edgeLine.setVisible(false); + return edgeCreated; + } + + @Override + public void setEdgeActive(String edgeId, boolean active) { + if (datalinkMap.containsKey(edgeId)) + for (GraphEdge datalink : datalinkMap.get(edgeId)) + datalink.setActive(active); + } + + public Element createElement(String tag) { + return getSVGDocument().createElementNS(svgNS, tag); + } + + SVGOMGElement createGElem() { + return (SVGOMGElement) createElement(SVG_G_TAG); + } + + SVGOMPolygonElement createPolygon() { + return (SVGOMPolygonElement) createElement(SVG_POLYGON_TAG); + } + + SVGOMEllipseElement createEllipse() { + return (SVGOMEllipseElement) createElement(SVG_ELLIPSE_TAG); + } + + SVGOMPathElement createPath() { + return (SVGOMPathElement) createElement(SVG_PATH_TAG); + } + + SVGOMRectElement createRect() { + return (SVGOMRectElement) createElement(SVG_RECT_TAG); + } + + public Text createText(String text) { + return getSVGDocument().createTextNode(text); + } + + SVGOMTextElement createText(Text text) { + SVGOMTextElement elem = (SVGOMTextElement) createElement(SVG_TEXT_TAG); + elem.appendChild(text); + return elem; + } + + public void updateSVGDocument(final Runnable thread) { + if (updateManager == null && !drawingDiagram) + thread.run(); + else if (!executor.isShutdown()) + executor.execute(new Runnable() { + @Override + public void run() { + waitForUpdateManager(); + try { + updateManager.getUpdateRunnableQueue().invokeLater( + thread); + } catch (IllegalStateException e) { + logger.error("Update of SVG failed", e); + } + } + + private void waitForUpdateManager() { + try { + while (updateManager == null) + Thread.sleep(200); + } catch (InterruptedException e) { + } + } + }); +// if (updateManager == null) +// thread.run(); +// else +// updateManager.getUpdateRunnableQueue().invokeLater(thread); + } + + public boolean isAnimatable() { + return animationSpeed > 0 && updateManager != null && !drawingDiagram; + } + + /** + * Returns the animation speed in milliseconds. + * + * @return the animation speed in milliseconds + */ + public int getAnimationSpeed() { + return animationSpeed; + } + + /** + * Sets the animation speed in milliseconds. A value of 0 turns off animation. + * + * @param animationSpeed the animation speed in milliseconds + */ + public void setAnimationSpeed(int animationSpeed) { + this.animationSpeed = animationSpeed; + } + + @Override + public void shutdown() { + super.shutdown(); + executor.execute(new Runnable() { + @Override + public void run() { + getSVGCanvas().stopProcessing(); + executor.shutdown(); + } + }); + } + +} + +class EdgeLine { + private static final float arrowLength = 10f; + private static final float arrowWidth = 3f; + + private Element line; + private Element pointer; + private SVGGraphController graphController; + + private EdgeLine(SVGGraphController graphController) { + this.graphController = graphController; + } + + public static EdgeLine createAndAdd(SVGDocument svgDocument, SVGGraphController graphController) { + EdgeLine edgeLine = new EdgeLine(graphController); + edgeLine.line = svgDocument.createElementNS(svgNS, SVG_LINE_TAG); + edgeLine.line.setAttribute(SVG_STYLE_ATTRIBUTE, + "fill:none;stroke:black"); + edgeLine.line.setAttribute("pointer-events", "none"); + edgeLine.line.setAttribute("visibility", "hidden"); + edgeLine.line.setAttribute(SVG_X1_ATTRIBUTE, "0"); + edgeLine.line.setAttribute(SVG_Y1_ATTRIBUTE, "0"); + edgeLine.line.setAttribute(SVG_X2_ATTRIBUTE, "0"); + edgeLine.line.setAttribute(SVG_Y2_ATTRIBUTE, "0"); + + edgeLine.pointer = svgDocument.createElementNS(svgNS, SVG_POLYGON_TAG); + edgeLine.pointer.setAttribute(SVG_STYLE_ATTRIBUTE, + "fill:black;stroke:black"); + edgeLine.pointer.setAttribute(SVG_POINTS_ATTRIBUTE, "0,0 " + + -arrowLength + "," + arrowWidth + " " + -arrowLength + "," + + -arrowWidth + " 0,0"); + edgeLine.pointer.setAttribute("pointer-events", "none"); + edgeLine.pointer.setAttribute("visibility", "hidden"); + + Element svgRoot = svgDocument.getDocumentElement(); + svgRoot.insertBefore(edgeLine.line, null); + svgRoot.insertBefore(edgeLine.pointer, null); + + return edgeLine; + } + + public void setSourcePoint(final Point point) { + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + line.setAttribute(SVG_X1_ATTRIBUTE, + String.valueOf(point.getX())); + line.setAttribute(SVG_Y1_ATTRIBUTE, + String.valueOf(point.getY())); + + float x = parseFloat(line.getAttribute(SVG_X2_ATTRIBUTE)); + float y = parseFloat(line.getAttribute(SVG_Y2_ATTRIBUTE)); + double angle = calculateAngle(line); + + pointer.setAttribute(SVG_TRANSFORM_ATTRIBUTE, "translate(" + x + + " " + y + ") rotate(" + angle + " 0 0) "); + } + }); + } + + public void setTargetPoint(final Point point) { + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + line.setAttribute(SVG_X2_ATTRIBUTE, + String.valueOf(point.getX())); + line.setAttribute(SVG_Y2_ATTRIBUTE, + String.valueOf(point.getY())); + + double angle = calculateAngle(line); + pointer.setAttribute(SVG_TRANSFORM_ATTRIBUTE, "translate(" + + point.x + " " + point.y + ") rotate(" + angle + + " 0 0) "); + } + }); + } + + public void setColour(final Color colour) { + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + String hexColour = getHexValue(colour); + line.setAttribute(SVG_STYLE_ATTRIBUTE, "fill:none;stroke:" + + hexColour + ";"); + pointer.setAttribute(SVG_STYLE_ATTRIBUTE, "fill:" + hexColour + + ";stroke:" + hexColour + ";"); + } + }); + } + + public void setVisible(final boolean visible) { + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (visible) { + line.setAttribute("visibility", "visible"); + pointer.setAttribute("visibility", "visible"); + } else { + line.setAttribute("visibility", "hidden"); + pointer.setAttribute("visibility", "hidden"); + } + } + }); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphEdge.java ---------------------------------------------------------------------- diff --git a/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphEdge.java b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphEdge.java new file mode 100644 index 0000000..736c6e5 --- /dev/null +++ b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphEdge.java @@ -0,0 +1,311 @@ +/******************************************************************************* + * 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 org.apache.taverna.workbench.models.graph.svg; + +import static org.apache.taverna.workbench.models.graph.svg.SVGGraphSettings.SELECTED_COLOUR; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.adjustPathLength; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.animate; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.calculateAngle; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.createAnimationElement; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.getHexValue; +import static org.apache.batik.util.CSSConstants.CSS_BLACK_VALUE; +import static org.apache.batik.util.CSSConstants.CSS_DISPLAY_PROPERTY; +import static org.apache.batik.util.CSSConstants.CSS_INLINE_VALUE; +import static org.apache.batik.util.CSSConstants.CSS_NONE_VALUE; +import static org.apache.batik.util.SMILConstants.SMIL_ADDITIVE_ATTRIBUTE; +import static org.apache.batik.util.SMILConstants.SMIL_SUM_VALUE; +import static org.apache.batik.util.SVGConstants.SVG_ANIMATE_TAG; +import static org.apache.batik.util.SVGConstants.SVG_ANIMATE_TRANSFORM_TAG; +import static org.apache.batik.util.SVGConstants.SVG_CLICK_EVENT_TYPE; +import static org.apache.batik.util.SVGConstants.SVG_CX_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_CY_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_D_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_FILL_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_MOUSEDOWN_EVENT_TYPE; +import static org.apache.batik.util.SVGConstants.SVG_NONE_VALUE; +import static org.apache.batik.util.SVGConstants.SVG_POINTS_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_RX_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_RY_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_STROKE_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_TRANSFORM_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_ZERO_VALUE; +import static org.apache.batik.util.SVGConstants.TRANSFORM_ROTATE; +import static org.apache.batik.util.SVGConstants.TRANSFORM_TRANSLATE; + +import java.awt.Color; +import java.awt.Point; +import java.util.List; + +import org.apache.taverna.workbench.models.graph.GraphEdge; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseClickEventListener; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseDownEventListener; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseOutEventListener; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseOverEventListener; + +import org.apache.batik.dom.svg.SVGGraphicsElement; +import org.apache.batik.dom.svg.SVGOMAnimationElement; +import org.apache.batik.dom.svg.SVGOMEllipseElement; +import org.apache.batik.dom.svg.SVGOMGElement; +import org.apache.batik.dom.svg.SVGOMPathElement; +import org.apache.batik.dom.svg.SVGOMPolygonElement; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.svg.SVGElement; + +/** + * SVG representation of a graph edge. + * + * @author David Withers + */ +public class SVGGraphEdge extends GraphEdge { + private static final String ARROW_LENGTH = "8.5"; + private static final String ARROW_WIDTH = "3"; + private static final String ELLIPSE_RADIUS = "3.5"; + + private SVGGraphController graphController; + private SVGGraphElementDelegate delegate; + private SVGMouseClickEventListener mouseClickAction; + private SVGMouseDownEventListener mouseDownAction; + @SuppressWarnings("unused") + private SVGMouseOverEventListener mouseOverAction; + @SuppressWarnings("unused") + private SVGMouseOutEventListener mouseOutAction; + private SVGOMGElement mainGroup; + private SVGOMPathElement path, deleteButton; + private SVGOMPolygonElement polygon; + private SVGOMEllipseElement ellipse; + private SVGGraphicsElement arrowHead; + private SVGOMAnimationElement animatePath, animatePosition, animateRotation; + + public SVGGraphEdge(SVGGraphController graphController) { + super(graphController); + this.graphController = graphController; + + mouseClickAction = new SVGMouseClickEventListener(this); + mouseDownAction = new SVGMouseDownEventListener(this); + mouseOverAction = new SVGMouseOverEventListener(this); + mouseOutAction = new SVGMouseOutEventListener(this); + + mainGroup = graphController.createGElem(); + mainGroup.setAttribute(SVG_STROKE_ATTRIBUTE, CSS_BLACK_VALUE); + mainGroup.setAttribute(SVG_STROKE_DASHARRAY_ATTRIBUTE, CSS_NONE_VALUE); + mainGroup.setAttribute(SVG_STROKE_WIDTH_ATTRIBUTE, "1"); + + path = graphController.createPath(); + path.setAttribute(SVG_FILL_ATTRIBUTE, SVG_NONE_VALUE); + EventTarget t = (EventTarget) path; + t.addEventListener(SVG_CLICK_EVENT_TYPE, mouseClickAction, false); + // t.addEventListener(SVGConstants.SVG_MOUSEOVER_EVENT_TYPE, mouseOverAction, false); + // t.addEventListener(SVGConstants.SVG_MOUSEOUT_EVENT_TYPE, mouseOutAction, false); + mainGroup.appendChild(path); + + polygon = graphController.createPolygon(); + polygon.setAttribute(SVG_POINTS_ATTRIBUTE, ARROW_LENGTH + ", 0" + + " 0, -" + ARROW_WIDTH + " 0," + ARROW_WIDTH); + t = (EventTarget) polygon; + t.addEventListener(SVG_CLICK_EVENT_TYPE, mouseClickAction, false); + t.addEventListener(SVG_MOUSEDOWN_EVENT_TYPE, mouseDownAction, false); + // t.addEventListener(SVGConstants.SVG_MOUSEOVER_EVENT_TYPE, mouseOverAction, false); + // t.addEventListener(SVGConstants.SVG_MOUSEOUT_EVENT_TYPE, mouseOutAction, false); + + ellipse = graphController.createEllipse(); + ellipse.setAttribute(SVG_CX_ATTRIBUTE, ELLIPSE_RADIUS); + ellipse.setAttribute(SVG_CY_ATTRIBUTE, SVG_ZERO_VALUE); + ellipse.setAttribute(SVG_RX_ATTRIBUTE, ELLIPSE_RADIUS); + ellipse.setAttribute(SVG_RY_ATTRIBUTE, ELLIPSE_RADIUS); + + arrowHead = polygon; + mainGroup.appendChild(arrowHead); + + deleteButton = graphController.createPath(); + deleteButton.setAttribute(SVG_STROKE_ATTRIBUTE, "red"); + deleteButton.setAttribute(SVG_STROKE_WIDTH_ATTRIBUTE, "2"); + deleteButton.setAttribute(SVG_D_ATTRIBUTE, + "M-3.5,-7L3.5,0M-3.5,0L3.5,-7"); + deleteButton.setAttribute(CSS_DISPLAY_PROPERTY, CSS_NONE_VALUE); + mainGroup.appendChild(deleteButton); + + animatePath = createAnimationElement(graphController, SVG_ANIMATE_TAG, + SVG_D_ATTRIBUTE, null); + + animatePosition = createAnimationElement(graphController, + SVG_ANIMATE_TRANSFORM_TAG, SVG_TRANSFORM_ATTRIBUTE, + TRANSFORM_TRANSLATE); + + animateRotation = createAnimationElement(graphController, + SVG_ANIMATE_TRANSFORM_TAG, SVG_TRANSFORM_ATTRIBUTE, + TRANSFORM_ROTATE); + animateRotation.setAttribute(SMIL_ADDITIVE_ATTRIBUTE, SMIL_SUM_VALUE); + + delegate = new SVGGraphElementDelegate(graphController, this, mainGroup); + } + + public SVGElement getSVGElement() { + return mainGroup; + } + + /** + * Returns the path. + * + * @return the path + */ + public SVGOMPathElement getPathElement() { + return path; + } + + @Override + public void setSelected(boolean selected) { + super.setSelected(selected); + final String color = selected ? SELECTED_COLOUR + : getHexValue(getColor()); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + mainGroup.setAttribute(SVG_STROKE_ATTRIBUTE, color); + mainGroup.setAttribute(SVG_FILL_ATTRIBUTE, color); + } + }); + } + + @Override + public void setActive(final boolean active) { + super.setActive(active); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (active) { + path.setAttribute(SVG_STROKE_WIDTH_ATTRIBUTE, "2"); + deleteButton.setAttribute(CSS_DISPLAY_PROPERTY, + CSS_INLINE_VALUE); + } else { + path.setAttribute(SVG_STROKE_WIDTH_ATTRIBUTE, "1"); + deleteButton.setAttribute(CSS_DISPLAY_PROPERTY, + CSS_NONE_VALUE); + } + } + }); + } + + @Override + public void setArrowHeadStyle(final ArrowStyle arrowHeadStyle) { + super.setArrowHeadStyle(arrowHeadStyle); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (ArrowStyle.NONE.equals(arrowHeadStyle)) + mainGroup.removeChild(arrowHead); + else if (ArrowStyle.NORMAL.equals(arrowHeadStyle)) { + mainGroup.removeChild(arrowHead); + arrowHead = polygon; + mainGroup.appendChild(arrowHead); + } else if (ArrowStyle.DOT.equals(arrowHeadStyle)) { + mainGroup.removeChild(arrowHead); + arrowHead = ellipse; + mainGroup.appendChild(arrowHead); + } + } + }); + } + + @Override + public void setPath(final List<Point> pointList) { + if (pointList == null) + return; + + final List<Point> oldPointList = getPath(); + super.setPath(pointList); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + Point lastPoint = pointList.get(pointList.size() - 1); + double angle = calculateAngle(pointList); + if (graphController.isAnimatable() && oldPointList != null) { + adjustPathLength(oldPointList, pointList.size()); + Point oldLastPoint = oldPointList.get(oldPointList.size() - 1); + double oldAngle = calculateAngle(oldPointList); + animate(animatePath, path, + graphController.getAnimationSpeed(), + SVGUtil.getPath(oldPointList), + SVGUtil.getPath(pointList)); + + animate(animatePosition, polygon, + graphController.getAnimationSpeed(), oldLastPoint.x + + ", " + oldLastPoint.y, lastPoint.x + ", " + + lastPoint.y); + + animate(animateRotation, polygon, + graphController.getAnimationSpeed(), oldAngle + + " 0 0", angle + " 0 0"); + + ellipse.setAttribute(SVG_TRANSFORM_ATTRIBUTE, "translate(" + + lastPoint.x + " " + lastPoint.y + ") rotate(" + + angle + " 0 0) "); + deleteButton.setAttribute(SVG_TRANSFORM_ATTRIBUTE, + "translate(" + lastPoint.x + " " + lastPoint.y + + ")"); + } else { + path.setAttribute(SVG_D_ATTRIBUTE, + SVGUtil.getPath(pointList)); + polygon.setAttribute(SVG_TRANSFORM_ATTRIBUTE, "translate(" + + lastPoint.x + " " + lastPoint.y + ") rotate(" + + angle + " 0 0) "); + ellipse.setAttribute(SVG_TRANSFORM_ATTRIBUTE, "translate(" + + lastPoint.x + " " + lastPoint.y + ") rotate(" + + angle + " 0 0) "); + deleteButton.setAttribute(SVG_TRANSFORM_ATTRIBUTE, + "translate(" + lastPoint.x + " " + lastPoint.y + + ")"); + } + } + }); + } + + @Override + public void setColor(final Color color) { + delegate.setColor(color); + super.setColor(color); + } + + @Override + public void setFillColor(final Color fillColor) { + delegate.setFillColor(fillColor); + super.setFillColor(fillColor); + } + + @Override + public void setVisible(final boolean visible) { + delegate.setVisible(visible); + super.setVisible(visible); + } + + @Override + public void setFiltered(final boolean filtered) { + delegate.setFiltered(filtered); + super.setFiltered(filtered); + } + + @Override + public void setOpacity(final float opacity) { + delegate.setOpacity(opacity); + super.setOpacity(opacity); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphElementDelegate.java ---------------------------------------------------------------------- diff --git a/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphElementDelegate.java b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphElementDelegate.java new file mode 100644 index 0000000..aaea6d1 --- /dev/null +++ b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphElementDelegate.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (C) 2009 The University of Manchester + * + * Modifications to the initial code base are copyright of their + * respective authors, or their employers as appropriate. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + ******************************************************************************/ +package org.apache.taverna.workbench.models.graph.svg; + +import static org.apache.taverna.workbench.models.graph.GraphElement.LineStyle.NONE; +import static org.apache.taverna.workbench.models.graph.svg.SVGGraphSettings.SELECTED_COLOUR; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.animate; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.createAnimationElement; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.getHexValue; +import static org.apache.batik.util.CSSConstants.CSS_DISPLAY_PROPERTY; +import static org.apache.batik.util.CSSConstants.CSS_INLINE_VALUE; +import static org.apache.batik.util.CSSConstants.CSS_NONE_VALUE; +import static org.apache.batik.util.CSSConstants.CSS_OPACITY_PROPERTY; +import static org.apache.batik.util.CSSConstants.CSS_POINTER_EVENTS_PROPERTY; +import static org.apache.batik.util.CSSConstants.CSS_VISIBLEPAINTED_VALUE; +import static org.apache.batik.util.SVGConstants.SVG_ANIMATE_TAG; +import static org.apache.batik.util.SVGConstants.SVG_FILL_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_NONE_VALUE; +import static org.apache.batik.util.SVGConstants.SVG_STROKE_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE; + +import java.awt.Color; + +import org.apache.taverna.workbench.models.graph.GraphElement; +import org.apache.taverna.workbench.models.graph.GraphElement.LineStyle; + +import org.apache.batik.dom.svg.SVGOMAnimationElement; +import org.apache.batik.dom.svg.SVGOMElement; + +/** + * Delegate for GraphElements. Logically a superclass of SVGGraph, SVGGraphNode + * and SVGGraphEdge (if java had multiple inheritance). + * + * @author David Withers + */ +public class SVGGraphElementDelegate { + private SVGGraphController graphController; + private GraphElement graphElement; + private SVGOMElement mainGroup; + private SVGOMAnimationElement animateOpacity; + + public SVGGraphElementDelegate(SVGGraphController graphController, + GraphElement graphElement, SVGOMElement mainGroup) { + this.graphController = graphController; + this.graphElement = graphElement; + this.mainGroup = mainGroup; + + animateOpacity = createAnimationElement(graphController, + SVG_ANIMATE_TAG, CSS_OPACITY_PROPERTY, null); + } + + public void setSelected(final boolean selected) { + boolean currentSelected = graphElement.isSelected(); + if (currentSelected != selected + && !LineStyle.NONE.equals(graphElement.getLineStyle())) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + mainGroup.setAttribute(SVG_STROKE_ATTRIBUTE, + selected ? SELECTED_COLOUR + : getHexValue(graphElement.getColor())); + mainGroup.setAttribute(SVG_STROKE_WIDTH_ATTRIBUTE, + selected ? "2" : "1"); + } + }); + } + + public void setLineStyle(final LineStyle lineStyle) { + LineStyle currentLineStyle = graphElement.getLineStyle(); + if (!currentLineStyle.equals(lineStyle)) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + String stroke = SVG_NONE_VALUE, dash = SVG_NONE_VALUE; + switch (lineStyle) { + case DOTTED: + stroke = getHexValue(graphElement.getColor()); + dash = "1,5"; + break; + case SOLID: + stroke = getHexValue(graphElement.getColor()); + default: + break; + } + mainGroup.setAttribute(SVG_STROKE_ATTRIBUTE, stroke); + mainGroup + .setAttribute(SVG_STROKE_DASHARRAY_ATTRIBUTE, dash); + } + }); + } + + public void setColor(final Color color) { + Color currentColor = graphElement.getColor(); + if (currentColor != color && NONE != graphElement.getLineStyle()) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + mainGroup.setAttribute(SVG_STROKE_ATTRIBUTE, + getHexValue(color)); + } + }); + } + + public void setFillColor(final Color fillColor) { + Color currentFillColor = graphElement.getFillColor(); + if (currentFillColor != fillColor) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + mainGroup.setAttribute(SVG_FILL_ATTRIBUTE, + getHexValue(fillColor)); + } + }); + } + + public void setVisible(final boolean visible) { + boolean currentVisible = graphElement.isVisible(); + if (currentVisible != visible) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + mainGroup.setAttribute(CSS_DISPLAY_PROPERTY, + visible ? CSS_INLINE_VALUE : CSS_NONE_VALUE); + } + }); + } + + public void setOpacity(final float opacity) { + final float currentOpacity = graphElement.getOpacity(); + if (currentOpacity != opacity) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (graphController.isAnimatable()) + animate(animateOpacity, mainGroup, + graphController.getAnimationSpeed(), + String.valueOf(currentOpacity), + String.valueOf(opacity)); + else + mainGroup.setAttribute(CSS_OPACITY_PROPERTY, + String.valueOf(opacity)); + } + }); + } + + public void setFiltered(final boolean filtered) { + boolean currentFiltered = graphElement.isFiltered(); + if (currentFiltered != filtered) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + mainGroup.setAttribute(CSS_POINTER_EVENTS_PROPERTY, + filtered ? CSS_NONE_VALUE + : CSS_VISIBLEPAINTED_VALUE); + setOpacity(filtered ? 0.2f : 1f); + } + }); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphNode.java ---------------------------------------------------------------------- diff --git a/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphNode.java b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphNode.java new file mode 100644 index 0000000..49ee0e1 --- /dev/null +++ b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphNode.java @@ -0,0 +1,611 @@ +/******************************************************************************* + * 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 org.apache.taverna.workbench.models.graph.svg; + +import static org.apache.taverna.workbench.models.graph.svg.SVGGraphSettings.COMPLETED_COLOUR; +import static org.apache.taverna.workbench.models.graph.svg.SVGGraphSettings.ERROR_COLOUR; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.animate; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.calculatePoints; +import static org.apache.taverna.workbench.models.graph.svg.SVGUtil.createAnimationElement; +import static org.apache.batik.util.CSSConstants.CSS_ALL_VALUE; +import static org.apache.batik.util.CSSConstants.CSS_BLACK_VALUE; +import static org.apache.batik.util.CSSConstants.CSS_DISPLAY_PROPERTY; +import static org.apache.batik.util.CSSConstants.CSS_HIDDEN_VALUE; +import static org.apache.batik.util.CSSConstants.CSS_INLINE_VALUE; +import static org.apache.batik.util.CSSConstants.CSS_NONE_VALUE; +import static org.apache.batik.util.CSSConstants.CSS_POINTER_EVENTS_PROPERTY; +import static org.apache.batik.util.CSSConstants.CSS_VISIBILITY_PROPERTY; +import static org.apache.batik.util.CSSConstants.CSS_VISIBLE_VALUE; +import static org.apache.batik.util.SVGConstants.SVG_ANIMATE_TAG; +import static org.apache.batik.util.SVGConstants.SVG_ANIMATE_TRANSFORM_TAG; +import static org.apache.batik.util.SVGConstants.SVG_CLICK_EVENT_TYPE; +import static org.apache.batik.util.SVGConstants.SVG_CX_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_CY_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_D_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_END_VALUE; +import static org.apache.batik.util.SVGConstants.SVG_FILL_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_FONT_FAMILY_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_FONT_SIZE_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_HEIGHT_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_MIDDLE_VALUE; +import static org.apache.batik.util.SVGConstants.SVG_MOUSEDOWN_EVENT_TYPE; +import static org.apache.batik.util.SVGConstants.SVG_MOUSEMOVE_EVENT_TYPE; +import static org.apache.batik.util.SVGConstants.SVG_MOUSEOUT_EVENT_TYPE; +import static org.apache.batik.util.SVGConstants.SVG_MOUSEOVER_EVENT_TYPE; +import static org.apache.batik.util.SVGConstants.SVG_NONE_VALUE; +import static org.apache.batik.util.SVGConstants.SVG_POINTS_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_RX_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_RY_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_STROKE_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_TRANSFORM_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_WIDTH_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_X_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.SVG_Y_ATTRIBUTE; +import static org.apache.batik.util.SVGConstants.TRANSFORM_TRANSLATE; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Point; + +import org.apache.taverna.workbench.models.graph.Graph; +import org.apache.taverna.workbench.models.graph.GraphNode; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseClickEventListener; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseDownEventListener; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseMovedEventListener; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseOutEventListener; +import org.apache.taverna.workbench.models.graph.svg.event.SVGMouseOverEventListener; + +import org.apache.batik.dom.svg.SVGOMAnimationElement; +import org.apache.batik.dom.svg.SVGOMEllipseElement; +import org.apache.batik.dom.svg.SVGOMGElement; +import org.apache.batik.dom.svg.SVGOMPathElement; +import org.apache.batik.dom.svg.SVGOMPolygonElement; +import org.apache.batik.dom.svg.SVGOMRectElement; +import org.apache.batik.dom.svg.SVGOMTextElement; +import org.apache.batik.util.CSSConstants; +import org.apache.batik.util.SVGConstants; +import org.w3c.dom.Text; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.svg.SVGElement; + +/** + * SVG representation of a graph node. + * + * @author David Withers + */ +public class SVGGraphNode extends GraphNode { + private SVGGraphController graphController; + private SVGGraphElementDelegate delegate; + private SVGMouseClickEventListener mouseClickAction; + private SVGMouseMovedEventListener mouseMovedAction; + private SVGMouseDownEventListener mouseDownAction; + @SuppressWarnings("unused") + private SVGMouseOverEventListener mouseOverAction; + @SuppressWarnings("unused") + private SVGMouseOutEventListener mouseOutAction; + private SVGOMGElement mainGroup, labelGroup, portsGroup; + private SVGElement expandedElement, contractedElement; + private SVGOMPolygonElement polygon, completedPolygon; + private SVGOMEllipseElement ellipse; + private SVGOMTextElement label, iteration, error; + private Text labelText, iterationText, errorsText; + private SVGElement deleteButton; + private SVGOMAnimationElement animateShape, animatePosition, animateLabel, animateIteration, + animateErrors; + + public SVGGraphNode(SVGGraphController graphController) { + super(graphController); + this.graphController = graphController; + mouseClickAction = new SVGMouseClickEventListener(this); + mouseDownAction = new SVGMouseDownEventListener(this); + mouseMovedAction = new SVGMouseMovedEventListener(this); + mouseOverAction = new SVGMouseOverEventListener(this); + mouseOutAction = new SVGMouseOutEventListener(this); + + mainGroup = graphController.createGElem(); + mainGroup.setAttribute("alignment-baseline", SVG_MIDDLE_VALUE); + mainGroup.setAttribute(SVG_STROKE_ATTRIBUTE, CSS_BLACK_VALUE); + mainGroup.setAttribute(SVG_STROKE_DASHARRAY_ATTRIBUTE, CSS_NONE_VALUE); + mainGroup.setAttribute(SVG_STROKE_WIDTH_ATTRIBUTE, "1"); + mainGroup.setAttribute(SVG_FILL_ATTRIBUTE, CSS_NONE_VALUE); + + EventTarget t = (EventTarget) mainGroup; + t.addEventListener(SVG_CLICK_EVENT_TYPE, mouseClickAction, false); + t.addEventListener(SVG_MOUSEMOVE_EVENT_TYPE, mouseMovedAction, false); + t.addEventListener(SVG_MOUSEDOWN_EVENT_TYPE, mouseDownAction, false); +// t.addEventListener(SVGConstants.SVG_MOUSEOVER_EVENT_TYPE, mouseOverAction, false); +// t.addEventListener(SVGConstants.SVG_MOUSEOUT_EVENT_TYPE, mouseOutAction, false); + + expandedElement = graphController.createGElem(); + contractedElement = graphController.createGElem(); + + portsGroup = graphController.createGElem(); + portsGroup.setAttribute(CSS_DISPLAY_PROPERTY, CSS_NONE_VALUE); + contractedElement.appendChild(portsGroup); + + mainGroup.appendChild(contractedElement); + + polygon = graphController.createPolygon(); + contractedElement.appendChild(polygon); + + ellipse = graphController.createEllipse(); + ellipse.setAttribute(CSS_DISPLAY_PROPERTY, CSS_NONE_VALUE); + ellipse.setAttribute(SVG_RX_ATTRIBUTE, String.valueOf(2)); + ellipse.setAttribute(SVG_CX_ATTRIBUTE, String.valueOf(0)); + ellipse.setAttribute(SVG_RY_ATTRIBUTE, String.valueOf(2)); + ellipse.setAttribute(SVG_CY_ATTRIBUTE, String.valueOf(0)); + contractedElement.appendChild(ellipse); + + completedPolygon = graphController.createPolygon(); + completedPolygon.setAttribute(SVG_POINTS_ATTRIBUTE, + calculatePoints(getShape(), 0, 0)); + completedPolygon.setAttribute(SVG_FILL_ATTRIBUTE, COMPLETED_COLOUR); + completedPolygon.setAttribute(SVG_FILL_OPACITY_ATTRIBUTE, "0.8"); + contractedElement.appendChild(completedPolygon); + + labelText = graphController.createText(""); + label = graphController.createText(labelText); + label.setAttribute(SVG_TEXT_ANCHOR_ATTRIBUTE, SVG_MIDDLE_VALUE); + label.setAttribute("baseline-shift", "-35%"); + label.setAttribute(SVG_FILL_ATTRIBUTE, CSS_BLACK_VALUE); + label.setAttribute(SVG_STROKE_ATTRIBUTE, SVGConstants.SVG_NONE_VALUE); + labelGroup = graphController.createGElem(); + labelGroup.appendChild(label); + contractedElement.appendChild(labelGroup); + + iterationText = graphController.createText(""); + iteration = graphController.createText(iterationText); + iteration.setAttribute(SVG_TEXT_ANCHOR_ATTRIBUTE, SVG_END_VALUE); + iteration.setAttribute(SVG_FONT_SIZE_ATTRIBUTE, "6"); + iteration.setAttribute(SVG_FONT_FAMILY_ATTRIBUTE, "sans-serif"); + iteration.setAttribute(SVG_FILL_ATTRIBUTE, CSS_BLACK_VALUE); + iteration.setAttribute(SVG_STROKE_ATTRIBUTE, SVG_NONE_VALUE); + contractedElement.appendChild(iteration); + + errorsText = graphController.createText(""); + error = graphController.createText(errorsText); + error.setAttribute(SVG_TEXT_ANCHOR_ATTRIBUTE, SVG_END_VALUE); + error.setAttribute(SVG_FONT_SIZE_ATTRIBUTE, "6"); + error.setAttribute(SVG_FONT_FAMILY_ATTRIBUTE, "sans-serif"); + error.setAttribute(SVG_FILL_ATTRIBUTE, CSSConstants.CSS_BLACK_VALUE); + error.setAttribute(SVG_STROKE_ATTRIBUTE, SVG_NONE_VALUE); + contractedElement.appendChild(error); + + // deleteButton = createDeleteButton(); + // g.appendChild(deleteButton); + + animateShape = createAnimationElement(graphController, SVG_ANIMATE_TAG, + SVG_POINTS_ATTRIBUTE, null); + + animatePosition = createAnimationElement(graphController, + SVG_ANIMATE_TRANSFORM_TAG, SVG_TRANSFORM_ATTRIBUTE, + TRANSFORM_TRANSLATE); + + animateLabel = SVGUtil.createAnimationElement(graphController, + SVG_ANIMATE_TRANSFORM_TAG, SVG_TRANSFORM_ATTRIBUTE, + TRANSFORM_TRANSLATE); + + animateIteration = createAnimationElement(graphController, + SVG_ANIMATE_TRANSFORM_TAG, SVG_TRANSFORM_ATTRIBUTE, + TRANSFORM_TRANSLATE); + + animateErrors = createAnimationElement(graphController, + SVG_ANIMATE_TRANSFORM_TAG, SVG_TRANSFORM_ATTRIBUTE, + TRANSFORM_TRANSLATE); + + delegate = new SVGGraphElementDelegate(graphController, this, mainGroup); + } + + @SuppressWarnings("unused") + private SVGElement createDeleteButton() { + final SVGOMGElement button = graphController.createGElem(); + button.setAttribute(CSS_VISIBILITY_PROPERTY, CSS_HIDDEN_VALUE); + button.setAttribute(CSS_POINTER_EVENTS_PROPERTY, CSS_ALL_VALUE); + + SVGOMRectElement rect = graphController.createRect(); + rect.setAttribute(SVG_X_ATTRIBUTE, "4"); + rect.setAttribute(SVG_Y_ATTRIBUTE, "4"); + rect.setAttribute(SVG_WIDTH_ATTRIBUTE, "13"); + rect.setAttribute(SVG_HEIGHT_ATTRIBUTE, "13"); + rect.setAttribute(SVG_FILL_ATTRIBUTE, "none"); + button.appendChild(rect); + + final SVGOMPathElement path = graphController.createPath(); + path.setAttribute(SVG_STROKE_ATTRIBUTE, "white"); + path.setAttribute(SVG_STROKE_WIDTH_ATTRIBUTE, "2"); + path.setAttribute(SVG_D_ATTRIBUTE, "M5,5L12,12M5,12L12,5"); + button.appendChild(path); + + EventTarget t = (EventTarget) button; + t.addEventListener(SVG_MOUSEOVER_EVENT_TYPE, new EventListener() { + @Override + public void handleEvent(Event evt) { + if (isInteractive()) { + deleteButton.setAttribute(CSS_VISIBILITY_PROPERTY, + CSS_VISIBLE_VALUE); + path.setAttribute(SVG_STROKE_ATTRIBUTE, "red"); + evt.stopPropagation(); + } + } + }, false); + t.addEventListener(SVG_MOUSEOUT_EVENT_TYPE, new EventListener() { + @Override + public void handleEvent(Event evt) { + if (isInteractive()) { + path.setAttribute(SVG_STROKE_ATTRIBUTE, "white"); + evt.stopPropagation(); + } + } + }, false); + + return button; + } + + public SVGElement getSVGElement() { + return mainGroup; + } + + @Override + public void setActive(final boolean active) { + super.setActive(active); + if (isInteractive()) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (active) { + deleteButton.setAttribute(CSS_VISIBILITY_PROPERTY, + CSS_VISIBLE_VALUE); + // deleteButton.setAttribute(CSSConstants.CSS_DISPLAY_PROPERTY, + // CSSConstants.CSS_INLINE_VALUE); + } else { + deleteButton.setAttribute(CSS_VISIBILITY_PROPERTY, + CSS_HIDDEN_VALUE); + // button.setAttribute(CSSConstants.CSS_DISPLAY_PROPERTY, + // CSSConstants.CSS_NONE_VALUE); + } + } + }); + } + + @Override + public void setGraph(Graph graph) { + super.setGraph(graph); + if (graph instanceof SVGGraph) { + SVGGraph svgGraph = (SVGGraph) graph; + final SVGElement graphElement = svgGraph.getSVGElement(); + if (isExpanded()) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + mainGroup.replaceChild(expandedElement, graphElement); + } + }); + expandedElement = graphElement; + } + } + + @Override + public void setExpanded(final boolean expanded) { + if (isExpanded() != expanded) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (expanded) + mainGroup.replaceChild(expandedElement, contractedElement); + else + mainGroup.replaceChild(contractedElement, expandedElement); + } + }); + super.setExpanded(expanded); + } + + @Override + public void addSourceNode(final GraphNode sourceNode) { + super.addSourceNode(sourceNode); + if (sourceNode instanceof SVGGraphNode) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + SVGGraphNode svgGraphNode = (SVGGraphNode) sourceNode; + portsGroup.appendChild(svgGraphNode.getSVGElement()); + } + }); + } + + @Override + public boolean removeSourceNode(final GraphNode sourceNode) { + if (sourceNode instanceof SVGGraphNode) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + SVGGraphNode svgGraphNode = (SVGGraphNode) sourceNode; + portsGroup.removeChild(svgGraphNode.getSVGElement()); + } + }); + return super.removeSourceNode(sourceNode); + } + + @Override + public void addSinkNode(final GraphNode sinkNode) { + super.addSinkNode(sinkNode); + if (sinkNode instanceof SVGGraphNode) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + SVGGraphNode svgGraphNode = (SVGGraphNode) sinkNode; + portsGroup.appendChild(svgGraphNode.getSVGElement()); + } + }); + } + + @Override + public boolean removeSinkNode(final GraphNode sinkNode) { + if (sinkNode instanceof SVGGraphNode) + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + SVGGraphNode svgGraphNode = (SVGGraphNode) sinkNode; + portsGroup.removeChild(svgGraphNode.getSVGElement()); + } + }); + return super.removeSinkNode(sinkNode); + } + + @Override + public void setPosition(final Point position) { + final Point oldPosition = getPosition(); + if (position != null && !position.equals(oldPosition)) { + super.setPosition(position); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (graphController.isAnimatable()) + animate(animatePosition, mainGroup, + graphController.getAnimationSpeed(), + oldPosition.x + ", " + oldPosition.y, + position.x + ", " + position.y); + else + mainGroup.setAttribute(SVG_TRANSFORM_ATTRIBUTE, + "translate(" + position.x + " " + position.y + + ")"); + } + }); + } + } + + @Override + public void setSize(final Dimension size) { + final Dimension oldSize = getSize(); + if (size != null && !size.equals(oldSize)) { + super.setSize(size); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + adjustSize(size, oldSize); + } + }); + } + } + + /** core of implementation of {@link #setSize(Dimension)} */ + private void adjustSize(Dimension size, Dimension oldSize) { + int oldWidth = oldSize.width; + int oldHeight = oldSize.height; + if (graphController.isAnimatable()) { + if (Shape.CIRCLE.equals(getShape())) { + ellipse.setAttribute(SVG_RX_ATTRIBUTE, + String.valueOf(size.width / 2f)); + ellipse.setAttribute(SVG_CX_ATTRIBUTE, + String.valueOf(size.width / 2f)); + ellipse.setAttribute(SVG_RY_ATTRIBUTE, + String.valueOf(size.height / 2f)); + ellipse.setAttribute(SVG_CY_ATTRIBUTE, + String.valueOf(size.height / 2f)); + } else + animate(animateShape, polygon, + graphController.getAnimationSpeed(), + calculatePoints(getShape(), oldWidth, oldHeight), + calculatePoints(getShape(), getWidth(), getHeight())); + + if (getLabel() != null && !getLabel().isEmpty()) + animate(animateLabel, labelGroup, + graphController.getAnimationSpeed(), (oldWidth / 2f) + + ", " + (oldHeight / 2f), (getWidth() / 2f) + + ", " + (getHeight() / 2f)); + else + labelGroup.setAttribute(SVG_TRANSFORM_ATTRIBUTE, + "translate(" + getWidth() / 2f + " " + getHeight() / 2f + ")"); + + if (getIteration() > 0) + animate(animateIteration, iteration, + graphController.getAnimationSpeed(), (oldWidth - 1.5) + + ", 5.5", (getWidth() - 1.5) + ", 5.5"); + else + iteration.setAttribute(SVG_TRANSFORM_ATTRIBUTE, "translate(" + + (getWidth() - 1.5) + " 5.5)"); + + if (getErrors() > 0) + animate(animateErrors, error, + graphController.getAnimationSpeed(), (oldWidth - 1.5) + + ", " + (oldHeight - 1), (getWidth() - 1.5) + + ", " + (getHeight() - 1)); + else + error.setAttribute(SVG_TRANSFORM_ATTRIBUTE, "translate(" + + (getWidth() - 1.5) + " " + (getHeight() - 1) + ")"); + } else { + if (Shape.CIRCLE.equals(getShape())) { + ellipse.setAttribute(SVG_RX_ATTRIBUTE, + String.valueOf(size.width / 2f)); + ellipse.setAttribute(SVG_CX_ATTRIBUTE, + String.valueOf(size.width / 2f)); + ellipse.setAttribute(SVG_RY_ATTRIBUTE, + String.valueOf(size.height / 2f)); + ellipse.setAttribute(SVG_CY_ATTRIBUTE, + String.valueOf(size.height / 2f)); + } else + polygon.setAttribute(SVG_POINTS_ATTRIBUTE, + calculatePoints(getShape(), getWidth(), getHeight())); + + labelGroup.setAttribute(SVG_TRANSFORM_ATTRIBUTE, "translate(" + + getWidth() / 2f + " " + getHeight() / 2f + ")"); + iteration.setAttribute(SVG_TRANSFORM_ATTRIBUTE, "translate(" + + (getWidth() - 1.5) + " 5.5)"); + error.setAttribute(SVG_TRANSFORM_ATTRIBUTE, "translate(" + + (getWidth() - 1.5) + " " + (getHeight() - 1) + ")"); + } + } + + @Override + public void setShape(final Shape shape) { + final Shape currentShape = getShape(); + if (shape != null && !shape.equals(currentShape)) { + super.setShape(shape); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (Shape.CIRCLE.equals(shape)) { + ellipse.setAttribute(CSS_DISPLAY_PROPERTY, + CSS_INLINE_VALUE); + polygon.setAttribute(CSS_DISPLAY_PROPERTY, + CSS_NONE_VALUE); + } else if (Shape.CIRCLE.equals(currentShape)) { + ellipse.setAttribute(CSS_DISPLAY_PROPERTY, + CSS_NONE_VALUE); + polygon.setAttribute(CSS_DISPLAY_PROPERTY, + CSS_INLINE_VALUE); + } + if (Shape.RECORD.equals(shape)) + portsGroup.setAttribute(CSS_DISPLAY_PROPERTY, + CSS_INLINE_VALUE); + else if (Shape.RECORD.equals(currentShape)) + portsGroup.setAttribute(CSS_DISPLAY_PROPERTY, + CSS_NONE_VALUE); + } + }); + } + } + + @Override + public void setLabel(final String label) { + super.setLabel(label); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + labelText.setData(label); + } + }); + } + + @Override + public void setIteration(final int iteration) { + super.setIteration(iteration); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (iteration > 0) + iterationText.setData(String.valueOf(iteration)); + else + iterationText.setData(""); + } + }); + } + + @Override + public void setErrors(final int errors) { + super.setErrors(errors); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + if (errors > 0) { + errorsText.setData(String.valueOf(errors)); + completedPolygon.setAttribute(SVG_FILL_ATTRIBUTE, + ERROR_COLOUR); + } else { + errorsText.setData(""); + completedPolygon.setAttribute(SVG_FILL_ATTRIBUTE, + COMPLETED_COLOUR); + } + } + }); + } + + @Override + public void setCompleted(final float complete) { + super.setCompleted(complete); + graphController.updateSVGDocument(new Runnable() { + @Override + public void run() { + completedPolygon.setAttribute( + SVG_POINTS_ATTRIBUTE, + calculatePoints(getShape(), + (int) (getWidth() * complete), getHeight())); + } + }); + } + + @Override + public void setSelected(final boolean selected) { + delegate.setSelected(selected); + super.setSelected(selected); + } + + @Override + public void setLineStyle(final LineStyle lineStyle) { + delegate.setLineStyle(lineStyle); + super.setLineStyle(lineStyle); + } + + @Override + public void setColor(final Color color) { + delegate.setColor(color); + super.setColor(color); + } + + @Override + public void setFillColor(final Color fillColor) { + delegate.setFillColor(fillColor); + super.setFillColor(fillColor); + } + + @Override + public void setVisible(final boolean visible) { + delegate.setVisible(visible); + super.setVisible(visible); + } + + @Override + public void setFiltered(final boolean filtered) { + delegate.setFiltered(filtered); + super.setFiltered(filtered); + } + + @Override + public void setOpacity(final float opacity) { + delegate.setOpacity(opacity); + super.setOpacity(opacity); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphSettings.java ---------------------------------------------------------------------- diff --git a/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphSettings.java b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphSettings.java new file mode 100644 index 0000000..2e9e228 --- /dev/null +++ b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGGraphSettings.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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 org.apache.taverna.workbench.models.graph.svg; + +public interface SVGGraphSettings { + String COMPLETED_COLOUR = "grey"; + String ERROR_COLOUR = "#dd3131"; + String SELECTED_COLOUR = "#4377d3"; + String NORMAL_COLOUR = "black"; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGMonitorShape.java ---------------------------------------------------------------------- diff --git a/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGMonitorShape.java b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGMonitorShape.java new file mode 100644 index 0000000..7944fc1 --- /dev/null +++ b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGMonitorShape.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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 org.apache.taverna.workbench.models.graph.svg; + +import org.apache.batik.dom.svg.SVGOMPolygonElement; + +public interface SVGMonitorShape extends SVGShape { + /** + * Returns the polygon used to display the completed value. + * + * @return the polygon used to display the completed value + */ + SVGOMPolygonElement getCompletedPolygon(); + + /** + * Sets the polygon used to display the completed value. + * + * @param polygon + * the new polygon used to display the completed value + */ + void setCompletedPolygon(SVGOMPolygonElement polygon); +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGShape.java ---------------------------------------------------------------------- diff --git a/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGShape.java b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGShape.java new file mode 100644 index 0000000..2bf4bf9 --- /dev/null +++ b/taverna-graph-model/src/main/java/org/apache/taverna/workbench/models/graph/svg/SVGShape.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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 org.apache.taverna.workbench.models.graph.svg; + +public interface SVGShape { + public void setIteration(final int iteration); + + // public void setErrors(final int errors); + + // public void setCompleted(final float complete); +}
