Pārlūkot izejas kodu

6.5.0 release

Former-commit-id: 41ed65dd570f80220869dec887d0445d1fae9c0a
Gaudenz Alder 8 gadi atpakaļ
vecāks
revīzija
ff9a93bfc6
100 mainītis faili ar 1947 papildinājumiem un 2146 dzēšanām
  1. 19 0
      ChangeLog
  2. 1 1
      VERSION
  3. 13 14
      etc/mxgraph/mxClient.js
  4. 20 67
      src/com/mxgraph/io/mxVsdxCodec.java
  5. 48 702
      src/com/mxgraph/io/vsdx/Shape.java
  6. 96 53
      src/com/mxgraph/io/vsdx/VsdxShape.java
  7. 62 1
      src/com/mxgraph/io/vsdx/geometry/ArcTo.java
  8. 6 1
      src/com/mxgraph/io/vsdx/geometry/DelRow.java
  9. 44 1
      src/com/mxgraph/io/vsdx/geometry/Ellipse.java
  10. 158 1
      src/com/mxgraph/io/vsdx/geometry/EllipticalArcTo.java
  11. 6 2
      src/com/mxgraph/io/vsdx/geometry/InfiniteLine.java
  12. 27 1
      src/com/mxgraph/io/vsdx/geometry/LineTo.java
  13. 29 1
      src/com/mxgraph/io/vsdx/geometry/MoveTo.java
  14. 54 2
      src/com/mxgraph/io/vsdx/geometry/NURBSTo.java
  15. 53 1
      src/com/mxgraph/io/vsdx/geometry/PolylineTo.java
  16. 6 2
      src/com/mxgraph/io/vsdx/geometry/RelCubBezTo.java
  17. 6 2
      src/com/mxgraph/io/vsdx/geometry/RelEllipticalArcTo.java
  18. 20 1
      src/com/mxgraph/io/vsdx/geometry/RelLineTo.java
  19. 22 1
      src/com/mxgraph/io/vsdx/geometry/RelMoveTo.java
  20. 6 2
      src/com/mxgraph/io/vsdx/geometry/RelQuadBezTo.java
  21. 8 1
      src/com/mxgraph/io/vsdx/geometry/Row.java
  22. 16 41
      src/com/mxgraph/io/vsdx/geometry/RowFactory.java
  23. 34 1
      src/com/mxgraph/io/vsdx/geometry/SplineKnot.java
  24. 48 1
      src/com/mxgraph/io/vsdx/geometry/SplineStart.java
  25. 35 0
      src/com/mxgraph/io/vsdx/mxVsdxGeometry.java
  26. 26 0
      src/com/mxgraph/io/vsdx/mxVsdxGeometryList.java
  27. 1 1
      war/WEB-INF/appengine-web.xml
  28. BIN
      war/WEB-INF/lib/datanucleus-appengine-1.0.10.final.jar
  29. BIN
      war/WEB-INF/lib/datanucleus-core-1.1.5.jar
  30. BIN
      war/WEB-INF/lib/datanucleus-jpa-1.1.5.jar
  31. BIN
      war/WEB-INF/lib/geronimo-jpa_3.0_spec-1.1.1.jar
  32. BIN
      war/WEB-INF/lib/geronimo-jta_1.1_spec-1.1.1.jar
  33. BIN
      war/WEB-INF/lib/jdo2-api-2.3-eb.jar
  34. 1 1
      war/cache.manifest
  35. 0 236
      war/export.html
  36. 28 2
      war/export2.html
  37. 166 168
      war/js/app.min.js
  38. 150 149
      war/js/atlas-viewer.min.js
  39. 167 169
      war/js/atlas.min.js
  40. 130 94
      war/js/diagramly/App.js
  41. 3 3
      war/js/diagramly/Dialogs.js
  42. 92 89
      war/js/diagramly/Editor.js
  43. 11 35
      war/js/diagramly/EditorUi.js
  44. 1 1
      war/js/diagramly/Embed.js
  45. 10 4
      war/js/diagramly/GitHubClient.js
  46. 1 1
      war/js/diagramly/GraphViewer.js
  47. 3 3
      war/js/diagramly/Menus.js
  48. 4 0
      war/js/diagramly/Settings.js
  49. 4 2
      war/js/diagramly/StorageFile.js
  50. 4 2
      war/js/diagramly/StorageLibrary.js
  51. 4 2
      war/js/diagramly/UrlLibrary.js
  52. 37 37
      war/js/embed-static.min.js
  53. 1 1
      war/js/embed.dev.js
  54. 1 1
      war/js/embed.min.js
  55. 3 1
      war/js/mxgraph/Actions.js
  56. 22 23
      war/js/mxgraph/Editor.js
  57. 15 1
      war/js/mxgraph/EditorUi.js
  58. 2 2
      war/js/mxgraph/Format.js
  59. 11 11
      war/js/mxgraph/Menus.js
  60. 16 2
      war/js/mxgraph/Shapes.js
  61. 36 36
      war/js/reader.min.js
  62. 150 150
      war/js/viewer.min.js
  63. 1 1
      war/shortcuts.svg
  64. BIN
      war/templates/business/bpmn.png
  65. 1 1
      war/templates/business/bpmn.xml
  66. BIN
      war/templates/business/bpmnS.png
  67. 0 1
      war/templates/business/bpmnS.xml
  68. BIN
      war/templates/business/swimlane.png
  69. 1 1
      war/templates/business/swimlane.xml
  70. BIN
      war/templates/business/swimlaneS.png
  71. 0 1
      war/templates/business/swimlaneS.xml
  72. BIN
      war/templates/charts/bar.png
  73. 1 1
      war/templates/charts/bar.xml
  74. BIN
      war/templates/charts/bar2.png
  75. 1 1
      war/templates/charts/bar2.xml
  76. BIN
      war/templates/charts/bar2S.png
  77. 0 1
      war/templates/charts/bar2S.xml
  78. BIN
      war/templates/charts/barS.png
  79. 0 1
      war/templates/charts/barS.xml
  80. BIN
      war/templates/charts/org1.png
  81. 1 1
      war/templates/charts/org1.xml
  82. BIN
      war/templates/charts/org1S.png
  83. 0 1
      war/templates/charts/org1S.xml
  84. BIN
      war/templates/charts/org2.png
  85. 1 1
      war/templates/charts/org2.xml
  86. BIN
      war/templates/charts/org2S.png
  87. 0 1
      war/templates/charts/org2S.xml
  88. BIN
      war/templates/charts/work_breakdown_structure.png
  89. 1 1
      war/templates/charts/work_breakdown_structure.xml
  90. BIN
      war/templates/charts/work_breakdown_structureS.png
  91. 0 1
      war/templates/charts/work_breakdown_structureS.xml
  92. BIN
      war/templates/flowcharts/flowchart1.png
  93. 1 1
      war/templates/flowcharts/flowchart1.xml
  94. BIN
      war/templates/flowcharts/flowchart1S.png
  95. 0 1
      war/templates/flowcharts/flowchart1S.xml
  96. BIN
      war/templates/flowcharts/flowchart2.png
  97. 1 1
      war/templates/flowcharts/flowchart2.xml
  98. BIN
      war/templates/flowcharts/flowchart2S.png
  99. 0 1
      war/templates/flowcharts/flowchart2S.xml
  100. 0 0
      war/templates/flowcharts/gantt.png

+ 19 - 0
ChangeLog

@@ -1,3 +1,22 @@
+13-APR-2017: 6.5.0
+
+- Fixes extension for exported files with dots
+- Fixes lost changes after create or open file in same window
+- Fixes ignored default page size for Google Drive files
+- Adds Alt+Shift+C for clear waypoints
+- Adds toFront/Back context menu for multiple cells
+- Adds arc size for copy/paste style
+- Fixes rounded swimlane boundary cases
+- Uses Cloudflare CDN for loading MathJax
+- Adds clear waypoints for vertices with connections
+- Adds error handling for saving macro in Confluence Cloud
+- Fixes cloned start/end arrow when splitting edge
+- Adds support for global shadow in PDF export
+- Fixes special characters in branch names for GitHub client
+- Fixes missing arc handle for unknown shapes
+- Fixes hightlight size for arrows
+- Uses mxGraph 3.7.2
+
 06-APR-2017: 6.4.6
 
 - Works around page counter loop condition in FF

+ 1 - 1
VERSION

@@ -1 +1 @@
-6.4.6
+6.5.0

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 13 - 14
etc/mxgraph/mxClient.js


+ 20 - 67
src/com/mxgraph/io/mxVsdxCodec.java

@@ -254,7 +254,9 @@ public class mxVsdxCodec
 				
 				graph.setConstrainChildren(false);
 				graph.setHtmlLabels(true);
-	
+				//Prevent change of edge parent as it misses with the routing points
+				((mxGraphModel)graph.getModel()).setMaintainEdgeParent(false);
+				
 				graph.getModel().beginUpdate();
 				importPage(page, graph, graph.getDefaultParent());
 				
@@ -855,52 +857,24 @@ public class mxVsdxCodec
 
 		//Get beginXY and endXY coordinates.
 		mxPoint beginXY = edgeShape.getStartXY(parentHeight);
+		mxPoint origBeginXY = new mxPoint(beginXY);
+		
 		beginXY = calculateAbsolutePoint(parent, graph, beginXY);
 
 		mxPoint fromConstraint = null;
 		Integer sourceSheet = connect.getSourceToSheet();
 
-		VsdxShape fromShape = sourceSheet != null ? vertexShapeMap
-				.get(new ShapePageId(pageId, sourceSheet)) : null;
-
 		mxCell source = sourceSheet != null ? vertexMap
 				.get(new ShapePageId(pageId, sourceSheet)) : null;
 
-		if (fromShape == null || source == null)
+		if (source == null)
 		{
 			// Source is dangling
 			source = (mxCell) graph.insertVertex(parent, null, null,
 					beginXY.getX(), beginXY.getY(), 0, 0);
 			fromConstraint = new mxPoint(0, 0);
 		}
-		else
-		{
-			mxCell srcTopParent = findTopParent(source, (mxCell) graph.getDefaultParent());
-
-			mxPoint dimensionFrom = fromShape.getDimensions();
-
-			//Get From shape origin and begin/end of edge in absolutes values.
-			double height = pageHeight;
-
-			if ((srcTopParent != null)
-					&& (srcTopParent.getGeometry() != null))
-			{
-				height = srcTopParent.getGeometry().getHeight();
-			}
-
-			mxPoint originFrom = fromShape.getOriginPoint(height, false);
-			Integer sourceToPart = connect.getSourceToPart();
-
-			if (sourceToPart != mxVsdxConstants.CONNECT_TO_PART_WHOLE_SHAPE)
-			{
-				mxPoint absOriginFrom = calculateAbsolutePoint(srcTopParent, graph, originFrom);
-				fromConstraint = new mxPoint(
-						(beginXY.getX() - absOriginFrom.getX())
-								/ dimensionFrom.getX(),
-						(beginXY.getY() - absOriginFrom.getY())
-								/ dimensionFrom.getY());
-			}
-		}
+		//Else: Routing points will contain the exit/entry points, so no need to set the to/from constraint 
 
 		mxPoint endXY = edgeShape.getEndXY(parentHeight);
 		endXY = calculateAbsolutePoint(parent, graph, endXY);
@@ -908,53 +882,24 @@ public class mxVsdxCodec
 		mxPoint toConstraint = null;
 		Integer toSheet = connect.getTargetToSheet();
 
-		VsdxShape toShape = toSheet != null ? vertexShapeMap
-				.get(new ShapePageId(pageId, toSheet)) : null;
-
 		mxCell target = toSheet != null ? vertexMap.get(new ShapePageId(
 				pageId, toSheet)) : null;
 
-		if (toShape == null || target == null)
+		if (target == null)
 		{
 			// Target is dangling
 			target = (mxCell) graph.insertVertex(parent, null, null,
 					endXY.getX(), endXY.getY(), 0, 0);
 			toConstraint = new mxPoint(0, 0);
 		}
-		else
-		{
-			target = vertexMap.get(new ShapePageId(pageId, toSheet));
-			mxCell trgTopParent = findTopParent(target, (mxCell) graph.getDefaultParent());
-			mxPoint dimentionTo = toShape.getDimensions();
-
-			//Get To shape origin.
-			double height = pageHeight;
-
-			if ((trgTopParent != null)
-					&& (trgTopParent.getGeometry() != null))
-			{
-				height = trgTopParent.getGeometry().getHeight();
-			}
-
-			mxPoint originTo = toShape.getOriginPoint(height, false);
-			Integer targetToPart = connect.getTargetToPart();
-
-			if (targetToPart != mxVsdxConstants.CONNECT_TO_PART_WHOLE_SHAPE)
-			{
-				mxPoint absOriginTo = calculateAbsolutePoint( trgTopParent, graph, originTo);
-				toConstraint = new mxPoint(
-						(endXY.getX() - absOriginTo.getX())
-								/ dimentionTo.getX(),
-						(endXY.getY() - absOriginTo.getY())
-								/ dimentionTo.getY());
-			}
-		}
+		//Else: Routing points will contain the exit/entry points, so no need to set the to/from constraint 
 
 		//Defines the style of the edge.
 		Map<String, String> styleMap = edgeShape
 				.getStyleFromEdgeShape(parentHeight);
 		//Insert new edge and set constraints.
 		Object edge;
