001: /*
002: * @(#)JGraphGXLCodec.java 1.0 12-MAY-2004
003: *
004: * Copyright (c) 2001-2004, Gaudenz Alder, Paul Raingeard de la Blétière
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions are met:
009: *
010: * - Redistributions of source code must retain the above copyright notice,
011: * this list of conditions and the following disclaimer.
012: * - Redistributions in binary form must reproduce the above copyright notice,
013: * this list of conditions and the following disclaimer in the documentation
014: * and/or other materials provided with the distribution.
015: * - Neither the name of JGraph nor the names of its contributors may be used
016: * to endorse or promote products derived from this software without specific
017: * prior written permission.
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028: * POSSIBILITY OF SUCH DAMAGE.
029: */
030: package com.jgraph.codecplugin;
031:
032: import java.awt.Color;
033: import java.awt.Dimension;
034: import java.awt.Font;
035: import java.awt.Point;
036: import java.awt.Rectangle;
037: import java.awt.geom.Rectangle2D;
038: import java.beans.BeanInfo;
039: import java.beans.Introspector;
040: import java.beans.PropertyDescriptor;
041: import java.io.ByteArrayInputStream;
042: import java.io.IOException;
043: import java.io.InputStream;
044: import java.net.HttpURLConnection;
045: import java.net.URL;
046: import java.util.ArrayList;
047: import java.util.Hashtable;
048: import java.util.Iterator;
049: import java.util.LinkedList;
050: import java.util.List;
051: import java.util.Map;
052:
053: import javax.xml.parsers.DocumentBuilder;
054: import javax.xml.parsers.DocumentBuilderFactory;
055:
056: import org.jgraph.JGraph;
057: import org.jgraph.graph.ConnectionSet;
058: import org.jgraph.graph.DefaultGraphCell;
059: import org.jgraph.graph.DefaultGraphModel;
060: import org.jgraph.graph.GraphCell;
061: import org.jgraph.graph.GraphConstants;
062: import org.jgraph.graph.GraphLayoutCache;
063: import org.jgraph.graph.GraphModel;
064: import org.w3c.dom.DOMException;
065: import org.w3c.dom.Document;
066: import org.w3c.dom.Element;
067: import org.w3c.dom.Node;
068: import org.w3c.dom.NodeList;
069: import org.xml.sax.EntityResolver;
070: import org.xml.sax.InputSource;
071: import org.xml.sax.SAXException;
072:
073: import com.jgraph.pad.graph.JGraphpadRichTextValue;
074:
075: /**
076: * GXL Codec.
077: */
078: public class JGraphpadGXLCodec {
079:
080: static transient Hashtable encodeHash;
081:
082: static transient Hashtable decodeHash;
083:
084: /**
085: * Perperty for XML parse. True : the parse wil validate the XML withing the
086: * DTD. False : It only will be done if it is available.
087: */
088: private static boolean validateDTD = false;
089:
090: /**
091: * Retrieves the encoding Hashtable with the node's Id.
092: *
093: * It may be usefull to sirialize the values of the nodes.
094: *
095: * @return Hastable with elements : ((key : node), (value : GXL id)).
096: */
097: public static Hashtable getLastEncodingHashtable() {
098: return encodeHash;
099: }
100:
101: /**
102: * Retrieves the decoding Hashtable with the node's Id.
103: *
104: * It may be usefull to sirialize the values of the nodes.
105: *
106: * @return Hastable with elements : ((key : node), (value : GXL id)).
107: */
108: public static Hashtable getLastDecodingHashtable() {
109: return decodeHash;
110: }
111:
112: /**
113: * Create a GXL-representation for all the cells.
114: *
115: * @param graph
116: * JGraph to encode.
117: * @return Encoded string.
118: */
119: public static String encode(JGraph graph) {
120: Object[] cells = graph.getDescendants(graph.getRoots());
121: return encode(graph, cells);
122: }
123:
124: /**
125: * Create a GXL-representation for the specified cells.
126: *
127: * @param graph
128: * JGraph to encode.
129: * @param cells
130: * Selected cells to be encoded.
131: * @return Encoded string.
132: */
133: public static String encode(JGraph graph, Object[] cells) {
134: int counter = 0;
135: encodeHash = new Hashtable();
136: String gxl = "<?xml version=\"1.0\"?>\n"
137: + "<!DOCTYPE gxl SYSTEM \"http://www.gupro.de/GXL/gxl-1.1.dtd\">\n"
138: + "<gxl xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n"
139: + "<graph id=\"jGraph\">\n";
140:
141: // Create external keys for nodes
142: for (int i = 0; i < cells.length; i++) {
143: if (JGraphpadCodecPlugin.isVertex(graph, cells[i])) {
144: encodeHash.put(cells[i], "node" + counter);
145: counter++;
146: }
147: }
148:
149: // Convert Nodes
150: Iterator it = encodeHash.keySet().iterator();
151: while (it.hasNext()) {
152: Object node = it.next();
153: gxl += encodeVertex(graph, (String) encodeHash.get(node),
154: node);
155: }
156:
157: // Convert Edges
158: int edges = 0;
159: for (int i = 0; i < cells.length; i++)
160: if (graph.getModel().isEdge(cells[i]))
161: gxl += encodeEdge(graph, new Integer(edges++), cells[i]);
162:
163: // Close main tags
164: gxl += "\n</graph>\n</gxl>";
165: return gxl;
166: }
167:
168: /**
169: * Create a string with tabs.
170: *
171: * @param level
172: * Tab level.
173: * @return Tab string.
174: */
175: private static String createTab(int level) {
176: String tab = "";
177: for (int i = 0; i < level; i++) {
178: tab += "\t";
179: }
180: return tab;
181: }
182:
183: /**
184: * Basic value encoding.
185: *
186: * @param type
187: * GXL Type of the value (int, bool, ...)
188: * @param value
189: * Value to be encoded.
190: * @param level
191: * Tab level.
192: * @return Encoded string.
193: */
194: protected static String encodeValue(String type, String value,
195: int level) {
196: return createTab(level) + "<" + type + ">" + value + "</"
197: + type + ">\n";
198: }
199:
200: /**
201: * Basic boolean encoding.
202: *
203: * @param value
204: * Value to be encoded.
205: * @param level
206: * Tab level.
207: * @return Encoded string.
208: */
209: private static String encodeValue(boolean value, int level) {
210: return createTab(level) + "<bool>" + value + "</bool>\n";
211: }
212:
213: /**
214: * Basic integer encoding.
215: *
216: * @param value
217: * Value to be encoded.
218: * @param level
219: * Tab level.
220: * @return Encoded string.
221: */
222: protected static String encodeValue(int value, int level) {
223: return createTab(level) + "<int>" + value + "</int>\n";
224: }
225:
226: /**
227: * Basic String encoding.
228: *
229: * @param value
230: * Value to be encoded.
231: * @param level
232: * Tab level.
233: * @return Encoded string.
234: */
235: protected static String encodeValue(String value, int level) {
236: return createTab(level) + "<string>" + value + "</string>\n";
237: }
238:
239: /**
240: * Attribute encoding.
241: *
242: * @param values
243: * Values of the attribute.
244: * @param attributeName
245: * name of the attribute.
246: * @param level
247: * Tab level.
248: * @return Encoded string.
249: */
250: protected static String encodeAttribute(String values,
251: String attributeName, int level) {
252: String tab = createTab(level);
253: return tab + "<attr name=\"" + attributeName + "\">\n" + values
254: + tab + "</attr>\n";
255: }
256:
257: /**
258: * String encoding.
259: *
260: * @param value
261: * Value of the attribute.
262: * @param attributeName
263: * name of the attribute.
264: * @param level
265: * Tab level.
266: * @return Encoded string.
267: */
268: protected static String encodeString(String value,
269: String attributeName, int level) {
270: if (value != null) {
271: return encodeAttribute(encodeValue(value, level + 1),
272: attributeName, level);
273: } else {
274: return "";
275: }
276: }
277:
278: /**
279: * Integer encoding.
280: *
281: * @param value
282: * Value of the attribute.
283: * @param attributeName
284: * name of the attribute.
285: * @param level
286: * Tab level.
287: * @return Encoded string.
288: */
289: protected static String encodeInteger(int value,
290: String attributeName, int level) {
291: return encodeAttribute(encodeValue(value, level + 1),
292: attributeName, level);
293: }
294:
295: /**
296: * Boolean encoding.
297: *
298: * @param value
299: * Value of the attribute.
300: * @param attributeName
301: * name of the attribute.
302: * @param level
303: * Tab level.
304: * @return Encoded string.
305: */
306: protected static String encodeBoolean(boolean value,
307: String attributeName, int level) {
308: return encodeAttribute(encodeValue(value, level + 1),
309: attributeName, level);
310: }
311:
312: /**
313: * Color encoding.
314: *
315: * @param color
316: * Color of the attribute.
317: * @param attributeName
318: * name of the attribute.
319: * @param level
320: * Tab level.
321: * @return Encoded string.
322: */
323: protected static String encodeColor(Color color,
324: String attributeName, int level) {
325: if (color != null) {
326: String tab1 = createTab(level + 1);
327: int level2 = level + 2;
328: String values = tab1 + "<tup>\n"
329: + encodeValue(color.getRed(), level2)
330: + encodeValue(color.getGreen(), level2)
331: + encodeValue(color.getBlue(), level2) + tab1
332: + "</tup>\n";
333: return encodeAttribute(values, attributeName, level);
334: } else {
335: return "";
336: }
337: }
338:
339: /**
340: * Font encoding.
341: *
342: * @param font
343: * Font of the attribute.
344: * @param attributeName
345: * name of the attribute.
346: * @param level
347: * Tab level.
348: * @return Encoded string.
349: */
350: protected static String encodeFont(Font font, String attributeName,
351: int level) {
352: if (font != null) {
353: String tab1 = createTab(level + 1);
354: int level2 = level + 2;
355: String values = tab1 + "<tup>\n"
356: + encodeValue(font.getFontName(), level2)
357: + encodeValue(font.getStyle(), level2)
358: + encodeValue(font.getSize(), level2) + tab1
359: + "</tup>\n";
360: return encodeAttribute(values, attributeName, level);
361: } else {
362: return "";
363: }
364: }
365:
366: /**
367: * Rectangle encoding.
368: *
369: * @param rec
370: * Rectangle to be encoded.
371: * @param attributeName
372: * name of the attribute.
373: * @param level
374: * Tab level.
375: * @return Encoded string.
376: */
377: protected static String encodeRectangle(Rectangle2D rec,
378: String attributeName, int level) {
379: if (rec != null) {
380: String tab1 = createTab(level + 1);
381: int level2 = level + 2;
382: String values = tab1 + "<tup>\n"
383: + encodeValue((int) rec.getCenterX(), level2)
384: + encodeValue((int) rec.getCenterY(), level2)
385: + encodeValue((int) rec.getWidth(), level2)
386: + encodeValue((int) rec.getHeight(), level2) + tab1
387: + "</tup>\n";
388: return encodeAttribute(values, attributeName, level);
389: } else {
390: return "";
391: }
392: }
393:
394: /**
395: * Bean encoding. This is usefull to encode the userObject in the Vertex. It
396: * must be a bean with a beanInfo class in order to inspect it.
397: *
398: * @param bean
399: * Bean to be encoded.
400: * @param attributeName
401: * name of the attribute.
402: * @param level
403: * Tab level.
404: * @return Encoded string.
405: */
406: protected static String encodeBean(Object bean,
407: String attributeName, int level) {
408: String encoded = "";
409: if (bean != null) {
410: try {
411: int level1 = level + 1;
412: BeanInfo bi = null;
413: PropertyDescriptor tmpProperties[] = null;
414: PropertyDescriptor prop = null;
415:
416: bi = Introspector.getBeanInfo(bean.getClass());
417: tmpProperties = bi.getPropertyDescriptors();
418: encoded += encodeString(bean.getClass().getName(),
419: "ClassName", level1);
420: for (int i = 0; i < tmpProperties.length; i++) {
421: prop = tmpProperties[i];
422: encoded += encodeString(prop.getReadMethod()
423: .invoke(bean, null).toString(), prop
424: .getDisplayName(), level1);
425: }
426: encoded = encodeAttribute(encoded, attributeName, level);
427: } catch (Exception e) {
428: e.printStackTrace();
429: }
430: }
431: return encoded;
432: }
433:
434: /**
435: * Encode a Vertex of a graph
436: *
437: * @param graph
438: * Graph containing the vertex.
439: * @param id
440: * Id of the vertex.
441: * @param vertex
442: * Vertex to be encoded.
443: * @return Encoded string.
444: */
445: protected static String encodeVertex(JGraph graph, String id,
446: Object vertex) {
447: int level = 2;
448: String label = graph.convertValueToString(vertex);
449: Map attributes = ((GraphCell) vertex).getAttributes();
450: String encoded = "\n\t<node id=\""
451: + id
452: + "\">\n"
453: + encodeString(label, "Label", level)
454: + encodeRectangle(GraphConstants.getBounds(attributes),
455: "Bounds", level)
456: + encodeColor(
457: GraphConstants.getBorderColor(attributes),
458: "BorderColor", level)
459: + encodeColor(GraphConstants.getForeground(attributes),
460: "BorderColor", level)
461: + encodeColor(GraphConstants.getBackground(attributes),
462: "BorderColor", level)
463: + encodeFont(GraphConstants.getFont(attributes),
464: "Font", level)
465: + encodeColor(GraphConstants.getLineColor(attributes),
466: "BorderColor", level)
467: // + encodeBoolean(GraphConstants.getOpaque(attributes),
468: // "Opaque", level)
469: // + encodeBean(GraphConstants.getValue(attributes), "Value",
470: // level)
471: + "\t</node>";
472: return encoded;
473: }
474:
475: /**
476: * Encode a Edge of a graph
477: *
478: * @param graph
479: * Graph containing the edge.
480: * @param id
481: * Id of the vertex.
482: * @param edge
483: * Edge to be encoded.
484: * @return Encoded string.
485: */
486: protected static String encodeEdge(JGraph graph, Object id,
487: Object edge) {
488: GraphModel model = graph.getModel();
489: String from = "";
490: if (model.getSource(edge) != null) {
491: Object source = encodeHash.get(model.getParent(model
492: .getSource(edge)));
493: if (source != null)
494: from = source.toString();
495: }
496: String to = "";
497: if (model.getTarget(edge) != null) {
498: Object target = encodeHash.get(model.getParent(model
499: .getTarget(edge)));
500: if (target != null)
501: to = target.toString();
502: }
503: if (from != null && to != null) {
504: int level = 2;
505: Map attributes = ((GraphCell) edge).getAttributes();
506: String label = graph.convertValueToString(edge);
507: return "\n\t<edge id=\"edge"
508: + id.toString()
509: + "\""
510: + " from=\""
511: + from
512: + "\""
513: + " to=\""
514: + to
515: + "\">\n"
516: + encodeString(label, "Label", 2)
517: + encodeInteger(GraphConstants
518: .getLineEnd(attributes), "LineEnd", level)
519: + encodeColor(GraphConstants
520: .getForeground(attributes), "Foreground",
521: level)
522: + encodeFont(GraphConstants.getFont(attributes),
523: "Font", level)
524: + encodeInteger(GraphConstants
525: .getLineStyle(attributes), "LineStyle",
526: level)
527: + encodeColor(GraphConstants
528: .getLineColor(attributes), "LineColor",
529: level) + "\n\t</edge>";
530: } else
531: return "";
532: }
533:
534: /**
535: * Extracts visual properties of the node from the child 'view' element
536: * Currently recognized properties: - Bounds - color - background-color -
537: * autosize - Font - Line-End, Line-size, Line-color
538: */
539: protected static void decodeCell(Node gnode, Map gnode_attrs) {
540: NodeList gnode_children = gnode.getChildNodes();
541: for (int gnode_child_i = 0; gnode_child_i < gnode_children
542: .getLength(); gnode_child_i++) {
543: Node gnode_child = gnode_children.item(gnode_child_i);
544: if (gnode_child.getNodeName().equals("attr")) {
545: String name = ((Element) gnode_child)
546: .getAttribute("name");
547: LinkedList values = new LinkedList();
548: // Retreaving all the values in the node
549: readGXLAttributeValues(gnode_child, values);
550: if ((name != null) && (values.size() > 0)) {
551: if (name.equals("Bounds")) {
552: if (values.size() == 4) {
553: Point p = new Point(Integer
554: .parseInt((String) values.get(0)),
555: Integer.parseInt((String) values
556: .get(1)));
557: Dimension d = new Dimension(Integer
558: .parseInt((String) values.get(2)),
559: Integer.parseInt((String) values
560: .get(3)));
561: Rectangle2D bounds = new Rectangle(p, d);
562: GraphConstants.setBounds(gnode_attrs,
563: bounds);
564: }
565: } else if (name.equals("Font")) {
566: if (values.size() == 3) {
567: Font font = new Font(
568: (String) values.get(0), Integer
569: .parseInt((String) values
570: .get(1)), Integer
571: .parseInt((String) values
572: .get(2)));
573: GraphConstants.setFont(gnode_attrs, font);
574: }
575: } else if (name.equals("Foreground")) {
576: try {
577: Color color = new Color(Integer
578: .parseInt((String) values.get(0)),
579: Integer.parseInt((String) values
580: .get(1)), Integer
581: .parseInt((String) values
582: .get(2)));
583: GraphConstants.setForeground(gnode_attrs,
584: color);
585: } catch (Exception nfe) {
586: }
587: } else if (name.equals("BorderColor")) {
588: try {
589: Color color = new Color(Integer
590: .parseInt((String) values.get(0)),
591: Integer.parseInt((String) values
592: .get(1)), Integer
593: .parseInt((String) values
594: .get(2)));
595: GraphConstants.setBorderColor(gnode_attrs,
596: color);
597: } catch (Exception nfe) {
598: }
599: } else if (name.equals("LineColor")) {
600: try {
601: Color color = new Color(Integer
602: .parseInt((String) values.get(0)),
603: Integer.parseInt((String) values
604: .get(1)), Integer
605: .parseInt((String) values
606: .get(2)));
607: GraphConstants.setLineColor(gnode_attrs,
608: color);
609: } catch (Exception nfe) {
610: }
611: } else if (name.equals("Background")) {
612: try {
613: Color color = new Color(Integer
614: .parseInt((String) values.get(0)),
615: Integer.parseInt((String) values
616: .get(1)), Integer
617: .parseInt((String) values
618: .get(2)));
619: GraphConstants.setBackground(gnode_attrs,
620: color);
621: } catch (Exception nfe) {
622: }
623: } else if (name.equals("LineColor")) {
624: try {
625: Color color = new Color(Integer
626: .parseInt((String) values.get(0)),
627: Integer.parseInt((String) values
628: .get(1)), Integer
629: .parseInt((String) values
630: .get(2)));
631: GraphConstants.setLineColor(gnode_attrs,
632: color);
633: } catch (Exception nfe) {
634: }
635: } else if (name.equals("LineEnd")) {
636: try {
637: GraphConstants.setLineEnd(gnode_attrs,
638: Integer.parseInt((String) values
639: .get(0)));
640: } catch (Exception e) {
641: }
642: } else if (name.equals("LineStyle")) {
643: try {
644: GraphConstants.setLineStyle(gnode_attrs,
645: Integer.parseInt((String) values
646: .get(0)));
647: } catch (Exception e) {
648: }
649: } else if (name.equals("AutoSize")) {
650: GraphConstants.setAutoSize(gnode_attrs, "true"
651: .equals((String) values.get(0)));
652: }
653: }
654: }
655: }
656: }
657:
658: /**
659: * Reads the values of an GXL Attribute.
660: *
661: * @param enode
662: * Node to read.
663: * @param values
664: * List to populate : with 2 dimension String arrys. return[0] :
665: * type of value return[1] : value
666: */
667: protected static void readGXLAttributeValues(Node enode,
668: LinkedList values) {
669: // read Child Elements
670: NodeList child_list = enode.getChildNodes();
671: for (int j = 0; j < child_list.getLength(); j++) {
672: Node currentNode = child_list.item(j);
673: String nodeName = currentNode.getNodeName();
674: if (nodeName.equals("tup") || nodeName.equals("set")
675: || nodeName.equals("enum")
676: || nodeName.equals("seq") || nodeName.equals("bag")) {
677: readGXLAttributeValues(currentNode, values);
678: } else if (nodeName.equals("int")
679: || nodeName.equals("bool")
680: || nodeName.equals("float")
681: || nodeName.equals("string")
682: || nodeName.equals("locator")) {
683: try {
684: Node firstChild = currentNode.getFirstChild();
685: // Check to see if first child exists. Null strings
686: // will just show no value
687: if (null == firstChild) {
688: if (nodeName.equals("string"))
689: values.add(new String(""));
690: } else {
691: values.add(currentNode.getFirstChild()
692: .getNodeValue());
693: }
694: } catch (DOMException e) {
695: }
696: }
697: }
698: }
699:
700: /**
701: * Decodes a Edge.
702: *
703: * @param enode
704: * XML Node.
705: * @param enode_attrs
706: * Cell Attributes.
707: */
708: protected static void decodeEdge(Node enode, Map enode_attrs) {
709: decodeCell(enode, enode_attrs);
710: }
711:
712: /**
713: * Manage DTD offline.
714: *
715: * @param db
716: * XML document builder.
717: */
718: private static void manageDTDLookup(DocumentBuilder db) {
719: // Error During DTD validation : can't find www.gupro.de
720: // Forget validation
721: db.setEntityResolver(new EntityResolver() {
722: public InputSource resolveEntity(java.lang.String publicId,
723: java.lang.String systemId) throws SAXException,
724: java.io.IOException {
725: InputSource is = null;
726: try {
727: URL url = new URL(systemId);
728: HttpURLConnection con = (HttpURLConnection) url
729: .openConnection();
730: con.connect();
731: int responseCode = con.getResponseCode();
732: con.disconnect();
733: if (responseCode != HttpURLConnection.HTTP_NOT_FOUND) {
734: is = new InputSource(systemId);
735: } else {
736: is = new InputSource(new ByteArrayInputStream(
737: "<?xml version='1.0' encoding='UTF-8'?>"
738: .getBytes()));
739: }
740: } catch (IOException e) {
741: is = new InputSource(new ByteArrayInputStream(
742: "<?xml version='1.0' encoding='UTF-8'?>"
743: .getBytes()));
744: }
745: return is;
746: }
747: });
748: }
749:
750: /**
751: * Decodes a GXL File.
752: *
753: * @param inputStream
754: * Stream to be decoded.
755: * @param cache
756: * GraphLayoutCache where the decode file is inserted.
757: */
758: public static void decode(InputStream inputStream,
759: GraphLayoutCache cache, Object vertexPrototype,
760: Object edgePrototype) throws Exception {
761: String defaultLayout = null;
762: // Create a DocumentBuilderFactory
763: DocumentBuilderFactory dbf = DocumentBuilderFactory
764: .newInstance();
765: // Create a DocumentBuilder
766: DocumentBuilder db = dbf.newDocumentBuilder();
767: // Manage the compliange with the DTD File.
768: if (validateDTD == false) {
769: manageDTDLookup(db);
770: }
771: // Parse the input file to get a Document object
772: Document doc = db.parse(inputStream);
773: // Get the first child (the graph-element)
774: // List for the new Cells
775: List newCells = new ArrayList();
776: // ConnectionSet for the Insert method
777: ConnectionSet cs = new ConnectionSet();
778: // Hashtable for the ID lookup (ID to Vertex)
779: decodeHash = new Hashtable();
780: // Hashtable for Attributes (Vertex to Map)
781: Hashtable attributes = new Hashtable();
782:
783: Element gxl = (Element) doc.getDocumentElement(); // First gxl element
784:
785: NodeList graph_list = gxl.getChildNodes();
786: if (graph_list.getLength() == 0) {
787: return;
788: }
789: for (int graph_index = 0; graph_index < graph_list.getLength(); graph_index++) {
790: Node graph_node = graph_list.item(graph_index);
791: if (graph_node.getNodeName().equals("graph")) {
792: Element graph_elem = (Element) graph_node;
793: NodeList list = graph_elem.getChildNodes();
794: boolean defaultDirected = "directed".equals(graph_elem
795: .getAttribute("edgemode"))
796: || "defaultdirected".equals(graph_elem
797: .getAttribute("edgemode"));
798: // End of Opheamro
799:
800: // Get Graph's Child Nodes (the cells)
801:
802: // Loop Children
803: for (int i = 0; i < list.getLength(); i++) {
804: Node node = list.item(i);
805: // Fetch Label
806: String label = getLabel(node);
807: // If Valid Node
808: if (node.getAttributes() != null
809: && node.getNodeName() != null) {
810: // Fetch Type
811: String type = node.getNodeName().toString()
812: .toLowerCase();
813:
814: // Create Vertex
815: if (type.equals("node")) {
816: // Fetch ID Node
817: String id = null;
818: Node tmp = node.getAttributes()
819: .getNamedItem("id");
820: // Fetch ID Value
821: if (tmp != null)
822: id = tmp.getNodeValue();
823: // Need unique valid ID
824: if (id != null
825: && !decodeHash.keySet()
826: .contains(id)) {
827: // Create Vertex with label
828: Object vertex = DefaultGraphModel
829: .cloneCell(cache.getModel(),
830: vertexPrototype);
831: cache.getModel().valueForCellChanged(
832: vertex,
833: new JGraphpadRichTextValue(
834: label));
835: // Add ID, Vertex pair to Hashtable
836: decodeHash.put(id, vertex);
837: // Add Default Attributes
838: Map node_attrs = new Hashtable(); // createDefaultAttributes(new
839: // Hashtable());
840: decodeCell(node, node_attrs);
841: attributes.put(vertex, node_attrs);
842: // Add Vertex to new Cells
843: newCells.add(vertex);
844: }
845:
846: // Create Edge
847: } else if (type.equals("edge")) {
848: Element edge_node = (Element) node;
849: // Fetch Source ID Node
850: Node tmp = node.getAttributes()
851: .getNamedItem("from");
852: // Fetch Source ID Value
853: String source = null;
854: if (tmp != null)
855: source = tmp.getNodeValue();
856: // Fetch Target ID Node
857: tmp = node.getAttributes().getNamedItem(
858: "to");
859: // Fetch Target ID Value
860: String target = null;
861: if (tmp != null)
862: target = tmp.getNodeValue();
863: // Create Edge with label
864: Object edge = DefaultGraphModel.cloneCell(
865: cache.getModel(), edgePrototype);
866: cache.getModel().valueForCellChanged(edge,
867: label);
868: // Find Source Port
869: if (source != null) {
870: // Fetch Vertex for Source ID
871: DefaultGraphCell vertex = (DefaultGraphCell) decodeHash
872: .get(source);
873: if (vertex != null)
874: // Connect to Source Port
875: cs.connect(edge, vertex
876: .getChildAt(0), true);
877: }
878: // Find Target Port
879: if (target != null) {
880: // Fetch Vertex for Target ID
881: DefaultGraphCell vertex = (DefaultGraphCell) decodeHash
882: .get(target);
883: if (vertex != null)
884: // Connect to Target Port
885: cs.connect(edge, vertex
886: .getChildAt(0), false);
887: }
888:
889: boolean edge_directed = ("true"
890: .equals(edge_node
891: .getAttribute("isdirected")) || defaultDirected)
892: && !("false"
893: .equals(edge_node
894: .getAttribute("isdirected")));
895: Map map = new Hashtable();
896: if (edge_directed) {
897: GraphConstants.setLineEnd(map,
898: GraphConstants.ARROW_CLASSIC);
899: GraphConstants.setEndFill(map, true);
900: }
901: decodeEdge(edge_node, map);
902: attributes.put(edge, map);
903:
904: // Add Edge to new Cells
905: newCells.add(edge);
906: } else if (type.equals("view")) { // Graph view
907: // attributes
908: // Currently defined: defaultlayout
909: defaultLayout = ((Element) node)
910: .getAttribute("defaultlayout");
911: }
912: }
913: }
914: }
915: }
916: // Insert the cells (View stores attributes)
917: cache.insert(newCells.toArray(), attributes, cs, null, null);
918: }
919:
920: /**
921: * Returns an attributeMap for the specified position and color.
922: */
923: protected static Map createDefaultAttributes(Map map) {
924: // Set a Black Line Border (the Border-Attribute must be Null!)
925: GraphConstants.setBorderColor(map, Color.black);
926: // Return the Map
927: return map;
928: }
929:
930: // Fetch Cell Label from Node
931: protected static String getLabel(Node node) {
932: String lab = null;
933: NodeList children = node.getChildNodes();
934: for (int j = 0; j < children.getLength(); j++) {
935: Node attr = children.item(j);
936: if (attr.getNodeName().equals("attr")
937: && attr.getAttributes().getNamedItem("name")
938: .getNodeValue().equals("Label")) {
939: NodeList values = attr.getChildNodes();
940: for (int k = 0; k < values.getLength(); k++) {
941: if (values.item(k).getNodeName().equals("string")) {
942: Node labelNode = values.item(k).getFirstChild();
943: if (labelNode != null)
944: lab = labelNode.getNodeValue();
945: }
946: }
947: }
948: }
949: return (lab != null) ? lab : new String("");
950: }
951:
952: /**
953: * Setter for the property validateDTD
954: *
955: * @param validate
956: * True, the validation will occur.
957: */
958: public static void setValidateDTD(boolean validate) {
959: validateDTD = validate;
960: }
961:
962: /**
963: * Getter for the property validateDTD
964: */
965: public static boolean getValidateDTD() {
966: return validateDTD;
967: }
968: }
|