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);
+}

Reply via email to