+		List<mxPoint> points = edgeShape.getRoutingPoints(parentHeight, origBeginXY, edgeShape.getRotation());
 		double rotation = edgeShape.getRotation();
 		if (rotation != 0)
 		{
@@ -977,10 +922,13 @@ public class mxVsdxCodec
 		{
 			edge = graph.insertEdge(parent, null, edgeShape.getTextLabel(), source,
 					target, mxVsdxUtils.getStyleString(styleMap, "="));
+			
+			mxPoint lblOffset = edgeShape.getLblEdgeOffset(beginXY, endXY, points);
+			((mxCell)edge).getGeometry().setOffset(lblOffset);
 		}
 		
 		mxGeometry edgeGeometry = graph.getModel().getGeometry(edge);
-		edgeGeometry.setPoints(edgeShape.getRoutingPoints(parentHeight, beginXY, edgeShape.getRotation()));
+		edgeGeometry.setPoints(points);
 
 		if (fromConstraint != null)
 		{
@@ -1046,6 +994,7 @@ public class mxVsdxCodec
 		}
 
 		mxPoint beginXY = edgeShape.getStartXY(parentHeight);
+		mxPoint origBeginXY = new mxPoint(beginXY);
 		mxPoint endXY = edgeShape.getEndXY(parentHeight);
 
 		//Define style of the edge
@@ -1055,6 +1004,7 @@ public class mxVsdxCodec
 		
 		//Insert new edge and set constraints.
 		Object edge;
+		List<mxPoint> points = edgeShape.getRoutingPoints(parentHeight, origBeginXY, edgeShape.getRotation());
 		double rotation = edgeShape.getRotation();
 		if (rotation != 0)
 		{
@@ -1075,9 +1025,12 @@ public class mxVsdxCodec
 		else
 		{
 			edge = graph.insertEdge(parent, null, edgeShape.getTextLabel(), null, null, mxVsdxUtils.getStyleString(styleMap, "="));
+			
+			mxPoint lblOffset = edgeShape.getLblEdgeOffset(beginXY, endXY, points);
+			((mxCell)edge).getGeometry().setOffset(lblOffset);
 		}
 		mxGeometry edgeGeometry = graph.getModel().getGeometry(edge);
-		edgeGeometry.setPoints(edgeShape.getRoutingPoints(parentHeight, beginXY, edgeShape.getRotation()));
+		edgeGeometry.setPoints(points);
 		
 		edgeGeometry.setTerminalPoint(beginXY, true);
 		edgeGeometry.setTerminalPoint(endXY, false);

+ 48 - 702
src/com/mxgraph/io/vsdx/Shape.java

@@ -5,10 +5,8 @@
 package com.mxgraph.io.vsdx;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -295,707 +293,12 @@ public class Shape extends Style
 	 */
 	protected String parseGeom()
 	{
-		if (!hasGeom())
+		if (!hasGeomList())
 		{
 			return "";
 		}
 		
-		String parsedGeom = "";
-		double h = this.getHeight();
-		double w = this.getWidth();
-		double x = 0, y = 0;
-		
-		for (int i = 0; i < geom.size(); i++)
-		{
-			boolean isFill = true;
-			boolean isLine = true;
-			boolean isShow = true;
-			boolean isSnap = true;
-			String geomElemParsed = "";
-
-			Node child = geom.get(i).getFirstChild();
-			
-			while (child != null)
-			{
-				if (child instanceof Element)
-				{
-					Element childElem = (Element) child;
-					String childName = childElem.getNodeName();
-					String value = null;
-					
-					if (childName.equals("Cell"))
-					{
-						childName = childElem.getAttribute("N");
-						value = childElem.getAttribute("V");
-					}
-					else if (childName.equals("Row"))
-					{
-						childName = childElem.getAttribute("T");
-					}
-					else
-					{
-						value = childElem.getTextContent();
-					}
-					
-					switch (childName)
-					{
-						case "NoFill":
-							if (value != null && value.equals("1"))
-							{
-								isFill = false;
-							}
-							break;
-						case "NoLine":
-							if (value != null && value.equals("1"))
-							{
-								isLine = false;
-							}
-							break;
-						case "NoShow":
-							if (value != null && value.equals("1"))
-							{
-								isShow = false;
-							}
-							break;
-						case "NoSnap":
-							if (value != null && value.equals("1"))
-							{
-								isSnap = false;
-							}
-							break;
-						case "MoveTo":
-							Map <String, String> children = getChildValues(childElem, null);
-							String xValue = children.get("X");
-							String yValue = children.get("Y");
-								
-							if (xValue != null && yValue != null)
-							{
-								x = Double.parseDouble(xValue) * mxVsdxUtils.conversionFactor;
-								y = Double.parseDouble(yValue) * mxVsdxUtils.conversionFactor;
-							}
-							
-							x = x * 100.0 / w;
-							y = y * 100.0 / h;
-							y = 100 - y;
-
-							x = Math.round(x * 100.0) / 100.0;
-							y = Math.round(y * 100.0) / 100.0;
-							
-							this.lastX = x;
-							this.lastY = y;
-							this.lastMoveX = x;
-							this.lastMoveY = y;
-
-							geomElemParsed += "<" + "move" + " x=\"" + String.valueOf(x) + "\" y=\"" + String.valueOf(y) + "\"/>";
-							break;
-						case "RelMoveTo":
-							children = getChildValues(childElem, null);
-							xValue = children.get("X");
-							yValue = children.get("Y");
-								
-							if (xValue != null && yValue != null)
-							{
-								x = Double.parseDouble(xValue) * 100;
-								y = 100 - Double.parseDouble(yValue) * 100;
-							}
-							
-							x = Math.round(x * 100.0) / 100.0;
-							y = Math.round(y * 100.0) / 100.0;
-							
-							this.lastX = x;
-							this.lastY = y;
-							this.lastMoveX = x;
-							this.lastMoveY = y;
-
-							geomElemParsed += "<" + "move" + " x=\"" + String.valueOf(x) + "\" y=\"" + String.valueOf(y) + "\"/>";
-							break;
-						case "LineTo":
-							children = getChildValues(childElem, null);
-							xValue = children.get("X");
-							yValue = children.get("Y");
-								
-							if (xValue != null && yValue != null)
-							{
-								x = Double.parseDouble(xValue) * mxVsdxUtils.conversionFactor;
-								y = Double.parseDouble(yValue) * mxVsdxUtils.conversionFactor;
-							}
-	
-							x = x * 100.0 / w;
-							y = y * 100.0 / h;
-							y = 100 - y;
-
-							x = Math.round(x * 100.0) / 100.0;
-							y = Math.round(y * 100.0) / 100.0;
-							
-							this.lastX = x;
-							this.lastY = y;
-
-							geomElemParsed += "<" + "line" + " x=\"" + String.valueOf(x) + "\" y=\"" + String.valueOf(y) + "\"/>";
-							break;
-						case "RelLineTo":
-							children = getChildValues(childElem, null);
-							xValue = children.get("X");
-							yValue = children.get("Y");
-								
-							if (xValue != null && yValue != null)
-							{
-								x = Double.parseDouble(xValue) * 100;
-								y = 100 - Double.parseDouble(yValue) * 100;
-							}
-							
-							x = Math.round(x * 100.0) / 100.0;
-							y = Math.round(y * 100.0) / 100.0;
-							
-							this.lastX = x;
-							this.lastY = y;
-
-							geomElemParsed += "<" + "line" + " x=\"" + String.valueOf(x) + "\" y=\"" + String.valueOf(y) + "\"/>";
-							break;
-						case "NURBSTo":
-							geomElemParsed += nurbsPath(childElem, "curve");
-							break;
-						case "ArcTo":
-							geomElemParsed += arcPath(childElem, "arc");
-							break;
-						case "InfiniteLine":
-							//xyElem(childElem, "line");
-							break;
-						case "Ellipse":
-							geomElemParsed += ellipsePath(childElem, "ellipse");
-							break;
-						case "EllipticalArcTo":
-							geomElemParsed += ellArcPath(childElem, "arc");
-							break;
-						case "SplineStart":
-							geomElemParsed += splineStartPath(childElem, "splineStart");
-							break;
-						case "SplineKnot":
-							geomElemParsed += splinePath(childElem, "splineKnot");
-							break;
-						case "PolylineTo":
-							geomElemParsed += polyPath(childElem, "poly");
-							break;
-						default:
-							this.styleDebug("ERROR: geom type not understood  - " + childName);
-							break;
-							
-					}
-				}
-
-				child = child.getNextSibling();
-			}
-			
-			if (isShow && !geomElemParsed.equals(""))
-			{
-				geomElemParsed += "</path>";
-				
-				if (isLine && isFill)
-				{
-					geomElemParsed += "<fillstroke/>";
-				}
-				else if (isFill)
-				{
-					geomElemParsed += "<fill/>";
-				}
-				else if (isLine)
-				{
-					geomElemParsed += "<stroke/>";
-				}
-				
-				parsedGeom += "<path>" + geomElemParsed;
-			}
-		}
-
-		if (parsedGeom.equals(""))
-		{
-			return "";
-		}
-		
-		//System.out.println(parsedGeom);
-
-		return "<shape strokewidth=\"inherit\"><foreground>" + parsedGeom + "</foreground></shape>";
-	}
-
-	protected String arcPath(Element arcElem, String command)
-	{
-		Map <String, String> children = getChildValues(arcElem, null);
-		String xValue = children.get("X");
-		String yValue = children.get("Y");
-		String aValue = children.get("A");
-			
-		if (xValue != null && yValue != null && aValue != null)
-		{
-			double h = this.getHeight();
-			double w = this.getWidth();
-			double x0 = Math.round(this.lastX * w) / 100;
-			double y0 = Math.round(this.lastY * h) / 100;
-			double x = Double.parseDouble(xValue) * mxVsdxUtils.conversionFactor;
-			
-			double y = Double.parseDouble(yValue) * mxVsdxUtils.conversionFactor;
-			y = h - y;
-			
-			double a = Double.parseDouble(aValue) * mxVsdxUtils.conversionFactor;
-
-			double dx = Math.abs(x - x0);
-			double dy = Math.abs(y - y0);
-
-			double rx = (a * 0.5) + (dx * dx + dy * dy) / (8.0 * a);
-			double ry = rx;
-			double r0 = Math.abs(rx);
-			
-			rx = rx * 100 / w;
-			ry = ry * 100 / h;
-			x = x * 100 / w;
-			y = y * 100 / h;
-			rx = Math.round(rx * 100.0) / 100.0;
-			ry = Math.round(ry * 100.0) / 100.0;
-			x = Math.round(x * 100.0) / 100.0;
-			y = Math.round(y * 100.0) / 100.0;
-
-			a = Math.round(a * 100.0) / 100.0;
-			rx = Math.abs(rx);
-			ry = Math.abs(ry);
-			
-			//determine sweep and large-arc flag
-			String sf = (a < 0) ? "1" : "0";
-			String laf = (r0 < Math.abs(a)) ? "1" : "0";
-
-			if (debug != null)
-			{
-				debug.drawLine(x0, y0, x, y, "");
-			}
-			
-			this.lastX = x;
-			this.lastY = y;
-
-			return "<" + command + 
-					" rx=\"" + String.valueOf(rx) + 
-					"\" ry=\"" + String.valueOf(ry) + 
-					"\" x=\"" + String.valueOf(x) + 
-					"\" y=\"" + String.valueOf(y) + 
-					"\" x-axis-rotation=\"0" + 
-					"\" large-arc-flag=\"" + laf + 
-					"\" sweep-flag=\"" + sf + 
-					"\"/>";
-		}
-		
-		return "";
-	}
-	
-	protected String ellipsePath(Element ellipseElem, String command)
-	{
-		Map <String, String> children = getChildValues(ellipseElem, null);
-		String xValue = children.get("X");
-		String yValue = children.get("Y");
-		String aValue = children.get("A");
-		String bValue = children.get("B");
-		String cValue = children.get("C");
-		String dValue = children.get("D");
-
-		if (xValue != null && yValue != null && aValue != null && bValue != null && cValue != null && dValue != null)
-		{
-			double h = this.getHeight();
-			double w = this.getWidth();
-			double x = Double.parseDouble(xValue) * mxVsdxUtils.conversionFactor;
-			double y = Double.parseDouble(yValue) * mxVsdxUtils.conversionFactor;
-			y = h - y;
-			double a = Double.parseDouble(aValue) * mxVsdxUtils.conversionFactor;
-			double b = Double.parseDouble(bValue) * mxVsdxUtils.conversionFactor;
-			b = h - b;
-			double c = Double.parseDouble(cValue) * mxVsdxUtils.conversionFactor;
-			double d = Double.parseDouble(dValue) * mxVsdxUtils.conversionFactor;
-			d = h - d;
-			
-			double dx1 = Math.abs(a - x);
-			double dy1 = Math.abs(b - y);
-			double r1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
-
-			double dx2 = Math.abs(c - x);
-			double dy2 = Math.abs(d - y);
-			double r2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
-			double newX = (x - r1) * 100 / w;
-			double newY = (y - r2) * 100 / h;
-			double newW = 2 * r1 * 100 / w;
-			double newH = 2 * r2 * 100 / h;
-			newH = Math.round(newH * 100.0) / 100.0;
-			newW = Math.round(newW * 100.0) / 100.0;
-			newX = Math.round(newX * 100.0) / 100.0;
-			newY = Math.round(newY * 100.0) / 100.0;
-			
-			return "<" + command + 
-					" x=\"" + String.valueOf(newX) + 
-					"\" y=\"" + String.valueOf(newY) + 
-					"\" w=\"" + String.valueOf(newW) + 
-					"\" h=\"" + String.valueOf(newH) + 
-					"\"/>";
-		}
-		
-		return "";
-	}
-	
-	protected String ellArcPath(Element ellArcElem, String command)
-	{
-		Map <String, String> children = getChildValues(ellArcElem, null);
-		String xValue = children.get("X");
-		String yValue = children.get("Y");
-		String aValue = children.get("A");
-		String bValue = children.get("B");
-		String cValue = children.get("C");
-		String dValue = children.get("D");
-		
-		if (xValue != null && yValue != null && aValue != null && bValue != null && cValue != null && dValue != null)
-		{
-			double h = this.getHeight();
-			double w = this.getWidth();
-			double x = Double.parseDouble(xValue) * mxVsdxUtils.conversionFactor;
-			double y = Double.parseDouble(yValue) * mxVsdxUtils.conversionFactor;
-			y = h - y;
-			double a = Double.parseDouble(aValue) * mxVsdxUtils.conversionFactor;
-			double b = Double.parseDouble(bValue) * mxVsdxUtils.conversionFactor;
-			double c = Double.parseDouble(cValue);
-			double d = Double.parseDouble(dValue);
-			
-			x = x * 100.0 / w;
-			y = y * 100.0 / h;
-			
-			double x1 = this.lastX * w / 100.0;
-			double y1 = this.lastY * h / 100.0;
-			
-			double x2 = x * w / 100.0;
-			double y2 = y * h / 100.0;
-			
-			double x3 = a;
-			double y3 = h - b;
-
-			double ang = -c;
-			
-			double p1x = Math.sqrt(x1 * x1 + y1 * y1) * Math.cos(Math.atan2(y1, x1) - ang);
-			double p1y = Math.sqrt(x1 * x1 + y1 * y1) * Math.sin(Math.atan2(y1, x1) - ang);
-            
-			double p2x = Math.sqrt(x2 * x2 + y2 * y2) * Math.cos(Math.atan2(y2, x2) - ang);
-			double p2y = Math.sqrt(x2 * x2 + y2 * y2) * Math.sin(Math.atan2(y2, x2) - ang);
-            
-			double p3x = Math.sqrt(x3 * x3 + y3 * y3) * Math.cos(Math.atan2(y3, x3) - ang);
-			double p3y = Math.sqrt(x3 * x3 + y3 * y3) * Math.sin(Math.atan2(y3, x3) - ang);
-			
-			double p0x = ((p1x-p2x)*(p1x+p2x)*(p2y-p3y)-(p2x-p3x)*(p2x+p3x)*(p1y-p2y)+d*d*(p1y-p2y)*(p2y-p3y)*(p1y-p3y))/(2*((p1x-p2x)*(p2y-p3y)-(p2x-p3x)*(p1y-p2y)));
-			double p0y = ((p1x-p2x)*(p2x-p3x)*(p1x-p3x)/(d*d)+(p2x-p3x)*(p1y-p2y)*(p1y+p2y)-(p1x-p2x)*(p2y-p3y)*(p2y+p3y))/(2*((p2x-p3x)*(p1y-p2y)-(p1x-p2x)*(p2y-p3y)));
-			
-			double newX = Math.sqrt(p0x * p0x + p0y * p0y) * Math.cos(Math.atan2(p0y, p0x) + ang);
-			double newY = Math.sqrt(p0x * p0x + p0y * p0y) * Math.sin(Math.atan2(p0y, p0x) + ang);
-			
-			newX = newX * w / 100.0;
-			newY = newY * h / 100.0;
-			
-			double dx = p1x - p0x;
-			double dy = p1y - p0y;
-			double rx = Math.sqrt(dx * dx + dy * dy * d * d);
-			double ry = rx / d;
-			double rot = Math.toDegrees(ang);
-			
-			rx = rx * 100.0 / w;
-			ry = ry * 100.0 / h;
-			
-			x = Math.round(x * 100.0) / 100.0;
-			y = Math.round(y * 100.0) / 100.0;
-			rx = Math.round(rx * 100.0) / 100.0;
-			ry = Math.round(ry * 100.0) / 100.0;
-			rot = Math.round(rot * 100.0) / 100.0;
-
-			//determine sweep
-			//TODO fix rare error (file "1 Supported Forms" shape "storeddata" on page 5)
-			double sweep = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1); 
-			String sf = (sweep > 0) ? "0" : "1"; 
-			
-			//determine large arc flag
-			String laf = "0";
-
-			if (mxVsdxUtils.isInsideTriangle(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) && 
-					isReflexAngle(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y))
-			{
-				laf = "1";
-			}
-			
-			if (debug != null)
-			{
-				debug.drawRect(p0x, p0y, "P0");
-				debug.drawRect(p1x, p1y, "P1");
-				debug.drawRect(p2x, p2y, "P2");
-				debug.drawRect(p3x, p3y, "P3");
-				debug.drawRect(newX, newY, "X");
-				debug.drawRect(x3, y3, "CP");
-				debug.drawLine(x1, y1, x2, y2, "");
-			}
-			
-			this.lastX = x;
-			this.lastY = y;
-			
-			return "<" + command + 
-			" rx=\"" + String.valueOf(rx) + 
-			"\" ry=\"" + String.valueOf(ry) + 
-			"\" x=\"" + String.valueOf(x) + 
-			"\" y=\"" + String.valueOf(y) + 
-			"\" x-axis-rotation=\"" + String.valueOf(rot) + 
-			"\" large-arc-flag=\"" + laf + 
-			"\" sweep-flag=\"" + sf + 
-			"\"/>";
-		}
-		
-		return "";
-	}
-
-	/**
-	 * @param x0 y0 center point of ellipse containing the arc
-	 * @param x1 y1 starting point of the arc
-	 * @param x2 y2 endpoint of the arc
-	 * @param x3 y3 control point
-	 * @return true if the start to end angle that contains the control point is a reflex angle 
-	 */
-	private boolean isReflexAngle(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3)
-	{
-		x1 = x1 - x0;
-		y1 = y1 - y0;
-		x2 = x2 - x0;
-		y2 = y2 - y0;
-		x2 = x3 - x0;
-		y3 = y3 - y0;
-		x0 = 0;
-		y0 = 0;
-
-		double aStart = Math.toDegrees(Math.atan2(y1, x1) - Math.atan2(y0, x0));
-		double aEnd = Math.toDegrees(Math.atan2(y2, x2) - Math.atan2(y0, x0));
-		double aCP = Math.toDegrees(Math.atan2(y3, x3) - Math.atan2(y0, x0));
-		
-		aStart = (aStart - aCP) % 360;
-		aEnd = (aEnd - aCP) % 360;
-
-		if (aStart > 180)
-		{
-			aStart = aStart - 360;
-		}
-		else if (aStart < -180)
-		{
-			aStart = aStart + 360;
-		}
-		
-		if (aEnd > 180)
-		{
-			aEnd = aEnd - 360;
-		}
-		else if (aEnd < -180)
-		{
-			aEnd = aEnd + 360;
-		}
-		
-		if ((aStart > 0 && aEnd < 0) || (aStart < 0 && aEnd > 0))
-		{
-			if (Math.abs(aStart - aEnd) > 180)
-			{
-				return true;
-			}
-		}
-		
-		return false;
-	}
-
-	protected String polyPath(Element polyElem, String command)
-	{
-		Map <String, String> nodeValues = new HashMap<String, String>();
-		nodeValues.put("A", "F");
-		Map <String, String> children = getChildValues(polyElem, nodeValues);
-		String xValue = children.get("X");
-		String yValue = children.get("Y");
-		String aValue = children.get("A");
-		String result = "";
-		
-		if (xValue != null && yValue != null && aValue != null)
-		{
-			double h = this.getHeight();
-			double w = this.getWidth();
-			double x = Double.parseDouble(xValue) * mxVsdxUtils.conversionFactor;
-			double y = Double.parseDouble(yValue) * mxVsdxUtils.conversionFactor;
-			x = x * 100.0 / w;
-			y = y * 100.0 / h;
-			y = 100 - y;
-			x = Math.round(x * 100.0) / 100.0;
-			y = Math.round(y * 100.0) / 100.0;
-			
-			aValue = aValue.replaceAll("\\s","").toLowerCase().replaceAll("polyline\\(","").replaceAll("\\)", "");
-			
-			LinkedList<String> polyEntriesList = new LinkedList<String>(Arrays.asList(aValue.split(",")));
-			
-			polyEntriesList.remove(0);
-			polyEntriesList.remove(0);
-			double currX = 0;
-			double currY = 0;
-
-			while (polyEntriesList.size() > 0)
-			{
-				currX = Double.valueOf(polyEntriesList.remove(0)) * mxVsdxUtils.conversionFactor;
-				currY = Double.valueOf(polyEntriesList.remove(0)) * mxVsdxUtils.conversionFactor;
-				currY = 100 - currY;
-				
-				currX = Math.round(currX * 100.0) / 100.0;
-				currY = Math.round(currY * 100.0) / 100.0;
-
-				this.lastX = currX;
-				this.lastY = currY;
-				
-				result += "<line x=\"" + String.valueOf(currX) + "\" y=\"" + String.valueOf(currY) + "\"/>";
-			}
-
-			if (this.lastMoveX == x && this.lastMoveY == y)
-			{
-				result += "<close/>";
-			}
-		}
-		
-		return result;
-	}
-
-	protected String splineStartPath(Element splineElem, String command)
-	{
-		Map <String, String> children = getChildValues(splineElem, null);
-		String xValue = children.get("X");
-		String yValue = children.get("Y");
-		String aValue = children.get("A");
-		String bValue = children.get("B");
-		String cValue = children.get("C");
-		String dValue = children.get("D");
-		String result = "";
-		
-		if (xValue != null && yValue != null && aValue != null && bValue != null && cValue != null && dValue != null)
-		{
-			double h = this.getHeight();
-			double w = this.getWidth();
-			double x = Double.parseDouble(xValue) * mxVsdxUtils.conversionFactor;
-			double y = Double.parseDouble(yValue) * mxVsdxUtils.conversionFactor;
-			//double a = Double.parseDouble(aValue);
-			//double b = Double.parseDouble(bValue);
-			double c = Double.parseDouble(cValue);
-			int d = Integer.parseInt(dValue);
-
-			//double firstKnot = b;
-			//double secondKnot = a;
-			double lastKnot = c;
-			this.lastKnot = lastKnot;
-			int degree = d;
-//				x = x * 100.0 / w;
-//				y = y * 100.0 / h;
-			y = 100 - y;
-			x = Math.round(x * 100.0) / 100.0;
-			y = Math.round(y * 100.0) / 100.0;
-			lastKnot = Math.round(lastKnot * 100.0) / 100.0;
-			double x0 = this.lastX * w / 100.0;
-			double y0 = this.lastY * h / 100.0;
-			
-			result = "<curve ";
-
-			if (debug != null)
-			{
-				debug.drawRect(x0, y0 , "0, " + Integer.toString(degree));
-				debug.drawRect(x, y , Double.toString(lastKnot));
-				debug.drawLine(x0, y0, x, y, "");
-			}
-
-			this.lastX = x;
-			this.lastY = y;
-
-		}
-		
-		return result;
-	}
-
-	protected String splinePath(Element splineElem, String command)
-	{
-		Map <String, String> children = getChildValues(splineElem, null);
-		String xValue = children.get("X");
-		String yValue = children.get("Y");
-		String aValue = children.get("A");
-		String result = "";
-		
-		if (xValue != null && yValue != null && aValue != null)
-		{
-			//double h = this.getHeight();
-			//double w = this.getWidth();
-			double x = Double.parseDouble(xValue) * mxVsdxUtils.conversionFactor;
-			double y = Double.parseDouble(yValue) * mxVsdxUtils.conversionFactor;
-			double a = Double.parseDouble(aValue);
-
-			double knot = a;
-//				x = x * 100.0 / w;
-//				y = y * 100.0 / h;
-			y = 100 - y;
-			x = Math.round(x * 100.0) / 100.0;
-			y = Math.round(y * 100.0) / 100.0;
-			knot = Math.round(knot * 100.0) / 100.0;
-			
-
-			if (debug != null)
-			{
-				debug.drawRect(x, y, Double.toString(knot));
-				debug.drawLine(this.lastX, this.lastY, x, y, "");
-			}
-			
-			this.lastX = x;
-			this.lastY = y;
-		}
-		
-		return result;
-	}
-
-	protected String nurbsPath(Element nurbsElem, String command)
-	{
-		Map <String, String> children = getChildValues(nurbsElem, null);
-		String xValue = children.get("X");
-		String yValue = children.get("Y");
-		String eValue = children.get("E");
-		String result = "";
-
-		if (xValue != null && yValue != null && eValue != null)
-		{
-			double h = this.getHeight();
-			double w = this.getWidth();
-			double x = Double.parseDouble(xValue) * mxVsdxUtils.conversionFactor;
-			double y = Double.parseDouble(yValue) * mxVsdxUtils.conversionFactor;
-			eValue = eValue.replace("NURBS(", "");
-			eValue = eValue.replace(")", "");
-			
-			List<String> nurbsValues = Arrays.asList(eValue.split("\\s*,\\s*"));
-			
-			if (nurbsValues.size() >= 10)
-			{
-				double x1 = Double.parseDouble(nurbsValues.get(4)) * 100.0;
-				double y1 = 100 - Double.parseDouble(nurbsValues.get(5)) * 100.0;
-				double x2 = Double.parseDouble(nurbsValues.get(8)) * 100.0;
-				double y2 = 100 - Double.parseDouble(nurbsValues.get(9)) * 100.0;
-	
-				y = y * 100.0 / h;
-				x = x * 100.0 / w;
-				y = 100 - y;
-				x = Math.round(x * 100.0) / 100.0;
-				y = Math.round(y * 100.0) / 100.0;
-				x1 = Math.round(x1 * 100.0) / 100.0;
-				y1 = Math.round(y1 * 100.0) / 100.0;
-				x2 = Math.round(x2 * 100.0) / 100.0;
-				y2 = Math.round(y2 * 100.0) / 100.0;
-	
-				if (debug != null)
-				{
-					debug.drawRect(x, y, "");
-					debug.drawLine(this.lastX, this.lastY, x, y, "");
-				}
-				
-				this.lastX = x;
-				this.lastY = y;
-				
-				result += "<curve x1=\"" + String.valueOf(x1) + "\" y1=\"" + String.valueOf(y1) + 
-						      "\" x2=\"" + String.valueOf(x2) + "\" y2=\"" + String.valueOf(y2) + 
-						      "\" x3=\"" + String.valueOf(x) + "\" y3=\"" + String.valueOf(y) + "\"/>";
-			}
-		}
-
-		return result;
+		return geomList.getShapeXML(this);
 	}
 
 	/**
@@ -1156,14 +459,17 @@ public class Shape extends Style
 					// edges in the center
 //					if (!masterShapeOnly || !text.equals("N"))
 //					{
-						text = textToList(text, pp);
 						// It's HTML text, so escape it.
 						text = text.replaceAll("&", "&amp;")
 								.replaceAll("\"", "&quot;")
 								.replaceAll("'", "&prime;")
 								.replaceAll("<", "&lt;")
-								.replaceAll(">", "&gt;")
-								.replaceAll("\n", "<br/>");
+								.replaceAll(">", "&gt;");
+	
+						text = textToList(text, pp);
+						
+						text = text.replaceAll("\n", "<br/>");
+						
 						ret += getTextCharFormated(text);
 //					}
 				}
@@ -1594,4 +900,44 @@ public class Shape extends Style
 	{
 		return geomList;
 	}
+
+	public double getLastX() {
+		return lastX;
+	}
+
+	public double getLastY() {
+		return lastY;
+	}
+
+	public double getLastMoveX() {
+		return lastMoveX;
+	}
+
+	public double getLastMoveY() {
+		return lastMoveY;
+	}
+
+	public double getLastKnot() {
+		return lastKnot;
+	}
+
+	public void setLastX(double lastX) {
+		this.lastX = lastX;
+	}
+
+	public void setLastY(double lastY) {
+		this.lastY = lastY;
+	}
+
+	public void setLastMoveX(double lastMoveX) {
+		this.lastMoveX = lastMoveX;
+	}
+
+	public void setLastMoveY(double lastMoveY) {
+		this.lastMoveY = lastMoveY;
+	}
+
+	public void setLastKnot(double lastKnot) {
+		this.lastKnot = lastKnot;
+	}
 }

+ 96 - 53
src/com/mxgraph/io/vsdx/VsdxShape.java

@@ -46,6 +46,8 @@ import com.mxgraph.view.mxGraph;
  */
 public class VsdxShape extends Shape
 {
+	private static final String ARROW_NO_FILL_MARKER = "0";
+
 	/**
 	 * Number of d.p. to round non-integers to
 	 */
@@ -119,11 +121,62 @@ public class VsdxShape extends Shape
 		arrowTypes = new HashMap<Integer, String>();
 		arrowTypes.put(0, mxConstants.NONE);
 		arrowTypes.put(1, mxConstants.ARROW_OPEN);
+		arrowTypes.put(2, "blockThin");
+		arrowTypes.put(3, mxConstants.ARROW_OPEN);
 		arrowTypes.put(4, mxConstants.ARROW_BLOCK);
 		arrowTypes.put(5, mxConstants.ARROW_CLASSIC);
 		arrowTypes.put(10, mxConstants.ARROW_OVAL);
 		arrowTypes.put(13, mxConstants.ARROW_BLOCK);
-
+		
+		arrowTypes.put(14, ARROW_NO_FILL_MARKER + mxConstants.ARROW_BLOCK);
+		arrowTypes.put(17, ARROW_NO_FILL_MARKER + mxConstants.ARROW_CLASSIC);
+		arrowTypes.put(20, ARROW_NO_FILL_MARKER + mxConstants.ARROW_OVAL);
+		arrowTypes.put(22, ARROW_NO_FILL_MARKER + "diamond");
+		
+		arrowTypes.put(23, "dash");
+		arrowTypes.put(24, "ERone");
+		arrowTypes.put(25, "ERmandOne");
+		arrowTypes.put(27, "ERmany");
+		arrowTypes.put(28, "ERoneToMany");
+		arrowTypes.put(29, "ERzeroToMany");
+		arrowTypes.put(30, "ERzeroToOne");
+		
+		//approximations
+		arrowTypes.put(6, mxConstants.ARROW_BLOCK);
+		arrowTypes.put(7, mxConstants.ARROW_OPEN);
+		arrowTypes.put(8, mxConstants.ARROW_CLASSIC);
+		
+		arrowTypes.put(9, "openAsync");
+		arrowTypes.put(11, "diamond");
+		
+		arrowTypes.put(12, mxConstants.ARROW_OPEN);
+		
+		arrowTypes.put(15, ARROW_NO_FILL_MARKER + mxConstants.ARROW_BLOCK);
+		arrowTypes.put(16, ARROW_NO_FILL_MARKER + mxConstants.ARROW_BLOCK);
+		arrowTypes.put(18, ARROW_NO_FILL_MARKER + mxConstants.ARROW_BLOCK);
+		arrowTypes.put(19, ARROW_NO_FILL_MARKER + mxConstants.ARROW_CLASSIC);
+		arrowTypes.put(21, ARROW_NO_FILL_MARKER + "diamond");
+		arrowTypes.put(26, "ERmandOne");
+		
+		arrowTypes.put(31, ARROW_NO_FILL_MARKER + mxConstants.ARROW_OVAL);
+		arrowTypes.put(32, ARROW_NO_FILL_MARKER + mxConstants.ARROW_OVAL);
+		arrowTypes.put(33, ARROW_NO_FILL_MARKER + mxConstants.ARROW_OVAL);
+		arrowTypes.put(34, ARROW_NO_FILL_MARKER + mxConstants.ARROW_OVAL);
+
+		arrowTypes.put(35, mxConstants.ARROW_OVAL);
+		arrowTypes.put(36, mxConstants.ARROW_OVAL);
+		arrowTypes.put(37, mxConstants.ARROW_OVAL);
+		arrowTypes.put(38, mxConstants.ARROW_OVAL);
+		
+		arrowTypes.put(39, mxConstants.ARROW_BLOCK);
+		arrowTypes.put(40, ARROW_NO_FILL_MARKER + mxConstants.ARROW_BLOCK);
+		
+		arrowTypes.put(41, ARROW_NO_FILL_MARKER + mxConstants.ARROW_OVAL);
+		arrowTypes.put(42, mxConstants.ARROW_OVAL);
+		
+		arrowTypes.put(43, mxConstants.ARROW_OPEN);
+		arrowTypes.put(44, mxConstants.ARROW_OPEN);
+		arrowTypes.put(45, mxConstants.ARROW_OPEN);
 	}
 
 	private final static Logger LOGGER = Logger.getLogger(VsdxShape.class.getName());
@@ -248,24 +301,11 @@ public class VsdxShape extends Shape
 	 */
 	public String getTextLabel()
 	{
-		Shape masterShape = null;
 		NodeList txtChildren = getTextChildren();
 
-		if (txtChildren == null && master != null)
+		if (txtChildren == null && masterShape != null)
 		{
-			if (this.getMasterId() != null)
-			{
-				masterShape = master.getMasterShape();
-			}
-			else 
-			{
-				masterShape = master.getSubShape(this.getShapeMasterId());
-			}
-			
-			if (masterShape != null)
-			{
-				txtChildren = masterShape.getTextChildren();
-			}
+			txtChildren = masterShape.getTextChildren();
 		}
 
 		if (this.htmlLabels)
@@ -423,23 +463,9 @@ public class VsdxShape extends Shape
 				{
 					value = this.fields.get(fieldIx);
 					
-					if (value == null)
+					if (value == null && masterShape != null && masterShape.fields != null)
 					{
-						Shape masterShape = null;
-	
-						if (this.getMasterId() != null)
-						{
-							masterShape = master.getMasterShape();
-						}
-						else 
-						{
-							masterShape = master.getSubShape(this.getShapeMasterId());
-						}
-						
-						if (masterShape != null && masterShape.fields != null)
-						{
-							value = masterShape.fields.get(fieldIx);
-						}
+						value = masterShape.fields.get(fieldIx);
 					}
 				}
 			}
@@ -1466,24 +1492,9 @@ public class VsdxShape extends Shape
 					return result;					
 				}
 						
