/**
* Copyright (c) 2010-2012, JGraph Ltd
*/
package com.mxgraph.io;
import com.mxgraph.io.graphml.mxGraphMlConstants;
import com.mxgraph.io.graphml.mxGraphMlData;
import com.mxgraph.io.graphml.mxGraphMlEdge;
import com.mxgraph.io.graphml.mxGraphMlGraph;
import com.mxgraph.io.graphml.mxGraphMlKey;
import com.mxgraph.io.graphml.mxGraphMlKeyManager;
import com.mxgraph.io.graphml.mxGraphMlNode;
import com.mxgraph.io.graphml.mxGraphMlShapeEdge;
import com.mxgraph.io.graphml.mxGraphMlShapeNode;
import com.mxgraph.io.graphml.mxGraphMlUtils;
import com.mxgraph.model.mxCell;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxDomUtils;
import com.mxgraph.util.mxPoint;
import com.mxgraph.view.mxCellState;
import com.mxgraph.view.mxConnectionConstraint;
import com.mxgraph.view.mxGraph;
import com.mxgraph.view.mxGraphView;
import java.util.HashMap;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Parses a GraphML .graphml file and imports it in the given graph.<br/>
*
* See wikipedia.org/wiki/GraphML for more on GraphML.
*
* This class depends from the classes contained in
* com.mxgraph.io.gmlImplements.
*/
public class mxGraphMlCodec
{
/**
* Receives a GraphMl document and parses it generating a new graph that is inserted in graph.
* @param document XML to be parsed
* @param graph Graph where the parsed graph is included.
*/
public static void decode(Document document, mxGraph graph)
{
Object parent = graph.getDefaultParent();
graph.getModel().beginUpdate();
// Initialise the key properties.
mxGraphMlKeyManager.getInstance().initialise(document);
NodeList graphs = document.getElementsByTagName(mxGraphMlConstants.GRAPH);
if (graphs.getLength() > 0)
{
Element graphElement = (Element) graphs.item(0);
//Create the graph model.
mxGraphMlGraph gmlGraph = new mxGraphMlGraph(graphElement);
gmlGraph.addGraph(graph, parent);
}
graph.getModel().endUpdate();
cleanMaps();
}
/**
* Remove all the elements in the Defined Maps.
*/
private static void cleanMaps()
{
mxGraphMlKeyManager.getInstance().getKeyMap().clear();
}
/**
* Generates a Xml document with the gmlGraph.
* @param gmlGraph Graph model.
* @return The Xml document generated.
*/
public static Document encodeXML(mxGraphMlGraph gmlGraph)
{
Document doc = mxDomUtils.createDocument();
Element graphml = doc.createElement(mxGraphMlConstants.GRAPHML);
graphml.setAttribute("xmlns", "http://graphml.graphdrawing.org/xmlns");
graphml.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xsi",
"http://www.w3.org/2001/XMLSchema-instance");
graphml.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:jGraph",
mxGraphMlConstants.JGRAPH_URL);
graphml.setAttributeNS(
"http://www.w3.org/2001/XMLSchema-instance",
"xsi:schemaLocation",
"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd");
HashMap<String, mxGraphMlKey> keyMap = mxGraphMlKeyManager.getInstance()
.getKeyMap();
for (mxGraphMlKey key : keyMap.values())
{
Element keyElement = key.generateElement(doc);
graphml.appendChild(keyElement);
}
Element graphE = gmlGraph.generateElement(doc);
graphml.appendChild(graphE);
doc.appendChild(graphml);
cleanMaps();
return doc;
}
/**
* Generates a Xml document with the cells in the graph.
* @param graph Graph with the cells.
* @return The Xml document generated.
*/
public static Document encode(mxGraph graph)
{
mxGraphMlGraph gmlGraph = new mxGraphMlGraph();
Object parent = graph.getDefaultParent();
createKeyElements();
gmlGraph = decodeGraph(graph, parent, gmlGraph);
gmlGraph.setEdgedefault(mxGraphMlConstants.EDGE_DIRECTED);
Document document = encodeXML(gmlGraph);
return document;
}
/**
* Creates the key elements for the encode.
*/
private static void createKeyElements()
{
HashMap<String, mxGraphMlKey> keyMap = mxGraphMlKeyManager.getInstance()
.getKeyMap();
mxGraphMlKey keyNode = new mxGraphMlKey(mxGraphMlConstants.KEY_NODE_ID,
mxGraphMlKey.keyForValues.NODE, mxGraphMlConstants.KEY_NODE_NAME,
mxGraphMlKey.keyTypeValues.STRING);
keyMap.put(mxGraphMlConstants.KEY_NODE_ID, keyNode);
mxGraphMlKey keyEdge = new mxGraphMlKey(mxGraphMlConstants.KEY_EDGE_ID,
mxGraphMlKey.keyForValues.EDGE, mxGraphMlConstants.KEY_EDGE_NAME,
mxGraphMlKey.keyTypeValues.STRING);
keyMap.put(mxGraphMlConstants.KEY_EDGE_ID, keyEdge);
mxGraphMlKeyManager.getInstance().setKeyMap(keyMap);
}
/**
* Returns a Gml graph with the data of the vertexes and edges in the graph.
* @param gmlGraph Gml document where the elements are put.
* @param parent Parent cell of the vertexes and edges to be added.
* @param graph Graph that contains the vertexes and edges.
* @return Returns the document with the elements added.
*/
public static mxGraphMlGraph decodeGraph(mxGraph graph, Object parent,
mxGraphMlGraph gmlGraph)
{
Object[] vertexes = graph.getChildVertices(parent);
List<mxGraphMlEdge> gmlEdges = gmlGraph.getEdges();
gmlEdges = encodeEdges(gmlEdges, parent, graph);
gmlGraph.setEdges(gmlEdges);
for (Object vertex : vertexes)
{
List<mxGraphMlNode> Gmlnodes = gmlGraph.getNodes();
mxCell v = (mxCell) vertex;
String id = v.getId();
mxGraphMlNode gmlNode = new mxGraphMlNode(id, null);
addNodeData(gmlNode, v);
Gmlnodes.add(gmlNode);
gmlGraph.setNodes(Gmlnodes);
mxGraphMlGraph gmlGraphx = new mxGraphMlGraph();
gmlGraphx = decodeGraph(graph, vertex, gmlGraphx);
if (!gmlGraphx.isEmpty())
{
List<mxGraphMlGraph> nodeGraphs = gmlNode.getNodeGraph();
nodeGraphs.add(gmlGraphx);
gmlNode.setNodeGraph(nodeGraphs);
}
}
return gmlGraph;
}
/**
* Add the node data in the gmlNode.
* @param gmlNode Gml node where the data add.
* @param v mxCell where data are obtained.
*/
public static void addNodeData(mxGraphMlNode gmlNode, mxCell v)
{
mxGraphMlData data = new mxGraphMlData();
mxGraphMlShapeNode dataShapeNode = new mxGraphMlShapeNode();
data.setDataKey(mxGraphMlConstants.KEY_NODE_ID);
dataShapeNode
.setDataHeight(String.valueOf(v.getGeometry().getHeight()));
dataShapeNode.setDataWidth(String.valueOf(v.getGeometry().getWidth()));
dataShapeNode.setDataX(String.valueOf(v.getGeometry().getX()));
dataShapeNode.setDataY(String.valueOf(v.getGeometry().getY()));
dataShapeNode.setDataLabel(v.getValue() != null ? v.getValue()
.toString() : "");
dataShapeNode.setDataStyle(v.getStyle() != null ? v.getStyle() : "");
data.setDataShapeNode(dataShapeNode);
gmlNode.setNodeData(data);
}
/**
* Add the edge data in the gmlEdge.
* @param gmlEdge Gml edge where the data add.
* @param v mxCell where data are obtained.
*/
public static void addEdgeData(mxGraphMlEdge gmlEdge, mxCell v)
{
mxGraphMlData data = new mxGraphMlData();
mxGraphMlShapeEdge dataShapeEdge = new mxGraphMlShapeEdge();
data.setDataKey(mxGraphMlConstants.KEY_EDGE_ID);
dataShapeEdge.setText(v.getValue() != null ? v.getValue().toString()
: "");
dataShapeEdge.setStyle(v.getStyle() != null ? v.getStyle() : "");
data.setDataShapeEdge(dataShapeEdge);
gmlEdge.setEdgeData(data);
}
/**
* Converts a connection point in the string representation of a port.
* The specials names North, NorthWest, NorthEast, East, West, South, SouthEast and SouthWest
* may be returned. Else, the values returned follows the pattern "double,double"
* where double must be in the range 0..1
* @param point mxPoint
* @return Name of the port
*/
private static String pointToPortString(mxPoint point)
{
String port = "";
if (point != null)
{
double x = point.getX();
double y = point.getY();
if (x == 0 && y == 0)
{
port = "NorthWest";
}
else if (x == 0.5 && y == 0)
{
port = "North";
}
else if (x == 1 && y == 0)
{
port = "NorthEast";
}
else if (x == 1 && y == 0.5)
{
port = "East";
}
else if (x == 1 && y == 1)
{
port = "SouthEast";
}
else if (x == 0.5 && y == 1)
{
port = "South";
}
else if (x == 0 && y == 1)
{
port = "SouthWest";
}
else if (x == 0 && y == 0.5)
{
port = "West";
}
else
{
port = "" + x + "," + y;
}
}
return port;
}
/**
* Returns a list of mxGmlEdge with the data of the edges in the graph.
* @param Gmledges List where the elements are put.
* @param parent Parent cell of the edges to be added.
* @param graph Graph that contains the edges.
* @return Returns the list Gmledges with the elements added.
*/
private static List<mxGraphMlEdge> encodeEdges(List<mxGraphMlEdge> Gmledges,
Object parent, mxGraph graph)
{
Object[] edges = graph.getChildEdges(parent);
for (Object edge : edges)
{
mxCell e = (mxCell) edge;
mxCell source = (mxCell) e.getSource();
mxCell target = (mxCell) e.getTarget();
String sourceName = "";
String targetName = "";
String sourcePort = "";
String targetPort = "";
sourceName = source != null ? source.getId() : "";
targetName = target != null ? target.getId() : "";
//Get the graph view that contains the states
mxGraphView view = graph.getView();
mxPoint sourceConstraint = null;
mxPoint targetConstraint = null;
if (view != null)
{
mxCellState edgeState = view.getState(edge);
mxCellState sourceState = view.getState(source);
mxConnectionConstraint scc = graph.getConnectionConstraint(
edgeState, sourceState, true);
if (scc != null)
{
sourceConstraint = scc.getPoint();
}
mxCellState targetState = view.getState(target);
mxConnectionConstraint tcc = graph.getConnectionConstraint(
edgeState, targetState, false);
if (tcc != null)
{
targetConstraint = tcc.getPoint();
}
}
//gets the port names
targetPort = pointToPortString(targetConstraint);
sourcePort = pointToPortString(sourceConstraint);
mxGraphMlEdge Gmledge = new mxGraphMlEdge(sourceName, targetName,
sourcePort, targetPort);
String style = e.getStyle();
if (style == null)
{
style = "horizontal";
}
HashMap<String, Object> styleMap = mxGraphMlUtils.getStyleMap(style,
"=");
String endArrow = (String) styleMap.get(mxConstants.STYLE_ENDARROW);
if ((endArrow != null && !endArrow.equals(mxConstants.NONE))
|| endArrow == null)
{
Gmledge.setEdgeDirected("true");
}
else
{
Gmledge.setEdgeDirected("false");
}
addEdgeData(Gmledge, e);
Gmledges.add(Gmledge);
}
return Gmledges;
}
}