-				String parsedGeom = "";
+				//Shape inherit master geometry and can change some of it or override it completely. So, no need to parse the master instead of the shape itself
+				String parsedGeom = this.parseGeom();
 
-				if (this.masterShape != null)
-				{
-					this.masterShape.debug = this.debug;
-					parsedGeom = this.masterShape.parseGeom();
-				}
-				else
-				{
-					this.styleDebug("No master shape found when looking for geom");
-				}
-				
-				if (parsedGeom.equals(""))
-				{
-					parsedGeom = this.parseGeom();
-					this.styleDebug("No master shape geom found");
-				}
-				
 				if (parsedGeom.equals(""))
 				{
 					this.styleDebug("No geom found");
@@ -1640,8 +1651,6 @@ public class VsdxShape extends Shape
 		String txtWidthF = this.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_WIDTH, "F", "");
 		String txtHeightF = this.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_HEIGHT, "F", "");
 
-		Shape masterShape = master != null ? master.getMasterShape() : null;
-
 		if (masterShape != null)
 		{
 			if (txtPinXF == "" || txtPinXF.toLowerCase().equals("inh"))
@@ -1694,8 +1703,6 @@ public class VsdxShape extends Shape
 	{
 		String txtAngleValue = this.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_ANGLE, "V", "");
 
-		Shape masterShape = master != null ? master.getMasterShape() : null;
-
 		if (masterShape != null)
 		{
 			if (txtAngleValue.equals(""))
@@ -1881,6 +1888,11 @@ public class VsdxShape extends Shape
 
 		if(startArrow != null)
 		{
+			if (startArrow.startsWith(ARROW_NO_FILL_MARKER))
+			{
+				startArrow = startArrow.substring(ARROW_NO_FILL_MARKER.length());
+				styleMap.put(mxConstants.STYLE_STARTFILL, "0");
+			}
 			styleMap.put(mxConstants.STYLE_STARTARROW, startArrow);
 		}
 
@@ -1889,6 +1901,11 @@ public class VsdxShape extends Shape
 
 		if(endArrow != null)
 		{
+			if (endArrow.startsWith(ARROW_NO_FILL_MARKER))
+			{
+				endArrow = endArrow.substring(ARROW_NO_FILL_MARKER.length());
+				styleMap.put(mxConstants.STYLE_ENDFILL, "0");
+			}
 			styleMap.put(mxConstants.STYLE_ENDARROW, endArrow);
 		}
 
@@ -2032,6 +2049,7 @@ public class VsdxShape extends Shape
 			//if arrow  head type is not supported, use the open arrow instead
 			type = VsdxShape.arrowTypes.get(1);
 		}
+		
 		return type;
 	}
 	
@@ -2126,4 +2144,29 @@ public class VsdxShape extends Shape
 
 		return null;
 	}
+
+	public mxPoint getLblEdgeOffset(mxPoint beginXY, mxPoint endXY, List<mxPoint> points) 
+	{
+		//currently, edges with multiple segments are not supported
+		//TODO use the code from https://github.com/jgraph/mxgraph/blob/master/javascript/src/js/view/mxGraphView.js#L1953 to calculate mxGraph label offset instead of the default mid point (width/2, height/2)
+		if (points == null || points.isEmpty() || (points.size() == 1 && points.get(0).equals(endXY)))
+		{
+	        //Calculate the text offset
+	        double txtWV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_WIDTH), getWidth());
+	        double txtHV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_HEIGHT), getHeight());
+	        double txtLocPinXV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_LOC_PIN_X), 0);
+	        double txtLocPinYV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_LOC_PIN_Y), 0);
+	        double txtPinXV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_PIN_X), 0);
+	        double txtPinYV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_PIN_Y), 0);
+	
+			double y = getHeight()/2 - (txtPinYV - txtLocPinYV + txtHV/2);
+			double x = txtPinXV - txtLocPinXV + txtWV/2 - getWidth()/2;
+	
+	        return new mxPoint(x, y);
+		}
+		else
+		{
+			return null;
+		}
+	}
 }

+ 62 - 1
src/com/mxgraph/io/vsdx/geometry/ArcTo.java

@@ -1,5 +1,9 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.io.vsdx.mxVsdxUtils;
+import com.mxgraph.util.mxPoint;
+
 public class ArcTo extends Row 
 {
 	public ArcTo(int index, Double x, Double y, Double a) 
@@ -9,9 +13,66 @@ public class ArcTo extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
+		if (this.x != null && this.y != null && this.a != null)
+		{
+			double h = shape.getHeight();
+			double w = shape.getWidth();
+			double x0 = Math.round(shape.getLastX() * w) / 100;
+			double y0 = Math.round(shape.getLastX() * h) / 100;
+			double x = this.x * mxVsdxUtils.conversionFactor;
+			
+			double y = this.y * mxVsdxUtils.conversionFactor;
+			y = h - y;
+			
+			double a = this.a * mxVsdxUtils.conversionFactor;
+
+			double dx = Math.abs(x - x0);
+			double dy = Math.abs(y - y0);
+
+			double rx = (a * 0.5) + (dx * dx + dy * dy) / (8.0 * a);
+			double ry = rx;
+			double r0 = Math.abs(rx);
+			
+			rx = rx * 100 / w;
+			ry = ry * 100 / h;
+			x = x * 100 / w;
+			y = y * 100 / h;
+			rx = Math.round(rx * 100.0) / 100.0;
+			ry = Math.round(ry * 100.0) / 100.0;
+			x = Math.round(x * 100.0) / 100.0;
+			y = Math.round(y * 100.0) / 100.0;
+
+			a = Math.round(a * 100.0) / 100.0;
+			rx = Math.abs(rx);
+			ry = Math.abs(ry);
+			
+			//determine sweep and large-arc flag
+			String sf = (a < 0) ? "1" : "0";
+			String laf = (r0 < Math.abs(a)) ? "1" : "0";
+
+			if (debug != null)
+			{
+				debug.drawLine(x0, y0, x, y, "");
+			}
+			
+			shape.setLastX(x);
+			shape.setLastY(y);
+
+			return "<arc" +
+					" rx=\"" + String.valueOf(rx) + 
+					"\" ry=\"" + String.valueOf(ry) + 
+					"\" x=\"" + String.valueOf(x) + 
+					"\" y=\"" + String.valueOf(y) + 
+					"\" x-axis-rotation=\"0" + 
+					"\" large-arc-flag=\"" + laf + 
+					"\" sweep-flag=\"" + sf + 
+					"\"/>";
+		}
 		
+		return "";
+
 	}
 
 }

+ 6 - 1
src/com/mxgraph/io/vsdx/geometry/DelRow.java

@@ -1,5 +1,8 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.util.mxPoint;
+
 public class DelRow extends Row{
 
 	public DelRow(int index) {
@@ -7,8 +10,10 @@ public class DelRow extends Row{
 	}
 
 	@Override
-	public void handle() {
+	public String handle(mxPoint p, Shape shape)
+	{
 		//Nothing
+		return "";
 	}
 
 }

+ 44 - 1
src/com/mxgraph/io/vsdx/geometry/Ellipse.java

@@ -1,5 +1,9 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.io.vsdx.mxVsdxUtils;
+import com.mxgraph.util.mxPoint;
+
 public class Ellipse extends Row 
 {
 	public Ellipse(int index, Double x, Double y, Double a, Double b, Double c, Double d) 
@@ -12,9 +16,48 @@ public class Ellipse extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
+		if (this.x != null && this.y != null && this.a != null && this.b != null && this.c != null && this.d != null)
+		{
+			double h = shape.getHeight();
+			double w = shape.getWidth();
+
+			double x = this.x * mxVsdxUtils.conversionFactor;
+			double y = this.y * mxVsdxUtils.conversionFactor;
+			y = h - y;
+			double a = this.a * mxVsdxUtils.conversionFactor;
+			double b = this.b * mxVsdxUtils.conversionFactor;
+			b = h - b;
+			double c = this.c * mxVsdxUtils.conversionFactor;
+			double d = this.d * mxVsdxUtils.conversionFactor;
+			d = h - d;
+			
+			double dx1 = Math.abs(a - x);
+			double dy1 = Math.abs(b - y);
+			double r1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
+
+			double dx2 = Math.abs(c - x);
+			double dy2 = Math.abs(d - y);
+			double r2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
+			double newX = (x - r1) * 100 / w;
+			double newY = (y - r2) * 100 / h;
+			double newW = 2 * r1 * 100 / w;
+			double newH = 2 * r2 * 100 / h;
+			newH = Math.round(newH * 100.0) / 100.0;
+			newW = Math.round(newW * 100.0) / 100.0;
+			newX = Math.round(newX * 100.0) / 100.0;
+			newY = Math.round(newY * 100.0) / 100.0;
+			
+			return "<ellipse" + 
+					" x=\"" + String.valueOf(newX) + 
+					"\" y=\"" + String.valueOf(newY) + 
+					"\" w=\"" + String.valueOf(newW) + 
+					"\" h=\"" + String.valueOf(newH) + 
+					"\"/>";
+		}
 		
+		return "";
 	}
 
 }

+ 158 - 1
src/com/mxgraph/io/vsdx/geometry/EllipticalArcTo.java

@@ -1,5 +1,9 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.io.vsdx.mxVsdxUtils;
+import com.mxgraph.util.mxPoint;
+
 public class EllipticalArcTo extends Row 
 {
 	public EllipticalArcTo(int index, Double x, Double y, Double a, Double b, Double c, Double d) 
@@ -12,9 +16,162 @@ public class EllipticalArcTo extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
+		if (this.x != null && this.y != null && this.a != null && this.b != null && this.c != null && this.d != null)
+		{
+			double h = shape.getHeight();
+			double w = shape.getWidth();
+
+			double x = this.x * mxVsdxUtils.conversionFactor;
+			double y = this.y * mxVsdxUtils.conversionFactor;
+			y = h - y;
+			double a = this.a * mxVsdxUtils.conversionFactor;
+			double b = this.b * mxVsdxUtils.conversionFactor;
+			double c = this.c;
+			double d = this.d;
+
+			x = x * 100.0 / w;
+			y = y * 100.0 / h;
+			
+			double x1 = shape.getLastX() * w / 100.0;
+			double y1 = shape.getLastY() * h / 100.0;
+			
+			double x2 = x * w / 100.0;
+			double y2 = y * h / 100.0;
+			
+			double x3 = a;
+			double y3 = h - b;
+
+			double ang = -c;
+			
+			double p1x = Math.sqrt(x1 * x1 + y1 * y1) * Math.cos(Math.atan2(y1, x1) - ang);
+			double p1y = Math.sqrt(x1 * x1 + y1 * y1) * Math.sin(Math.atan2(y1, x1) - ang);
+            
+			double p2x = Math.sqrt(x2 * x2 + y2 * y2) * Math.cos(Math.atan2(y2, x2) - ang);
+			double p2y = Math.sqrt(x2 * x2 + y2 * y2) * Math.sin(Math.atan2(y2, x2) - ang);
+            
+			double p3x = Math.sqrt(x3 * x3 + y3 * y3) * Math.cos(Math.atan2(y3, x3) - ang);
+			double p3y = Math.sqrt(x3 * x3 + y3 * y3) * Math.sin(Math.atan2(y3, x3) - ang);
+			
+			double p0x = ((p1x-p2x)*(p1x+p2x)*(p2y-p3y)-(p2x-p3x)*(p2x+p3x)*(p1y-p2y)+d*d*(p1y-p2y)*(p2y-p3y)*(p1y-p3y))/(2*((p1x-p2x)*(p2y-p3y)-(p2x-p3x)*(p1y-p2y)));
+			double p0y = ((p1x-p2x)*(p2x-p3x)*(p1x-p3x)/(d*d)+(p2x-p3x)*(p1y-p2y)*(p1y+p2y)-(p1x-p2x)*(p2y-p3y)*(p2y+p3y))/(2*((p2x-p3x)*(p1y-p2y)-(p1x-p2x)*(p2y-p3y)));
+			
+			double newX = Math.sqrt(p0x * p0x + p0y * p0y) * Math.cos(Math.atan2(p0y, p0x) + ang);
+			double newY = Math.sqrt(p0x * p0x + p0y * p0y) * Math.sin(Math.atan2(p0y, p0x) + ang);
+			
+			newX = newX * w / 100.0;
+			newY = newY * h / 100.0;
+			
+			double dx = p1x - p0x;
+			double dy = p1y - p0y;
+			double rx = Math.sqrt(dx * dx + dy * dy * d * d);
+			double ry = rx / d;
+			double rot = Math.toDegrees(ang);
+			
+			rx = rx * 100.0 / w;
+			ry = ry * 100.0 / h;
+			
+			x = Math.round(x * 100.0) / 100.0;
+			y = Math.round(y * 100.0) / 100.0;
+			rx = Math.round(rx * 100.0) / 100.0;
+			ry = Math.round(ry * 100.0) / 100.0;
+			rot = Math.round(rot * 100.0) / 100.0;
+
+			//determine sweep
+			//TODO fix rare error (file "1 Supported Forms" shape "storeddata" on page 5)
+			double sweep = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1); 
+			String sf = (sweep > 0) ? "0" : "1"; 
+			
+			//determine large arc flag
+			String laf = "0";
+
+			if (mxVsdxUtils.isInsideTriangle(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) && 
+					isReflexAngle(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y))
+			{
+				laf = "1";
+			}
+			
+			if (debug != null)
+			{
+				debug.drawRect(p0x, p0y, "P0");
+				debug.drawRect(p1x, p1y, "P1");
+				debug.drawRect(p2x, p2y, "P2");
+				debug.drawRect(p3x, p3y, "P3");
+				debug.drawRect(newX, newY, "X");
+				debug.drawRect(x3, y3, "CP");
+				debug.drawLine(x1, y1, x2, y2, "");
+			}
+			
+			shape.setLastX(x);
+			shape.setLastY(y);
+			
+			return "<arc" + 
+			" rx=\"" + String.valueOf(rx) + 
+			"\" ry=\"" + String.valueOf(ry) + 
+			"\" x=\"" + String.valueOf(x) + 
+			"\" y=\"" + String.valueOf(y) + 
+			"\" x-axis-rotation=\"" + String.valueOf(rot) + 
+			"\" large-arc-flag=\"" + laf + 
+			"\" sweep-flag=\"" + sf + 
+			"\"/>";
+		}
+		
+		return "";
+	}
+
+	/**
+	 * @param x0 y0 center point of ellipse containing the arc
+	 * @param x1 y1 starting point of the arc
+	 * @param x2 y2 endpoint of the arc
+	 * @param x3 y3 control point
+	 * @return true if the start to end angle that contains the control point is a reflex angle 
+	 */
+	private boolean isReflexAngle(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3)
+	{
+		x1 = x1 - x0;
+		y1 = y1 - y0;
+		x2 = x2 - x0;
+		y2 = y2 - y0;
+		x2 = x3 - x0;
+		y3 = y3 - y0;
+		x0 = 0;
+		y0 = 0;
+
+		double aStart = Math.toDegrees(Math.atan2(y1, x1) - Math.atan2(y0, x0));
+		double aEnd = Math.toDegrees(Math.atan2(y2, x2) - Math.atan2(y0, x0));
+		double aCP = Math.toDegrees(Math.atan2(y3, x3) - Math.atan2(y0, x0));
+		
+		aStart = (aStart - aCP) % 360;
+		aEnd = (aEnd - aCP) % 360;
+
+		if (aStart > 180)
+		{
+			aStart = aStart - 360;
+		}
+		else if (aStart < -180)
+		{
+			aStart = aStart + 360;
+		}
+		
+		if (aEnd > 180)
+		{
+			aEnd = aEnd - 360;
+		}
+		else if (aEnd < -180)
+		{
+			aEnd = aEnd + 360;
+		}
+		
+		if ((aStart > 0 && aEnd < 0) || (aStart < 0 && aEnd > 0))
+		{
+			if (Math.abs(aStart - aEnd) > 180)
+			{
+				return true;
+			}
+		}
 		
+		return false;
 	}
 
 }

+ 6 - 2
src/com/mxgraph/io/vsdx/geometry/InfiniteLine.java

@@ -1,5 +1,8 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.util.mxPoint;
+
 public class InfiniteLine extends Row 
 {
 	public InfiniteLine(int index, Double x, Double y, Double a, Double b) 
@@ -10,9 +13,10 @@ public class InfiniteLine extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
-		
+		//TODO implement this!
+		return "";
 	}
 
 }

+ 27 - 1
src/com/mxgraph/io/vsdx/geometry/LineTo.java

@@ -1,5 +1,9 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.io.vsdx.mxVsdxUtils;
+import com.mxgraph.util.mxPoint;
+
 public class LineTo extends Row 
 {
 
@@ -9,9 +13,31 @@ public class LineTo extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
+		double x = p.getX(), y = p.getY();
+		double h = shape.getHeight();
+		double w = shape.getWidth();
+
+		if (this.x != null && this.y != null)
+		{
+			x = this.x * mxVsdxUtils.conversionFactor;
+			y = this.y * mxVsdxUtils.conversionFactor;
+		}			
+
+		x = x * 100.0 / w;
+		y = y * 100.0 / h;
+		y = 100 - y;
+
+		x = Math.round(x * 100.0) / 100.0;
+		y = Math.round(y * 100.0) / 100.0;
 		
+		p.setX(x);
+		p.setY(y);
+		shape.setLastX(x);
+		shape.setLastY(y);
+
+		return "<" + "line" + " x=\"" + String.valueOf(x) + "\" y=\"" + String.valueOf(y) + "\"/>";
 	}
 
 }

+ 29 - 1
src/com/mxgraph/io/vsdx/geometry/MoveTo.java

@@ -1,5 +1,9 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.io.vsdx.mxVsdxUtils;
+import com.mxgraph.util.mxPoint;
+
 public class MoveTo extends Row 
 {
 	public MoveTo(int index, Double x, Double y) 
@@ -8,8 +12,32 @@ public class MoveTo extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
+		double x = p.getX(), y = p.getY();
+		double h = shape.getHeight();
+		double w = shape.getWidth();
+
+		if (this.x != null && this.y != null)
+		{
+			x = this.x * mxVsdxUtils.conversionFactor;
+			y = this.y * mxVsdxUtils.conversionFactor;
+		}
 		
+		x = x * 100.0 / w;
+		y = y * 100.0 / h;
+		y = 100 - y;
+
+		x = Math.round(x * 100.0) / 100.0;
+		y = Math.round(y * 100.0) / 100.0;
+		
+		p.setX(x);
+		p.setY(y);
+		shape.setLastX(x);
+		shape.setLastY(y);
+		shape.setLastMoveX(x);
+		shape.setLastMoveY(y);
+
+		return "<" + "move" + " x=\"" + String.valueOf(x) + "\" y=\"" + String.valueOf(y) + "\"/>";
 	}
 }

+ 54 - 2
src/com/mxgraph/io/vsdx/geometry/NURBSTo.java

@@ -1,5 +1,12 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import java.util.Arrays;
+import java.util.List;
+
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.io.vsdx.mxVsdxUtils;
+import com.mxgraph.util.mxPoint;
+
 public class NURBSTo extends Row 
 {
 	public NURBSTo(int index, Double x, Double y, Double a, Double b, Double c, Double d, String e) 
@@ -13,9 +20,54 @@ public class NURBSTo extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
-		
+		if (this.x != null && this.y != null && this.formulaE != null)
+		{
+			double h = shape.getHeight();
+			double w = shape.getWidth();
+
+			double x = this.x * mxVsdxUtils.conversionFactor;
+			double y = this.y * mxVsdxUtils.conversionFactor;
+			String eValue = this.formulaE.replace("NURBS(", "");
+			eValue = eValue.replace(")", "");
+			
+			List<String> nurbsValues = Arrays.asList(eValue.split("\\s*,\\s*"));
+			
+			if (nurbsValues.size() >= 10)
+			{
+				double x1 = Double.parseDouble(nurbsValues.get(4)) * 100.0;
+				double y1 = 100 - Double.parseDouble(nurbsValues.get(5)) * 100.0;
+				double x2 = Double.parseDouble(nurbsValues.get(8)) * 100.0;
+				double y2 = 100 - Double.parseDouble(nurbsValues.get(9)) * 100.0;
+	
+				y = y * 100.0 / h;
+				x = x * 100.0 / w;
+				y = 100 - y;
+				x = Math.round(x * 100.0) / 100.0;
+				y = Math.round(y * 100.0) / 100.0;
+				x1 = Math.round(x1 * 100.0) / 100.0;
+				y1 = Math.round(y1 * 100.0) / 100.0;
+				x2 = Math.round(x2 * 100.0) / 100.0;
+				y2 = Math.round(y2 * 100.0) / 100.0;
+	
+				if (debug != null)
+				{
+					debug.drawRect(x, y, "");
+					debug.drawLine(shape.getLastX(), shape.getLastY(), x, y, "");
+				}
+				
+				shape.setLastX(x);
+				shape.setLastY(y);
+			
+				return "<curve x1=\"" + String.valueOf(x1) + "\" y1=\"" + String.valueOf(y1) + 
+						      "\" x2=\"" + String.valueOf(x2) + "\" y2=\"" + String.valueOf(y2) + 
+						      "\" x3=\"" + String.valueOf(x) + "\" y3=\"" + String.valueOf(y) + "\"/>";
+			}
+		}
+
+		return "";
+
 	}
 
 }

+ 53 - 1
src/com/mxgraph/io/vsdx/geometry/PolylineTo.java

@@ -1,5 +1,12 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import java.util.Arrays;
+import java.util.LinkedList;
+
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.io.vsdx.mxVsdxUtils;
+import com.mxgraph.util.mxPoint;
+
 public class PolylineTo extends Row 
 {
 	public PolylineTo(int index, Double x, Double y, String a) 
@@ -9,9 +16,54 @@ public class PolylineTo extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
+		String result = "";
+		
+		if (this.x != null && this.y != null && this.formulaA != null)
+		{
+			double h = shape.getHeight();
+			double w = shape.getWidth();
+			double x = this.x * mxVsdxUtils.conversionFactor;
+			double y = this.y * mxVsdxUtils.conversionFactor;
+			x = x * 100.0 / w;
+			y = y * 100.0 / h;
+			y = 100 - y;
+			x = Math.round(x * 100.0) / 100.0;
+			y = Math.round(y * 100.0) / 100.0;
+			
+			String aValue = this.formulaA.replaceAll("\\s","").toLowerCase().replaceAll("polyline\\(","").replaceAll("\\)", "");
+			
+			LinkedList<String> polyEntriesList = new LinkedList<String>(Arrays.asList(aValue.split(",")));
+			
+			polyEntriesList.remove(0);
+			polyEntriesList.remove(0);
+			double currX = 0;
+			double currY = 0;
+
+			while (polyEntriesList.size() > 0)
+			{
+				currX = Double.valueOf(polyEntriesList.remove(0)) * mxVsdxUtils.conversionFactor;
+				currY = Double.valueOf(polyEntriesList.remove(0)) * mxVsdxUtils.conversionFactor;
+				currY = 100 - currY;
+				
+				currX = Math.round(currX * 100.0) / 100.0;
+				currY = Math.round(currY * 100.0) / 100.0;
+
+				shape.setLastX(currX);
+				shape.setLastY(currY);
+
+				result += "<line x=\"" + String.valueOf(currX) + "\" y=\"" + String.valueOf(currY) + "\"/>";
+			}
+
+			if (shape.getLastMoveX() == x && shape.getLastMoveY() == y)
+			{
+				result += "<close/>";
+			}
+		}
 		
+		return result;
+
 	}
 
 }

+ 6 - 2
src/com/mxgraph/io/vsdx/geometry/RelCubBezTo.java

@@ -1,5 +1,8 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.util.mxPoint;
+
 public class RelCubBezTo extends Row 
 {
 	public RelCubBezTo(int index, Double x, Double y, Double a, Double b, Double c, Double d) 
@@ -12,9 +15,10 @@ public class RelCubBezTo extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
-		
+		//TODO implement this!
+		return "";
 	}
 
 }

+ 6 - 2
src/com/mxgraph/io/vsdx/geometry/RelEllipticalArcTo.java

@@ -1,5 +1,8 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.util.mxPoint;
+
 public class RelEllipticalArcTo extends Row 
 {
 	public RelEllipticalArcTo(int index, Double x, Double y, Double a, Double b, Double c, Double d) 
@@ -12,9 +15,10 @@ public class RelEllipticalArcTo extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
-		
+		//TODO implement this!
+		return "";
 	}
 
 }

+ 20 - 1
src/com/mxgraph/io/vsdx/geometry/RelLineTo.java

@@ -1,5 +1,8 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.util.mxPoint;
+
 public class RelLineTo extends Row 
 {
 
@@ -9,9 +12,25 @@ public class RelLineTo extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
+		double x = p.getX(), y = p.getY();
+		
+		if (this.x != null && this.y != null)
+		{
+			x = this.x * 100;
+			y = 100 - this.y * 100;
+		}
 		
+		x = Math.round(x * 100.0) / 100.0;
+		y = Math.round(y * 100.0) / 100.0;
+		
+		p.setX(x);
+		p.setY(y);
+		shape.setLastX(x);
+		shape.setLastY(y);
+
+		return "<" + "line" + " x=\"" + String.valueOf(x) + "\" y=\"" + String.valueOf(y) + "\"/>";
 	}
 
 }

+ 22 - 1
src/com/mxgraph/io/vsdx/geometry/RelMoveTo.java

@@ -1,5 +1,8 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.util.mxPoint;
+
 public class RelMoveTo extends Row 
 {
 
@@ -9,9 +12,27 @@ public class RelMoveTo extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
+		double x = p.getX(), y = p.getY();
+		
+		if (this.x != null && this.y != null)
+		{
+			x = this.x * 100;
+			y = 100 - this.y * 100;
+		}
 		
+		x = Math.round(x * 100.0) / 100.0;
+		y = Math.round(y * 100.0) / 100.0;
+		
+		p.setX(x);
+		p.setY(y);
+		shape.setLastX(x);
+		shape.setLastY(y);
+		shape.setLastMoveX(x);
+		shape.setLastMoveY(y);
+
+		return "<" + "move" + " x=\"" + String.valueOf(x) + "\" y=\"" + String.valueOf(y) + "\"/>";
 	}
 
 }

+ 6 - 2
src/com/mxgraph/io/vsdx/geometry/RelQuadBezTo.java

@@ -1,5 +1,8 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.util.mxPoint;
+
 public class RelQuadBezTo extends Row 
 {
 	public RelQuadBezTo(int index, Double x, Double y, Double a, Double b)
@@ -10,9 +13,10 @@ public class RelQuadBezTo extends Row
 	}
 
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
-		
+		//TODO implement this!
+		return "";
 	}
 
 }

+ 8 - 1
src/com/mxgraph/io/vsdx/geometry/Row.java

@@ -1,11 +1,17 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.io.vsdx.mxPathDebug;
+import com.mxgraph.util.mxPoint;
+
 public abstract class Row 
 {
 	protected Double x, y, a, b, c, d;
 	protected String formulaA, formulaE; 
 	protected int index;
 	
+	public mxPathDebug debug = null;
+	
 	public Row(int index, Double x, Double y) 
 	{
 		this.index = index;
@@ -13,7 +19,8 @@ public abstract class Row
 		this.y = y;
 	}
 
-	public abstract void handle();
+	//TODO probably point p is not needed as the point from previous step is stored in lastP?
+	public abstract String handle(mxPoint p, Shape shape);
 
 	public Double getX() 
 	{

+ 16 - 41
src/com/mxgraph/io/vsdx/geometry/RowFactory.java

@@ -40,7 +40,20 @@ public class RowFactory
 			}
 			
 			Double x = null, y = null, a = null, b = null, c = null, d = null;
-			String formulaE = null, formulaA = null;;
+			String formulaE = null, formulaA = null;
+			
+			if (parentObj != null)
+			{
+				x = parentObj.getX();
+				y = parentObj.getY();
+				a = parentObj.getA();
+				b = parentObj.getB();
+				c = parentObj.getC();
+				d = parentObj.getD();
+				formulaA = parentObj.getFormulaA();
+				formulaE = parentObj.getFormulaE();
+			}
+			
 			ArrayList<Element> cells = mxVsdxUtils.getDirectChildElements(elem);
 			
 			for (Element cell : cells)
@@ -52,64 +65,26 @@ public class RowFactory
 				{
 					case "X":
 						x = getDoubleVal(val);
-						
-						if (x == null && parentObj != null) 
-						{
-							x = parentObj.getX();
-						}
 					break;
 					case "Y":
 						y = getDoubleVal(val);
-
-						if (y == null && parentObj != null) 
-						{
-							y = parentObj.getY();
-						}
 					break;
 					case "A":
 						a = getDoubleVal(val);
-						formulaA = val;
-
-						if (a == null && parentObj != null) 
-						{
-							a = parentObj.getA();
-						}
-						if (formulaA == null && parentObj != null) 
-						{
-							formulaA = parentObj.getFormulaA();
-						}
+						//Special case for PolylineTo where we need the F attribute instead of V
+						formulaA = cell.getAttribute("F");
 					break;
 					case "B":
 						b = getDoubleVal(val);
-						
-						if (b == null && parentObj != null) 
-						{
-							b = parentObj.getB();
-						}
 					break;
 					case "C":
 						c = getDoubleVal(val);
-
-						if (c == null && parentObj != null) 
-						{
-							c = parentObj.getC();
-						}
 					break;
 					case "D":
 						d = getDoubleVal(val);
-						
-						if (d == null && parentObj != null) 
-						{
-							d = parentObj.getD();
-						}
 					break;
 					case "E":
 						formulaE = val;
-						
-						if (formulaE == null && parentObj != null) 
-						{
-							formulaE = parentObj.getFormulaE();
-						}
 					break;
 				}
 			}

+ 34 - 1
src/com/mxgraph/io/vsdx/geometry/SplineKnot.java

@@ -1,5 +1,9 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.io.vsdx.mxVsdxUtils;
+import com.mxgraph.util.mxPoint;
+
 public class SplineKnot extends Row 
 {
 	public SplineKnot(int index, Double x, Double y, Double a)
@@ -8,10 +12,39 @@ public class SplineKnot extends Row
 		this.a = a;
 	}
 
+	//TODO Is this complete?
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
+		if (this.x != null && this.y != null && this.a != null)
+		{
+			//double h = this.getHeight();
+			//double w = this.getWidth();
+			double x = this.x * mxVsdxUtils.conversionFactor;
+			double y = this.y * mxVsdxUtils.conversionFactor;
+			double a = this.a;
+
+			double knot = a;
+//				x = x * 100.0 / w;
+//				y = y * 100.0 / h;
+			y = 100 - y;
+			x = Math.round(x * 100.0) / 100.0;
+			y = Math.round(y * 100.0) / 100.0;
+			knot = Math.round(knot * 100.0) / 100.0;
+			
+
+			if (debug != null)
+			{
+				debug.drawRect(x, y, Double.toString(knot));
+				debug.drawLine(shape.getLastX(), shape.getLastY(), x, y, "");
+			}
+			
+			shape.setLastX(x);
+			shape.setLastY(y);
+		}
 		
+		return "";
+
 	}
 
 }

+ 48 - 1
src/com/mxgraph/io/vsdx/geometry/SplineStart.java

@@ -1,5 +1,9 @@
 package com.mxgraph.io.vsdx.geometry;
 
+import com.mxgraph.io.vsdx.Shape;
+import com.mxgraph.io.vsdx.mxVsdxUtils;
+import com.mxgraph.util.mxPoint;
+
 public class SplineStart extends Row 
 {
 	public SplineStart(int index, Double x, Double y, Double a, Double b, Double c, Double d) 
@@ -11,10 +15,53 @@ public class SplineStart extends Row
 		this.d = d;
 	}
 
+	//TODO Is this complete?
 	@Override
-	public void handle() 
+	public String handle(mxPoint p, Shape shape)
 	{
+		if (this.x != null && this.y != null && this.a != null && this.b != null && this.c != null && this.d != null)
+		{
+			double h = shape.getHeight();
+			double w = shape.getWidth();
+
+			double x = this.x * mxVsdxUtils.conversionFactor;
+			double y = this.y * mxVsdxUtils.conversionFactor;
+			//double a = Double.parseDouble(aValue);
+			//double b = Double.parseDouble(bValue);
+			double c = this.c;
+			int d = this.d.intValue();
+
+			//double firstKnot = b;
+			//double secondKnot = a;
+			double lastKnot = c;
+			
+			shape.setLastKnot(lastKnot);
+			
+			int degree = d;
+//				x = x * 100.0 / w;
+//				y = y * 100.0 / h;
+			y = 100 - y;
+			x = Math.round(x * 100.0) / 100.0;
+			y = Math.round(y * 100.0) / 100.0;
+			lastKnot = Math.round(lastKnot * 100.0) / 100.0;
+			double x0 = shape.getLastX() * w / 100.0;
+			double y0 = shape.getLastY() * h / 100.0;
+			
+			if (debug != null)
+			{
+				debug.drawRect(x0, y0 , "0, " + Integer.toString(degree));
+				debug.drawRect(x, y , Double.toString(lastKnot));
+				debug.drawLine(x0, y0, x, y, "");
+			}
+
+			shape.setLastX(x);
+			shape.setLastY(y);
+
+			return "<curve ";
+		}
 		
+		return "";
+
 	}
 
 }

+ 35 - 0
src/com/mxgraph/io/vsdx/mxVsdxGeometry.java

@@ -9,6 +9,7 @@ import org.w3c.dom.Element;
 
 import com.mxgraph.io.vsdx.geometry.Row;
 import com.mxgraph.io.vsdx.geometry.RowFactory;
+import com.mxgraph.util.mxPoint;
 
 public class mxVsdxGeometry {
 	private int index;
@@ -152,4 +153,38 @@ public class mxVsdxGeometry {
 		return rows;
 	}
 
+	public String getPathXML(mxPoint p, Shape shape)
+	{
+		if (noShow) return "";
+		
+		StringBuilder geomElemParsed = new StringBuilder("<path>");
+		int initSize = geomElemParsed.length();
+		
+		for (Row row : rows)
+		{
+			geomElemParsed.append(row.handle(p, shape));
+		}
+
+		if (geomElemParsed.length() > initSize)
+		{
+			geomElemParsed.append("</path>");
+			
+			if (!noLine && !noFill)
+			{
+				geomElemParsed.append("<fillstroke/>");
+			}
+			else if (!noFill)
+			{
+				geomElemParsed.append("<fill/>");
+			}
+			else if (!noLine)
+			{
+				geomElemParsed.append("<stroke/>");
+			}
+			
+			return geomElemParsed.toString();
+		}
+		
+		return "";
+	}
 }

+ 26 - 0
src/com/mxgraph/io/vsdx/mxVsdxGeometryList.java

@@ -109,6 +109,9 @@ public class mxVsdxGeometryList
 		
 		List<mxPoint> points = new ArrayList<mxPoint>();
 		
+		//Adding the starting point as a routing point instead of setting the entryX/Y
+		points.add(startPoint);
+		
 		double offsetX = 0;
 		double offsetY = 0;
 		
@@ -157,4 +160,27 @@ public class mxVsdxGeometryList
 		return points;
 	}
 
+	public String getShapeXML(Shape shape)
+	{
+		mxPoint p = new mxPoint(0, 0);
+
+		StringBuilder parsedGeom = new StringBuilder("<shape strokewidth=\"inherit\"><foreground>");
+		int initSize = parsedGeom.length();
+		
+		for (mxVsdxGeometry geo : geomList)
+		{
+			parsedGeom.append(geo.getPathXML(p, shape));
+		}
+
+		if (parsedGeom.length() == initSize)
+		{
+			return "";
+		}
+		
+		//System.out.println(parsedGeom);
+		
+		parsedGeom.append("</foreground></shape>");
+		return parsedGeom.toString();
+	}
+	
 }

+ 1 - 1
war/WEB-INF/appengine-web.xml

@@ -2,7 +2,7 @@
 <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
 	<application>drawdotio</application>
 	<!-- IMPORTANT! DO NOT CHANGE THIS VALUE IN SOURCE CONTROL! -->
-	<version>6-4-6</version>
+	<version>test</version>
 	
 	<!-- Configure java.util.logging -->
 	<system-properties>

BIN
war/WEB-INF/lib/datanucleus-appengine-1.0.10.final.jar


BIN
war/WEB-INF/lib/datanucleus-core-1.1.5.jar


BIN
war/WEB-INF/lib/datanucleus-jpa-1.1.5.jar


BIN
war/WEB-INF/lib/geronimo-jpa_3.0_spec-1.1.1.jar


BIN
war/WEB-INF/lib/geronimo-jta_1.1_spec-1.1.1.jar


BIN
war/WEB-INF/lib/jdo2-api-2.3-eb.jar


+ 1 - 1
war/cache.manifest

@@ -1,7 +1,7 @@
 CACHE MANIFEST
 
 # THIS FILE WAS GENERATED. DO NOT MODIFY!
-# 04/06/2017 12:53 AM
+# 04/13/2017 03:09 PM
 
 app.html
 index.html?offline=1

+ 0 - 236
war/export.html

@@ -1,236 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-	<script>
-		var mathJaxQueue = [];
-		
-		// Disables global typesetting and messages on startup, adds queue for
-		// asynchronous rendering while MathJax is loading
-		window.MathJax =
-		{
-			skipStartupTypeset: true,
-			messageStyle: 'none',
-			AuthorInit: function ()
-			{
-				MathJax.Hub.Register.StartupHook('Begin', function()
-				{
-					for (var i = 0; i < mathJaxQueue.length; i++)
-					{
-						MathJax.Hub.Queue(['Typeset', MathJax.Hub, mathJaxQueue[i]]);
-					}
-				});
-		    }
-		};
-	
-		// Adds global enqueue method for async rendering
-		window.MathJaxRender = function(container)
-		{
-			// Initial rendering when MathJax finished loading
-			if (typeof(MathJax) !== 'undefined' && typeof(MathJax.Hub) !== 'undefined')
-			{
-				MathJax.Hub.Queue(['Typeset', MathJax.Hub, container]);
-			}
-			else
-			{
-				mathJaxQueue.push(container);
-			}
-		}
-	</script>
-    <script src="https://cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_HTMLorMML"></script>
-	<script>
-		var urlParams = (function(url)
-		{
-			var result = new Object();
-			var params = window.location.search.slice(1).split('&');
-			
-			for (var i = 0; i < params.length; i++)
-			{
-				idx = params[i].indexOf('=');
-				
-				if (idx > 0)
-				{
-					result[params[i].substring(0, idx)] = params[i].substring(idx + 1);
-				}
-			}
-			
-			return result;
-		})(window.location.href);
-		
-		// Removes unused dependencies
-		urlParams['analytics'] = '0';
-		urlParams['picker'] = '0';
-		urlParams['gapi'] = '0';
-		urlParams['db'] = '0';
-		
-		// Public global variables
-		var MAX_REQUEST_SIZE = 10485760;
-		var MAX_AREA = 10000 * 10000;
-
-		// Paths and files
-		var STENCIL_PATH = 'stencils';
-		var SHAPES_PATH = 'shapes';
-		var IMAGE_PATH = 'images';
-		// Path for images inside the diagram
-		var GRAPH_IMAGE_PATH = 'img';
-		var STYLE_PATH = 'styles';
-		var CSS_PATH = 'styles';
-		
-		// Directory for i18 files and basename for main i18n file
-		var RESOURCES_PATH = 'resources';
-		var RESOURCE_BASE = RESOURCES_PATH + '/dia';
-	
-		// Specifies connection mode for touch devices (at least one should be true)
-		var isLocalStorage = false;
-		var uiTheme = null;
-
-		// Sets the base path, the UI language via URL param and configures the
-		// supported languages to avoid 404s. The loading of all core language
-		// resources is disabled as all required resources are in grapheditor.
-		// properties. Note that in this example the loading of two resource
-		// files (the special bundle and the default bundle) is disabled to
-		// save a GET request. This requires that all resources be present in
-		// the special bundle.
-		var mxLoadResources = false;
-		var mxLanguage = 'en'
-		var geBasePath = 'js';
-		var mxBasePath = 'mxgraph';
-
-		function render(data)
-		{
-			mxConstants.SHADOWCOLOR = '#000000';
-			mxConstants.SHADOW_OPACITY = 0.25;
-
-			var graph = new Graph(document.getElementById('graph'));
-			graph.foldingEnabled = false;
-			graph.setEnabled(false);
-			
-			if (data.math)
-			{
-				mxClient.NO_FO = true;
-			}
-
-			var xmlDoc = mxUtils.parseXml(data.xml);
-			var codec = new mxCodec(xmlDoc);
-			codec.decode(xmlDoc.documentElement, graph.getModel());
-
-			// Handles PDF output where the output should match the page format if the page is visible
-			if (data.math && data.format == 'pdf' && xmlDoc.documentElement.getAttribute('page') == '1')
-			{
-				graph.pageVisible = true;
-
-				var pw = xmlDoc.documentElement.getAttribute('pageWidth');
-				var ph = xmlDoc.documentElement.getAttribute('pageHeight');
-				
-				if (pw != null && ph != null)
-				{
-					graph.pageFormat = new mxRectangle(0, 0, parseFloat(pw), parseFloat(ph));
-				}
-				
-				var ps = xmlDoc.documentElement.getAttribute('pageScale');
-				
-				if (ps != null)
-				{
-					graph.pageScale = ps;
-				}
-				
-				graph.getPageSize = function()
-				{
-					return new mxRectangle(0, 0, this.pageFormat.width * this.pageScale,
-							this.pageFormat.height * this.pageScale);
-				};
-				
-				graph.getPageLayout = function()
-				{
-					var size = (this.pageVisible) ? this.getPageSize() : this.scrollTileSize;
-					var bounds = this.getGraphBounds();
-					
-					if (bounds.width == 0 || bounds.height == 0)
-					{
-						return new mxRectangle(0, 0, 1, 1);
-					}
-					else
-					{
-						// Computes untransformed graph bounds
-						var x = bounds.x / this.view.scale - this.view.translate.x;
-						var y = bounds.y / this.view.scale - this.view.translate.y;
-						var w = bounds.width / this.view.scale;
-						var h = bounds.height / this.view.scale;
-						
-						var x0 = Math.floor(x / size.width);
-						var y0 = Math.floor(y / size.height);
-						var w0 = Math.ceil((x + w) / size.width) - x0;
-						var h0 = Math.ceil((y + h) / size.height) - y0;
-						
-						return new mxRectangle(x0, y0, w0, h0);
-					}
-				};
-
-				// Fits the number of background pages to the graph
-				graph.view.getBackgroundPageBounds = function()
-				{
-					var layout = this.graph.getPageLayout();
-					var page = this.graph.getPageSize();
-					
-					return new mxRectangle(this.scale * (this.translate.x + layout.x * page.width),
-							this.scale * (this.translate.y + layout.y * page.height),
-							this.scale * layout.width * page.width,
-							this.scale * layout.height * page.height);
-				};
-			}
-			else if (data.crop)
-			{
-				var b = graph.getGraphBounds();
-				graph.view.setTranslate(-b.x, -b.y);
-			}
-			else if (data.w != null && data.h != null)
-			{
-				var b = graph.getGraphBounds();
-				var s = Math.floor(Math.min(data.w / b.width, data.h / b.height) * 100) / 100;
-				graph.view.scaleAndTranslate(s, (data.w - b.width * s) / 2 / s - b.x,
-						(data.h - b.height * s) / 2 / s - b.y);
-			}
-			
-			if (data.math)
-			{
-				window.MathJaxRender(graph.container);
-				
-				// Asynchronous callback when MathJax has finished
-				window.MathJax.Hub.Queue(function ()
-				{
-					if (typeof window.callPhantom === 'function')
-					{
-						window.callPhantom();
-					}
-				});
-			}
-
-			var bounds = (graph.pageVisible) ? graph.view.getBackgroundPageBounds() : graph.getGraphBounds();
-			var bg = xmlDoc.documentElement.getAttribute('background');
-			
-			// Apply background color for direct export
-			if (data.format == 'jpg' && bg == 'none')
-			{
-				bg = '#ffffff';
-			}
-			
-			if (graph.pageVisible)
-			{
-				document.body.style.width = bounds.width + 'px';
-				document.body.style.height = bounds.height + 'px';
-			}
-			
-			document.body.style.backgroundColor = bg || '#ffffff';
-
-			// SVG not needed for math export
-			var svg = (data.math) ? '' : mxUtils.getXml(graph.getSvg());
-			
-			return {width: bounds.width, height: bounds.height, bg: bg, svg: svg};
-		};
-	</script>
-	<script src="js/app.min.js"></script>
-</head>
-<body style="margin:0px;">
-	<div id="graph"></div>
-</body>
-</html>

+ 28 - 2
war/export2.html

@@ -32,7 +32,7 @@
 			data.w = parseFloat(data.w) || 0;
 			data.h = parseFloat(data.h) || 0;
 			data.scale = parseFloat(data.scale) || 1;
-			
+
 			// Parses XML
 			var xmlDoc = mxUtils.parseXml(data.xml);
 			var diagrams = null;
@@ -309,7 +309,6 @@
 
 				// Negative coordinates are cropped or shifted if page visible
 				var gb = graph.getGraphBounds();
-				var border = 0;
 				var x0 = 0;
 				var y0 = 0;
 		
@@ -332,12 +331,39 @@
 				// Renders print output into this document and removes the graph container
 				preview.open(null, window);
 				graph.container.parentNode.removeChild(graph.container);
+
+				// Adds shadow
+				if (mxClient.IS_SVG && xmlDoc.documentElement.getAttribute('shadow') == '1')
+				{
+					var svgs = document.getElementsByTagName('svg');
+					
+					for (var i = 0; i < svgs.length; i++)
+					{
+						var svg = svgs[i];
+
+						var filter = graph.addSvgShadow(svg, null, true);
+						filter.setAttribute('id', 'shadow-' + i);
+						svg.appendChild(filter);
+						svg.setAttribute('filter', 'url(#' + 'shadow-' + i + ')');
+					}
+					
+					border = 7;
+				}
 				
 				bounds = new mxRectangle(0, 0, pf.width, pf.height);
 				renderMath(graph.container.parentNode);
 			}
 			else
 			{
+				// Adds shadow
+				if (mxClient.IS_SVG && xmlDoc.documentElement.getAttribute('shadow') == '1')
+				{
+					graph.addSvgShadow(graph.view.canvas.ownerSVGElement, null, true);
+					graph.setShadowVisible(true);
+					bounds.width += 7;
+					bounds.height += 7;
+				}
+				
 				renderMath(graph.container);
 				
 				if (data.format != 'pdf')

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 166 - 168
war/js/app.min.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 150 - 149
war/js/atlas-viewer.min.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 167 - 169
war/js/atlas.min.js


+ 130 - 94
war/js/diagramly/App.js

@@ -1879,39 +1879,36 @@ App.prototype.open = function()
 			}
 			else if (window.opener.openFile != null)
 			{
-				window.opener.openFile.setConsumer(mxUtils.bind(this, function(xml, filename)
+				window.opener.openFile.setConsumer(mxUtils.bind(this, function(xml, filename, temp)
 				{
 					this.spinner.stop();
 					
 					if (filename == null)
 					{
 						var title = urlParams['title'];
+						temp = true;
 						
 						if (title != null)
 						{
-							title = decodeURIComponent(title);
+							filename = decodeURIComponent(title);
 						}
 						else
 						{
-							title = this.defaultFilename;
+							filename = this.defaultFilename;
 						}
-						
-						this.fileLoaded(new LocalFile(this, xml, title, true));
 					}
-					else
+					
+					// Replaces PNG with XML extension
+					var dot = filename.substring(filename.length - 4) == '.png';
+					
+					if (dot > 0)
 					{
-						// Replaces PNG with XML extension
-						var dot = filename.substring(filename.length - 4) == '.png';
-						
-						if (dot > 0)
-						{
-							filename = filename.substring(0, filename.length - 4) + '.xml';
-						}
-						
-						this.fileLoaded((mxClient.IS_IOS) ?
-							new StorageFile(this, xml, filename) :
-							new LocalFile(this, xml, filename));
+						filename = filename.substring(0, filename.length - 4) + '.xml';
 					}
+					
+					this.fileLoaded((mxClient.IS_IOS) ?
+						new StorageFile(this, xml, filename) :
+						new LocalFile(this, xml, filename, temp));
 				}));
 			}
 		}
@@ -3163,75 +3160,76 @@ App.prototype.fileCreated = function(file, libs, replace, done)
 		var redirect = window.location.protocol + '//' + window.location.hostname + url;
 		var graph = null;
 		
+		// TODO: This code and comment needs checking (name is undefined and condition is inversed)
 		// Handles special case where SVG files need a rendered graph to be saved
-		if (!/\.svg$/i.test(name) && dataNode != null)
-		{
-			graph = this.createTemporaryGraph(this.editor.graph.getStylesheet());
-
-			document.body.appendChild(graph.container);
-			node = dataNode;
-			
-			if (node != null)
-			{
-				var diagramNode = null;
-				
-				if (node.nodeName == 'diagram')
-				{
-					diagramNode = node;
-				}
-				else if (node.nodeName == 'mxfile')
-				{
-					var diagrams = node.getElementsByTagName('diagram');
-
-					if (diagrams.length > 0)
-					{
-						diagramNode = diagrams[0];
-						var graphGetGlobalVariable = graph.getGlobalVariable;
-						
-						graph.getGlobalVariable = function(name)
-						{
-							if (name == 'page')
-							{
-								return diagramNode.getAttribute('name') || mxResources.get('pageWithNumber', [1])
-							}
-							else if (name == 'pagenumber')
-							{
-								return 1;
-							}
-							
-							return graphGetGlobalVariable.apply(this, arguments);
-						};
-					}
-				}
-				
-				if (diagramNode != null)
-				{
-					var tmp = graph.decompress(mxUtils.getTextContent(diagramNode));
-					
-					if (tmp != null && tmp.length > 0)
-					{
-						node = mxUtils.parseXml(tmp).documentElement;
-					}
-				}
-			}
-			
-			// Hack to decode XML into temp graph via editor
-			var prev = this.editor.graph;
-			
-			try
-			{
-				this.editor.graph = graph;
-				this.editor.setGraphXml(node);	
-			}
-			catch (e)
-			{
-				// ignore
-			}
-			finally
-			{
-				this.editor.graph = prev;
-			}
-		}
+//		if (!/\.svg$/i.test(name) && dataNode != null)
+//		{
+//			graph = this.createTemporaryGraph(this.editor.graph.getStylesheet());
+//
+//			document.body.appendChild(graph.container);
+//			node = dataNode;
+//			
+//			if (node != null)
+//			{
+//				var diagramNode = null;
+//				
+//				if (node.nodeName == 'diagram')
+//				{
+//					diagramNode = node;
+//				}
+//				else if (node.nodeName == 'mxfile')
+//				{
+//					var diagrams = node.getElementsByTagName('diagram');
+//
+//					if (diagrams.length > 0)
+//					{
+//						diagramNode = diagrams[0];
+//						var graphGetGlobalVariable = graph.getGlobalVariable;
+//						
+//						graph.getGlobalVariable = function(name)
+//						{
+//							if (name == 'page')
+//							{
+//								return diagramNode.getAttribute('name') || mxResources.get('pageWithNumber', [1])
+//							}
+//							else if (name == 'pagenumber')
+//							{
+//								return 1;
+//							}
+//							
+//							return graphGetGlobalVariable.apply(this, arguments);
+//						};
+//					}
+//				}
+//				
+//				if (diagramNode != null)
+//				{
+//					var tmp = graph.decompress(mxUtils.getTextContent(diagramNode));
+//					
+//					if (tmp != null && tmp.length > 0)
+//					{
+//						node = mxUtils.parseXml(tmp).documentElement;
+//					}
+//				}
+//			}
+//			
+//			// Hack to decode XML into temp graph via editor
+//			var prev = this.editor.graph;
+//			
+//			try
+//			{
+//				this.editor.graph = graph;
+//				this.editor.setGraphXml(node);	
+//			}
+//			catch (e)
+//			{
+//				// ignore
+//			}
+//			finally
+//			{
+//				this.editor.graph = prev;
+//			}
+//		}
 		
 		file.setData(this.createFileData(dataNode, graph, file, redirect));
 
@@ -3249,7 +3247,14 @@ App.prototype.fileCreated = function(file, libs, replace, done)
 		{
 			complete();
 			
-			var fn2 = mxUtils.bind(this, function()
+			var currentFile = this.getCurrentFile();
+			
+			if (replace == null && currentFile != null)
+			{
+				replace = !currentFile.isModified() && currentFile.getMode() == null;
+			}
+			
+			var fn3 = mxUtils.bind(this, function()
 			{
 				window.openFile = null;
 				this.fileLoaded(file);
@@ -3258,15 +3263,27 @@ App.prototype.fileCreated = function(file, libs, replace, done)
 				{
 					this.sidebar.showEntries(libs);
 				}
+			});
 
-				if (done != null)
+			var fn2 = mxUtils.bind(this, function()
+			{
+				if (currentFile == null || !currentFile.isModified())
 				{
-					done();
+					fn3();
+				}
+				else
+				{
+					this.confirm(mxResources.get('allChangesLost'), fn3);
 				}
 			});
-	
-			// Updates the file if it has been overwritten
-			if (!replace && this.getCurrentFile() != null && this.mode != null)
+
+			if (done != null)
+			{
+				done();
+			}
+
+			// Opens the file in a new window
+			if (replace != null && !replace)
 			{
 				// Opens local file in a new window
 				if (file.constructor == LocalFile)
@@ -3276,9 +3293,14 @@ App.prototype.fileCreated = function(file, libs, replace, done)
 						window.openFile = null;
 					});
 						
-					window.openFile.setData(file.getData(), file.getTitle());
+					window.openFile.setData(file.getData(), file.getTitle(), file.getMode() == null);
 				}
 
+				if (done != null)
+				{
+					done();
+				}
+				
 				window.openWindow(url, null, fn2);
 			}
 			else
@@ -3317,7 +3339,7 @@ App.prototype.loadFile = function(id, sameWindow, file)
 {
 	this.hideDialog();
 	
-	var fn = mxUtils.bind(this, function()
+	var fn2 = mxUtils.bind(this, function()
 	{
 		if (this.spinner.spin(document.body, mxResources.get('loading')))
 		{
@@ -3530,12 +3552,26 @@ App.prototype.loadFile = function(id, sameWindow, file)
 		}
 	});
 	
+	var currentFile = this.getCurrentFile();
+	
+	var fn = mxUtils.bind(this, function()
+	{
+		if (currentFile == null || !currentFile.isModified())
+		{
+			fn2();
+		}
+		else
+		{
+			this.confirm(mxResources.get('allChangesLost'), fn2);
+		}
+	});
+	
 	if (id == null || id.length == 0)
 	{
 		this.editor.setStatus('');
 		this.fileLoaded(null);
 	}
-	else if (this.getCurrentFile() != null && !this.isDiagramEmpty() && !sameWindow)
+	else if (currentFile != null && currentFile.isModified() && !sameWindow)
 	{
 		window.openWindow(this.getUrl() + '#' + id, null, fn);
 	}

+ 3 - 3
war/js/diagramly/Dialogs.js

@@ -2420,13 +2420,13 @@ var NewDialog = function(editorUi, compact, showName, callback)
 			if (title != null && title.length > 0)
 			{
 				var tempMode = (editorUi.mode == App.MODE_ONEDRIVE || (editorUi.mode == App.MODE_GOOGLE &&
-					(editorUi.stateArg == null || editorUi.stateArg.folderId == null))) ?  editorUi.mode : null;
+					(editorUi.stateArg == null || editorUi.stateArg.folderId == null))) ? editorUi.mode : null;
 				
 				editorUi.pickFolder(tempMode, function(folderId)
 				{
 					editorUi.createFile(title, templateXml, (templateLibs != null && templateLibs.length > 0) ? templateLibs : null, null, function()
 					{
-						editorUi.hideDialog();				
+						editorUi.hideDialog();
 					}, null, folderId);
 				}, tempMode != App.MODE_GOOGLE);
 			}
@@ -4112,7 +4112,7 @@ PrintDialog.prototype.create = function(editorUi, titleText)
 			}
 			
 			doc.writeln('</script>');
-			doc.writeln('<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/2.6-latest/MathJax.js"></script>');
+			doc.writeln('<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>');
 		}
 		
 		pv.closeDocument();

+ 92 - 89
war/js/diagramly/Editor.js

@@ -401,6 +401,9 @@
 		this.graph.view.y0 = null;
 		mxClient.NO_FO = (this.graph.mathEnabled) ? true : this.originalNoForeignObject;
 		editorResetGraph.apply(this, arguments);
+		
+		// Overrides default with persisted value
+		this.graph.pageFormat = mxSettings.getPageFormat();
 	};
 
 	/**
@@ -420,7 +423,7 @@
 	 */
 	Editor.initMath = function(src, config)
 	{
-		src = (src != null) ? src : 'https://cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_HTMLorMML';
+		src = (src != null) ? src : 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_HTMLorMML';
 		Editor.mathJaxQueue = [];
 		
 		Editor.doMathJaxRender = function(container)
@@ -508,94 +511,6 @@
 		}
 	};
 
-	/**
-	 * Adds a shadow filter to the given svg root.
-	 */
-	Editor.prototype.addSvgShadow = function(svgRoot, group, createOnly)
-	{
-		createOnly = (createOnly != null) ? createOnly : false;
-		
-		var svgDoc = svgRoot.ownerDocument;
-		
-		var filter = (svgDoc.createElementNS != null) ?
-			svgDoc.createElementNS(mxConstants.NS_SVG, 'filter') : svgDoc.createElement('filter');
-		filter.setAttribute('id', this.graph.shadowId);
-
-		var blur = (svgDoc.createElementNS != null) ?
-				svgDoc.createElementNS(mxConstants.NS_SVG, 'feGaussianBlur') : svgDoc.createElement('feGaussianBlur');
-		blur.setAttribute('in', 'SourceAlpha');
-		blur.setAttribute('stdDeviation', '1.7');
-		blur.setAttribute('result', 'blur');
-		filter.appendChild(blur);
-		
-		var offset = (svgDoc.createElementNS != null) ?
-				svgDoc.createElementNS(mxConstants.NS_SVG, 'feOffset') : svgDoc.createElement('feOffset');
-		offset.setAttribute('in', 'blur');
-		offset.setAttribute('dx', '3');
-		offset.setAttribute('dy', '3');
-		offset.setAttribute('result', 'offsetBlur');
-		filter.appendChild(offset);
-		
-		var flood = (svgDoc.createElementNS != null) ?
-				svgDoc.createElementNS(mxConstants.NS_SVG, 'feFlood') : svgDoc.createElement('feFlood');
-		flood.setAttribute('flood-color', '#3D4574');
-		flood.setAttribute('flood-opacity', '0.4');
-		flood.setAttribute('result', 'offsetColor');
-		filter.appendChild(flood);
-		
-		var composite = (svgDoc.createElementNS != null) ?
-				svgDoc.createElementNS(mxConstants.NS_SVG, 'feComposite') : svgDoc.createElement('feComposite');
-		composite.setAttribute('in', 'offsetColor');
-		composite.setAttribute('in2', 'offsetBlur');
-		composite.setAttribute('operator', 'in');
-		composite.setAttribute('result', 'offsetBlur');
-		filter.appendChild(composite);
-
-		var feBlend = (svgDoc.createElementNS != null) ?
-				svgDoc.createElementNS(mxConstants.NS_SVG, 'feBlend') : svgDoc.createElement('feBlend');
-		feBlend.setAttribute('in', 'SourceGraphic');
-		feBlend.setAttribute('in2', 'offsetBlur');
-		filter.appendChild(feBlend);
-		
-		// Creates defs element if not available
-		var defs = svgRoot.getElementsByTagName('defs');
-		var defsElt = null;
-		
-		if (defs.length == 0)
-		{
-			defsElt = (svgDoc.createElementNS != null) ?
-				svgDoc.createElementNS(mxConstants.NS_SVG, 'defs') : svgDoc.createElement('defs');
-			
-			if (svgRoot.firstChild != null)
-			{
-				svgRoot.insertBefore(defsElt, svgRoot.firstChild);
-			}
-			else
-			{
-				svgRoot.appendChild(defsElt);
-			}
-		}
-		else
-		{
-			defsElt = defs[0];
-		}
-		
-		defsElt.appendChild(filter);
-		
-		if (!createOnly)
-		{
-			(group || svgRoot.getElementsByTagName('g')[0]).setAttribute('filter', 'url(#' + this.graph.shadowId + ')');
-			
-			if (!isNaN(parseInt(svgRoot.getAttribute('width'))))
-			{
-				svgRoot.setAttribute('width', parseInt(svgRoot.getAttribute('width')) + 6);
-				svgRoot.setAttribute('height', parseInt(svgRoot.getAttribute('height')) + 6);
-			}
-		}
-		
-		return filter;
-	};
-	
 	/**
 	 * Return array of string values, or NULL if CSV string not well formed.
 	 */
@@ -1156,6 +1071,94 @@
 		this.currentStyle = 'default-style2';
 	};
 
+	/**
+	 * Adds a shadow filter to the given svg root.
+	 */
+	Graph.prototype.addSvgShadow = function(svgRoot, group, createOnly)
+	{
+		createOnly = (createOnly != null) ? createOnly : false;
+		
+		var svgDoc = svgRoot.ownerDocument;
+		
+		var filter = (svgDoc.createElementNS != null) ?
+			svgDoc.createElementNS(mxConstants.NS_SVG, 'filter') : svgDoc.createElement('filter');
+		filter.setAttribute('id', this.shadowId);
+
+		var blur = (svgDoc.createElementNS != null) ?
+				svgDoc.createElementNS(mxConstants.NS_SVG, 'feGaussianBlur') : svgDoc.createElement('feGaussianBlur');
+		blur.setAttribute('in', 'SourceAlpha');
+		blur.setAttribute('stdDeviation', '1.7');
+		blur.setAttribute('result', 'blur');
+		filter.appendChild(blur);
+		
+		var offset = (svgDoc.createElementNS != null) ?
+				svgDoc.createElementNS(mxConstants.NS_SVG, 'feOffset') : svgDoc.createElement('feOffset');
+		offset.setAttribute('in', 'blur');
+		offset.setAttribute('dx', '3');
+		offset.setAttribute('dy', '3');
+		offset.setAttribute('result', 'offsetBlur');
+		filter.appendChild(offset);
+		
+		var flood = (svgDoc.createElementNS != null) ?
+				svgDoc.createElementNS(mxConstants.NS_SVG, 'feFlood') : svgDoc.createElement('feFlood');
+		flood.setAttribute('flood-color', '#3D4574');
+		flood.setAttribute('flood-opacity', '0.4');
+		flood.setAttribute('result', 'offsetColor');
+		filter.appendChild(flood);
+		
+		var composite = (svgDoc.createElementNS != null) ?
+				svgDoc.createElementNS(mxConstants.NS_SVG, 'feComposite') : svgDoc.createElement('feComposite');
+		composite.setAttribute('in', 'offsetColor');
+		composite.setAttribute('in2', 'offsetBlur');
+		composite.setAttribute('operator', 'in');
+		composite.setAttribute('result', 'offsetBlur');
+		filter.appendChild(composite);
+
+		var feBlend = (svgDoc.createElementNS != null) ?
+				svgDoc.createElementNS(mxConstants.NS_SVG, 'feBlend') : svgDoc.createElement('feBlend');
+		feBlend.setAttribute('in', 'SourceGraphic');
+		feBlend.setAttribute('in2', 'offsetBlur');
+		filter.appendChild(feBlend);
+		
+		// Creates defs element if not available
+		var defs = svgRoot.getElementsByTagName('defs');
+		var defsElt = null;
+		
+		if (defs.length == 0)
+		{
+			defsElt = (svgDoc.createElementNS != null) ?
+				svgDoc.createElementNS(mxConstants.NS_SVG, 'defs') : svgDoc.createElement('defs');
+			
+			if (svgRoot.firstChild != null)
+			{
+				svgRoot.insertBefore(defsElt, svgRoot.firstChild);
+			}
+			else
+			{
+				svgRoot.appendChild(defsElt);
+			}
+		}
+		else
+		{
+			defsElt = defs[0];
+		}
+		
+		defsElt.appendChild(filter);
+		
+		if (!createOnly)
+		{
+			(group || svgRoot.getElementsByTagName('g')[0]).setAttribute('filter', 'url(#' + this.shadowId + ')');
+			
+			if (!isNaN(parseInt(svgRoot.getAttribute('width'))))
+			{
+				svgRoot.setAttribute('width', parseInt(svgRoot.getAttribute('width')) + 6);
+				svgRoot.setAttribute('height', parseInt(svgRoot.getAttribute('height')) + 6);
+			}
+		}
+		
+		return filter;
+	};
+	
 	/**
 	 * Loads the stylesheet for this graph.
 	 */

+ 11 - 35
war/js/diagramly/EditorUi.js

@@ -1062,7 +1062,7 @@
 					
 					if (addShadow)
 					{
-						this.editor.addSvgShadow(svgRoot);
+						this.editor.graph.addSvgShadow(svgRoot);
 					}
 					
 					// Embeds the images in the SVG output (async)
@@ -2434,17 +2434,8 @@
 	 */
 	EditorUi.prototype.saveCanvas = function(canvas, xml, format)
 	{
-   		var file = this.getCurrentFile();
-   	    var filename = (file != null && file.getTitle() != null) ? file.getTitle() : this.defaultFilename;
-   	    var dot = filename.lastIndexOf('.');
-   	    
-   	    if (dot > 0)
-   	    {
-   	    	filename = filename.substring(0, dot);
-   	    }
-   	    
-   	    var ext = (format == 'jpeg') ? 'jpg' : format;
-   	    filename += '.' + ext;
+		var ext = ((format == 'jpeg') ? 'jpg' : format);
+		var filename = this.getBaseFilename() + '.' + ext;
    	    var data = this.createImageDataUri(canvas, xml, format);
    	    this.saveData(filename, ext, data.substring(data.lastIndexOf(',') + 1), 'image/' + format, true);
 	};
@@ -2825,20 +2816,10 @@
 			
 			if (addShadow)
 			{
-				this.editor.addSvgShadow(svgRoot);
-			}
-		
-			var file = this.getCurrentFile();
-			var filename = (file != null && file.getTitle() != null) ? file.getTitle() : this.defaultFilename;
-			
-			var dot = filename.lastIndexOf('.');
-			
-			if (dot > 0)
-			{
-				filename = filename.substring(0, dot);
+				this.editor.graph.addSvgShadow(svgRoot);
 			}
 			
-			filename += '.svg';
+			var filename = this.getBaseFilename() + '.svg';
 
 			var doSave = mxUtils.bind(this, function(svgRoot)
 			{
@@ -3881,7 +3862,7 @@
 		// Adds shadow filter
 		if (shadow)
 		{
-			this.editor.addSvgShadow(svgRoot);
+			this.editor.graph.addSvgShadow(svgRoot);
 		}
 		
 		// SVG inside image tag
@@ -4082,16 +4063,11 @@
 	 */
 	EditorUi.prototype.getEmbeddedSvg = function(xml, graph, url, noHeader, callback, ignoreSelection, redirect)
 	{
-		var bg = null;
+		var bg = graph.background;
 		
-		if (graph != null)
+		if (bg == mxConstants.NONE)
 		{
-			bg = graph.background;
-			
-			if (bg == mxConstants.NONE)
-			{
-				bg = null;
-			}
+			bg = null;
 		}
 
 		// Sets or disables alternate text for foreignObjects. Disabling is needed
@@ -4268,7 +4244,7 @@
 			{
 				if (addShadow)
 				{
-					this.editor.addSvgShadow(svgRoot);
+					this.editor.graph.addSvgShadow(svgRoot);
 				}
 				
 				this.convertMath(graph, svgRoot, true, mxUtils.bind(this, function()
@@ -5607,7 +5583,7 @@
 		if (mxClient.IS_SVG)
 		{
 			// LATER: Add shadow for labels in graph.container (eg. math, NO_FO), scaling
-			this.editor.addSvgShadow(graph.view.canvas.ownerSVGElement, null, true);
+			this.editor.graph.addSvgShadow(graph.view.canvas.ownerSVGElement, null, true);
 		}
 
 		/**

+ 1 - 1
war/js/diagramly/Embed.js

@@ -64,7 +64,7 @@
 
 			var script = document.createElement('script');
 			script.type = 'text/javascript';
-			script.src = 'https://cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_HTMLorMML';
+			script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_HTMLorMML';
 			document.getElementsByTagName('head')[0].appendChild(script);
 		}
 	};

+ 10 - 4
war/js/diagramly/GitHubClient.js

@@ -351,7 +351,7 @@ GitHubClient.prototype.getFile = function(path, success, error, asLibrary)
 		if (this.token != null)
 		{
 			var url = this.baseUrl + '/repos/' + org + '/' + repo + '/contents/' +
-				path + '?ref=' + decodeURIComponent(ref) + '&token=' + this.token;
+				path + '?ref=' + ref + '&token=' + this.token;
 			var tokens = path.split('/');
 			var name = (tokens.length > 0) ? tokens[tokens.length - 1] : path;
 	
@@ -365,7 +365,7 @@ GitHubClient.prototype.getFile = function(path, success, error, asLibrary)
 	else
 	{
 		var req = new mxXmlRequest(this.baseUrl + '/repos/' + org + '/' + repo +
-			'/contents/' + path + '?ref=' + decodeURIComponent(ref), null, 'GET');
+			'/contents/' + path + '?ref=' + ref, null, 'GET');
 		
 		this.executeRequest(req, mxUtils.bind(this, function(req)
 		{
@@ -770,14 +770,20 @@ GitHubClient.prototype.showGitHubDialog = function(showFiles, fn)
 		this.ui.handleError(err, null, mxUtils.bind(this, function()
 		{
 			this.ui.spinner.stop();
-			this.ui.hideDialog();
+			
+			org = null;
+			repo = null;
+			ref = null;
+			path = null;
+			
+			selectRepo();
 		}));
 	});
 	
 	var selectFile = mxUtils.bind(this, function()
 	{
 		var req = new mxXmlRequest(this.baseUrl + '/repos/' + org + '/' + repo +
-				'/contents/' + path + '?ref=' + ref, null, 'GET');
+				'/contents/' + path + '?ref=' + encodeURIComponent(ref), null, 'GET');
 		dlg.okButton.removeAttribute('disabled');
 		div.innerHTML = '';
 		this.ui.spinner.spin(div, mxResources.get('loading'));

+ 1 - 1
war/js/diagramly/GraphViewer.js

@@ -136,7 +136,7 @@ GraphViewer.prototype.init = function(container, xmlNode, graphConfig)
 			if (mxClient.IS_SVG)
 			{
 				// LATER: Add shadow for labels in graph.container (eg. math, NO_FO), scaling
-				this.editor.addSvgShadow(this.graph.view.canvas.ownerSVGElement, null, true);
+				this.editor.graph.addSvgShadow(this.graph.view.canvas.ownerSVGElement, null, true);
 			}
 			
 			// Adds page placeholders

+ 3 - 3
war/js/diagramly/Menus.js

@@ -305,11 +305,11 @@
 			}
 		}, null, null, 'Ctrl+Shift+M');
 
-		var copiedStyles = ['rounded', 'shadow', 'dashed', 'dashPattern', 'fontFamily', 'fontSize', 'fontColor', 'fontStyle', 'align',
-		                    'verticalAlign', 'strokeColor', 'strokeWidth', 'fillColor', 'gradientColor', 'swimlaneFillColor',
+		var copiedStyles = ['rounded', 'shadow', 'dashed', 'dashPattern', 'fontFamily', 'fontSize', 'fontColor', 'fontStyle',
+			 				'align', 'verticalAlign', 'strokeColor', 'strokeWidth', 'fillColor', 'gradientColor', 'swimlaneFillColor',
 		                    'textOpacity', 'gradientDirection', 'glass', 'labelBackgroundColor', 'labelBorderColor', 'opacity',
 		                    'spacing', 'spacingTop', 'spacingLeft', 'spacingBottom', 'spacingRight', 'endFill', 'endArrow',
-		                    'endSize', 'startStill', 'startArrow', 'startSize'];
+		                    'endSize', 'startStill', 'startArrow', 'startSize', 'arcSize'];
 		
 		editorUi.actions.addAction('copyStyle', function()
 		{

+ 4 - 0
war/js/diagramly/Settings.js

@@ -1,3 +1,7 @@
+/**
+ * Copyright (c) 2006-2017, JGraph Ltd
+ * Copyright (c) 2006-2017, Gaudenz Alder
+ */
 /**
  * Utility class for working with persisted application settings
  */

+ 4 - 2
war/js/diagramly/StorageFile.js

@@ -1,5 +1,7 @@
-// $Id = StorageFile.js,v 1.12 2010-01-02 09 =45 =14 gaudenz Exp $
-// Copyright (c) 2006-2014, JGraph Ltd
+/**
+ * Copyright (c) 2006-2017, JGraph Ltd
+ * Copyright (c) 2006-2017, Gaudenz Alder
+ */
 /**
  * Constructs a new point for the optional x and y coordinates. If no
  * coordinates are given, then the default values for <x> and <y> are used.

+ 4 - 2
war/js/diagramly/StorageLibrary.js

@@ -1,5 +1,7 @@
-// $Id = DriveFile.js,v 1.12 2010-01-02 09 =45 =14 gaudenz Exp $
-// Copyright (c) 2006-2014, JGraph Ltd
+/**
+ * Copyright (c) 2006-2017, JGraph Ltd
+ * Copyright (c) 2006-2017, Gaudenz Alder
+ */
 /**
  * Constructs a new point for the optional x and y coordinates. If no
  * coordinates are given, then the default values for <x> and <y> are used.

+ 4 - 2
war/js/diagramly/UrlLibrary.js

@@ -1,5 +1,7 @@
-// $Id = DriveFile.js,v 1.12 2010-01-02 09 =45 =14 gaudenz Exp $
-// Copyright (c) 2006-2014, JGraph Ltd
+/**
+ * Copyright (c) 2006-2017, JGraph Ltd
+ * Copyright (c) 2006-2017, Gaudenz Alder
+ */
 /**
  * Constructs a new point for the optional x and y coordinates. If no
  * coordinates are given, then the default values for <x> and <y> are used.

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 37 - 37
war/js/embed-static.min.js


+ 1 - 1
war/js/embed.dev.js

@@ -64,7 +64,7 @@
 
 			var script = document.createElement('script');
 			script.type = 'text/javascript';
-			script.src = 'https://cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_HTMLorMML';
+			script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_HTMLorMML';
 			document.getElementsByTagName('head')[0].appendChild(script);
 		}
 	};

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
war/js/embed.min.js


+ 3 - 1
war/js/mxgraph/Actions.js

@@ -966,6 +966,8 @@ Actions.prototype.init = function()
 		
 		if (cells != null)
 		{
+			cells = graph.addAllEdges(cells);
+			
 			graph.getModel().beginUpdate();
 			try
 			{
@@ -991,7 +993,7 @@ Actions.prototype.init = function()
 				graph.getModel().endUpdate();
 			}
 		}
-	});
+	}, null, null, 'Alt+Shift+C');
 	action = this.addAction('subscript', mxUtils.bind(this, function()
 	{
 	    if (graph.cellEditor.isContentEditing())

+ 22 - 23
war/js/mxgraph/Editor.js

@@ -66,30 +66,29 @@ Editor.pageCounter = 0;
 // were opened from another domain then this will fail.
 (function()
 {
-	if (!mxClient.IS_FF) // https://drawio.atlassian.net/browse/DS-795
+	try
 	{
-		try
+		var op = window;
+
+		while (op.opener != null && typeof op.opener.Editor !== 'undefined' &&
+			!isNaN(op.opener.Editor.pageCounter) &&	
+			// Workaround for possible infinite loop in FF https://drawio.atlassian.net/browse/DS-795
+			op.opener != op)
 		{
-			var op = window;
-			
-			while (op.opener != null && typeof op.opener.Editor !== 'undefined' &&
-				!isNaN(op.opener.Editor.pageCounter))
-			{
-				op = op.opener;
-			}
-			
-			// Increments the counter in the first opener in the chain
-			if (op != null)
-			{
-				op.Editor.pageCounter++;
-				Editor.pageCounter = op.Editor.pageCounter;
-			}
+			op = op.opener;
 		}
-		catch (e)
+		
+		// Increments the counter in the first opener in the chain
+		if (op != null)
 		{
-			// ignore
+			op.Editor.pageCounter++;
+			Editor.pageCounter = op.Editor.pageCounter;
 		}
 	}
+	catch (e)
+	{
+		// ignore
+	}
 })();
 
 /**
@@ -629,6 +628,7 @@ OpenFile = function(done)
 	this.producer = null;
 	this.consumer = null;
 	this.done = done;
+	this.args = null;
 };
 
 /**
@@ -643,10 +643,9 @@ OpenFile.prototype.setConsumer = function(value)
 /**
  * Sets the data from the loaded file.
  */
-OpenFile.prototype.setData = function(value, filename)
+OpenFile.prototype.setData = function()
 {
-	this.data = value;
-	this.filename = filename;
+	this.args = arguments;
 	this.execute();
 };
 
@@ -664,10 +663,10 @@ OpenFile.prototype.error = function(msg)
  */
 OpenFile.prototype.execute = function()
 {
-	if (this.consumer != null && this.data != null)
+	if (this.consumer != null && this.args != null)
 	{
 		this.cancel(false);
-		this.consumer(this.data, this.filename);
+		this.consumer.apply(this, this.args);
 	}
 };
 

+ 15 - 1
war/js/mxgraph/EditorUi.js

@@ -2527,9 +2527,9 @@ EditorUi.prototype.updateActionStates = function()
 	}
 	
 	this.actions.get('setAsDefaultStyle').setEnabled(graph.getSelectionCount() == 1);
+	this.actions.get('clearWaypoints').setEnabled(!graph.isSelectionEmpty());
 	this.actions.get('turn').setEnabled(!graph.isSelectionEmpty());
 	this.actions.get('curved').setEnabled(edgeSelected);
-	this.actions.get('clearWaypoints').setEnabled(edgeSelected);
 	this.actions.get('rotation').setEnabled(vertexSelected);
 	this.actions.get('wordWrap').setEnabled(vertexSelected);
 	this.actions.get('autosize').setEnabled(vertexSelected);
@@ -3604,10 +3604,24 @@ EditorUi.prototype.createKeyHandler = function(editor)
 	
 	var keyHandlerGetFunction = keyHandler.getFunction;
 
+	// Alt+Shift+Keycode mapping to action
+	var altShiftActions = {67: this.actions.get('clearWaypoints')}; // Alt+Shift+C
+	
 	mxKeyHandler.prototype.getFunction = function(evt)
 	{
 		if (graph.isEnabled())
 		{
+			// TODO: Add alt modified state in core API, here are some specific cases
+			if (!graph.isSelectionEmpty() && mxEvent.isShiftDown(evt) && mxEvent.isAltDown(evt))
+			{
+				var action = altShiftActions[evt.keyCode];
+
+				if (action != null)
+				{
+					return action.funct;
+				}
+			}
+			
 			if (evt.keyCode == 9 && mxEvent.isAltDown(evt))
 			{
 				if (mxEvent.isShiftDown(evt))

+ 2 - 2
war/js/mxgraph/Format.js

@@ -1528,7 +1528,7 @@ ArrangePanel.prototype.addGroupOps = function(div)
 		div.appendChild(btn);
 		count++;
 	}
-	else if (ss.edges.length > 0)
+	else if (graph.getSelectionCount() > 0)
 	{
 		if (count > 0)
 		{
@@ -1540,7 +1540,7 @@ ArrangePanel.prototype.addGroupOps = function(div)
 			this.editorUi.actions.get('clearWaypoints').funct();
 		}));
 		
-		btn.setAttribute('title', mxResources.get('clearWaypoints'));
+		btn.setAttribute('title', mxResources.get('clearWaypoints') + ' (' + this.editorUi.actions.get('clearWaypoints').shortcut + ')');
 		btn.style.width = '202px';
 		btn.style.marginBottom = '2px';
 		div.appendChild(btn);

+ 11 - 11
war/js/mxgraph/Menus.js

@@ -992,7 +992,7 @@ Menus.prototype.createPopupMenu = function(menu, cell, evt)
 
 	}
 
-	if (graph.getSelectionCount() > 0)
+	if (!graph.isSelectionEmpty())
 	{
 		if (graph.getSelectionCount() == 1)
 		{
@@ -1003,13 +1003,11 @@ Menus.prototype.createPopupMenu = function(menu, cell, evt)
 		
 		cell = graph.getSelectionCell();
 		var state = graph.view.getState(cell);
-		
+
 		if (state != null)
 		{
-			if (graph.getSelectionCount() == 1)
-			{
-				this.addMenuItems(menu, ['toFront', 'toBack', '-'], null, evt);
-			}
+			var hasWaypoints = false;
+			this.addMenuItems(menu, ['toFront', 'toBack', '-'], null, evt);
 
 			if (graph.getModel().isEdge(cell) && mxUtils.getValue(state.style, mxConstants.STYLE_EDGE, null) != 'entityRelationEdgeStyle' &&
 				mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null) != 'arrow')
@@ -1034,13 +1032,15 @@ Menus.prototype.createPopupMenu = function(menu, cell, evt)
 	
 				// Adds reset waypoints option if waypoints exist
 				var geo = graph.getModel().getGeometry(cell);
-				
-				if (geo != null && geo.points != null && geo.points.length > 0)
-				{
-					this.addMenuItems(menu, ['clearWaypoints'], null, evt);	
-				}
+				hasWaypoints = geo != null && geo.points != null && geo.points.length > 0;
 			}
 
+			if (graph.getSelectionCount() == 1 && (hasWaypoints || (graph.getModel().isVertex(cell) &&
+				graph.getModel().getEdgeCount(cell) > 0)))
+			{
+				this.addMenuItems(menu, ['clearWaypoints'], null, evt);
+			}
+			
 			if (graph.getSelectionCount() > 1)	
 			{
 				menu.addSeparator();

+ 16 - 2
war/js/mxgraph/Shapes.js

@@ -2926,7 +2926,14 @@
 				// LATER: Make locked state independent of rotatable flag, fix toggle if default is false
 				//if (this.graph.isCellResizable(this.state.cell) || this.graph.isCellMovable(this.state.cell))
 				{
-					var fn = handleFactory[this.state.style['shape']];
+					var name = this.state.style['shape'];
+					
+					if (this.state.view.graph.cellRenderer.defaultShapes[name] == null)
+					{
+						name = mxConstants.SHAPE_RECTANGLE;
+					}
+					
+					var fn = handleFactory[name];
 				
 					if (fn != null)
 					{
@@ -2942,7 +2949,14 @@
 		{
 			if (this.state.view.graph.getSelectionCount() == 1)
 			{
-				var fn = handleFactory[this.state.style['shape']];
+				var name = this.state.style['shape'];
+				
+				if (this.state.view.graph.cellRenderer.defaultShapes[name] == null)
+				{
+					name = mxConstants.SHAPE_CONNECTOR;
+				}
+				
+				var fn = handleFactory[name];
 				
 				if (fn != null)
 				{

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 36 - 36
war/js/reader.min.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 150 - 150
war/js/viewer.min.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
war/shortcuts.svg


BIN
war/templates/business/bpmn.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
war/templates/business/bpmn.xml


BIN
war/templates/business/bpmnS.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
war/templates/business/bpmnS.xml


BIN
war/templates/business/swimlane.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
war/templates/business/swimlane.xml


BIN
war/templates/business/swimlaneS.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
war/templates/business/swimlaneS.xml


BIN
war/templates/charts/bar.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
war/templates/charts/bar.xml


BIN
war/templates/charts/bar2.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
war/templates/charts/bar2.xml


BIN
war/templates/charts/bar2S.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
war/templates/charts/bar2S.xml


BIN
war/templates/charts/barS.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
war/templates/charts/barS.xml


BIN
war/templates/charts/org1.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
war/templates/charts/org1.xml


BIN
war/templates/charts/org1S.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
war/templates/charts/org1S.xml


BIN
war/templates/charts/org2.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
war/templates/charts/org2.xml


BIN
war/templates/charts/org2S.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
war/templates/charts/org2S.xml


BIN
war/templates/charts/work_breakdown_structure.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
war/templates/charts/work_breakdown_structure.xml


BIN
war/templates/charts/work_breakdown_structureS.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
war/templates/charts/work_breakdown_structureS.xml


BIN
war/templates/flowcharts/flowchart1.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
war/templates/flowcharts/flowchart1.xml


BIN
war/templates/flowcharts/flowchart1S.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
war/templates/flowcharts/flowchart1S.xml


BIN
war/templates/flowcharts/flowchart2.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 1
war/templates/flowcharts/flowchart2.xml


BIN
war/templates/flowcharts/flowchart2S.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
war/templates/flowcharts/flowchart2S.xml


+ 0 - 0
war/templates/flowcharts/gantt.png


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels