0001: /*
0002: * $Id: JGraphpadJGXAction.java,v 1.4 2006/02/03 14:36:39 david Exp $
0003: * Copyright (c) 2001-2005, Gaudenz Alder
0004: *
0005: * All rights reserved.
0006: *
0007: * See LICENSE file for license details. If you are unable to locate
0008: * this file please contact info (at) jgraph (dot) com.
0009: */
0010: package com.jgraph.jgxplugin;
0011:
0012: import java.awt.Color;
0013: import java.awt.Component;
0014: import java.awt.Dimension;
0015: import java.awt.Font;
0016: import java.awt.Point;
0017: import java.awt.event.ActionEvent;
0018: import java.awt.geom.Point2D;
0019: import java.awt.geom.Rectangle2D;
0020: import java.io.File;
0021: import java.io.InputStream;
0022: import java.net.URL;
0023: import java.net.URLDecoder;
0024: import java.util.Hashtable;
0025: import java.util.Iterator;
0026: import java.util.LinkedList;
0027: import java.util.List;
0028: import java.util.Map;
0029: import java.util.Stack;
0030: import java.util.StringTokenizer;
0031:
0032: import javax.swing.BorderFactory;
0033: import javax.swing.Icon;
0034: import javax.swing.JComponent;
0035: import javax.swing.border.Border;
0036: import javax.xml.parsers.DocumentBuilder;
0037: import javax.xml.parsers.DocumentBuilderFactory;
0038:
0039: import org.jgraph.JGraph;
0040: import org.jgraph.graph.AttributeMap;
0041: import org.jgraph.graph.ConnectionSet;
0042: import org.jgraph.graph.DefaultGraphCell;
0043: import org.jgraph.graph.DefaultGraphModel;
0044: import org.jgraph.graph.DefaultPort;
0045: import org.jgraph.graph.Edge;
0046: import org.jgraph.graph.GraphConstants;
0047: import org.w3c.dom.Document;
0048: import org.w3c.dom.Node;
0049:
0050: import com.jgraph.JGraphEditor;
0051: import com.jgraph.JGraphpad;
0052: import com.jgraph.editor.JGraphEditorAction;
0053: import com.jgraph.pad.action.JGraphpadFileAction;
0054: import com.jgraph.pad.graph.JGraphpadBusinessObject;
0055: import com.jgraph.pad.graph.JGraphpadGraphConstants;
0056: import com.jgraph.pad.graph.JGraphpadRichTextValue;
0057: import com.jgraph.pad.graph.JGraphpadVertexRenderer;
0058: import com.jgraph.pad.util.JGraphpadImageIcon;
0059: import com.jgraph.pad.util.JGraphpadShadowBorder;
0060:
0061: /**
0062: * JGX import for reading older JGraphpad files.
0063: */
0064: public class JGraphpadJGXAction extends JGraphpadFileAction {
0065:
0066: public static final String TYPE_RECT = "rect", TYPE_TEXT = "text",
0067: TYPE_ELLIPSE = "ellipse", TYPE_DIAMOND = "diamond",
0068: TYPE_TRIANGLE = "triangle", TYPE_ROUNDRECT = "roundRect",
0069: TYPE_SWIMLANE = "swimlane", TYPE_IMAGE = "image",
0070: TYPE_PORT = "port", TYPE_EDGE = "edge";
0071:
0072: public static final String NAME_IMPORTJGX = "importJGX";
0073:
0074: public static final String EMPTY = new String("Empty");
0075:
0076: public static final String PARENT = new String("Parent");
0077:
0078: protected static Map cells = new Hashtable();
0079:
0080: protected static Map attrs = new Hashtable();
0081:
0082: protected static Map objs = new Hashtable();
0083:
0084: protected static List delayedAttributes;
0085:
0086: protected static List connectionSetIDs;
0087:
0088: protected Map cellMap = new Hashtable();
0089:
0090: protected AttributeCollection attrCol = new AttributeCollection();
0091:
0092: protected Map userObjectMap = new Hashtable();
0093:
0094: /**
0095: * Constructs a new Batik action for the specified editor.
0096: */
0097: protected JGraphpadJGXAction(JGraphEditor editor) {
0098: super (NAME_IMPORTJGX, editor);
0099: }
0100:
0101: /**
0102: * Executes the action based on the action name.
0103: *
0104: * @param event
0105: * The object that describes the event.
0106: */
0107: public void actionPerformed(ActionEvent event) {
0108: Component component = getPermanentFocusOwner();
0109: try {
0110: if (component instanceof JGraph) {
0111: JGraph graph = (JGraph) component;
0112: if (getName().equals(NAME_IMPORTJGX))
0113: doImportJGX(graph, false);
0114: }
0115: } catch (Exception e) {
0116: dlgs.errorDialog(getPermanentFocusOwner(), e
0117: .getLocalizedMessage());
0118: }
0119: }
0120:
0121: public void doImportJGX(JGraph graph, boolean urlDialog)
0122: throws Exception {
0123: String filename = (urlDialog) ? dlgs.valueDialog(
0124: getString("EnterURL"), "") : dlgs.fileDialog(
0125: getPermanentFocusOwnerOrParent(),
0126: getString("OpenJGXFile"), true, ".jgx",
0127: getString("JGXFileDescription"), lastDirectory);
0128: if (filename != null) {
0129: InputStream in = editor.getModel().getInputStream(filename);
0130: read(in, graph);
0131: System.out.println("file " + filename + " read");
0132: in.close();
0133: lastDirectory = new File(filename).getParentFile();
0134: }
0135: }
0136:
0137: public DefaultGraphCell createCell(JGraph graph, Object type,
0138: Object userObject) {
0139: if (type.equals(TYPE_EDGE)) {
0140: Object prototype = getValue(KEY_EDGEPROTOTYPE);
0141: if (prototype instanceof DefaultGraphCell) {
0142: DefaultGraphCell edge = (DefaultGraphCell) DefaultGraphModel
0143: .cloneCell(graph.getModel(), prototype);
0144: graph.getModel().valueForCellChanged(edge, userObject);
0145: return edge;
0146: }
0147: } else if (type.equals(TYPE_PORT)) {
0148: return new DefaultPort(); // no port prototype
0149: } else {
0150: Object prototype = getValue(KEY_VERTEXPROTOTYPE);
0151: if (prototype instanceof DefaultGraphCell) {
0152: DefaultGraphCell vertex = (DefaultGraphCell) DefaultGraphModel
0153: .cloneCell(graph.getModel(), prototype);
0154: graph.getModel()
0155: .valueForCellChanged(vertex, userObject);
0156: Map attrs = graph.getModel().getAttributes(vertex);
0157: if (type.equals(TYPE_ROUNDRECT))
0158: JGraphpadGraphConstants.setVertexShape(attrs,
0159: JGraphpadVertexRenderer.SHAPE_ROUNDED);
0160: else if (type.equals(TYPE_ELLIPSE))
0161: JGraphpadGraphConstants.setVertexShape(attrs,
0162: JGraphpadVertexRenderer.SHAPE_CIRCLE);
0163: else if (type.equals(TYPE_DIAMOND))
0164: JGraphpadGraphConstants.setVertexShape(attrs,
0165: JGraphpadVertexRenderer.SHAPE_DIAMOND);
0166: else if (type.equals(TYPE_TRIANGLE))
0167: JGraphpadGraphConstants.setVertexShape(attrs,
0168: JGraphpadVertexRenderer.SHAPE_TRIANGLE);
0169: else if (type.equals(TYPE_TEXT)
0170: && userObject instanceof Map) {
0171: Map user = (Map) userObject;
0172: Object text = user.get("value");
0173: if (text != null)
0174: graph.getModel().valueForCellChanged(
0175: vertex,
0176: new JGraphpadRichTextValue(text
0177: .toString()));
0178: }
0179: return vertex;
0180: }
0181: }
0182: return null;
0183: }
0184:
0185: /**
0186: * returns <tt>pad_xml</tt>
0187: */
0188: public String getFileExtension() {
0189: return "jgx";
0190: }
0191:
0192: /**
0193: * Returns null
0194: */
0195: public JComponent getReadAccessory() {
0196: return null;
0197: }
0198:
0199: /**
0200: * Returns null
0201: */
0202: public Hashtable getReadProperties(JComponent accessory) {
0203: return null;
0204: }
0205:
0206: //
0207: // Read
0208: //
0209:
0210: public void read(InputStream in, JGraph graph) throws Exception {
0211: // Create a DocumentBuilderFactory
0212: DocumentBuilderFactory dbf = DocumentBuilderFactory
0213: .newInstance();
0214: // Create a DocumentBuilder
0215: DocumentBuilder db = dbf.newDocumentBuilder();
0216: // Parse the input file to get a Document object
0217: Document doc = db.parse(in);
0218: // Get the first child (the jgx-element)
0219: Node modelNode = null;
0220: Node objsNode = null;
0221: Node attrsNode = null;
0222: Node viewNode = null;
0223:
0224: delayedAttributes = new LinkedList();
0225: connectionSetIDs = new LinkedList();
0226:
0227: for (int i = 0; i < doc.getDocumentElement().getChildNodes()
0228: .getLength(); i++) {
0229: Node node = doc.getDocumentElement().getChildNodes()
0230: .item(i);
0231: if (node.getNodeName().toLowerCase().equals("model")) {
0232: modelNode = node;
0233: } else if (node.getNodeName().toLowerCase().equals("user")) {
0234: objsNode = node;
0235: } else if (node.getNodeName().toLowerCase().equals("attrs")) {
0236: attrsNode = node;
0237: } else if (node.getNodeName().toLowerCase().equals("view")) {
0238: viewNode = node;
0239: }
0240: }
0241: objs = decodeUserObjects(objsNode);
0242: attrs = parseAttrs(attrsNode);
0243: attrs = augmentAttrs(attrs);
0244: Map settings = decodeMap(viewNode, false, false);
0245: ConnectionSet cs = new ConnectionSet();
0246: Hashtable cells = new Hashtable();
0247: DefaultGraphCell[] insert = parseChildren(graph, modelNode,
0248: cells, cs);
0249:
0250: // Create ConnectionSet
0251: Iterator it = connectionSetIDs.iterator();
0252: while (it.hasNext()) {
0253: ConnectionID cid = (ConnectionID) it.next();
0254: Object cell = cid.getCell();
0255: String tid = cid.getTargetID();
0256: if (tid != null) {
0257: Object port = cells.get(tid);
0258: if (port != null) {
0259: cs.connect(cell, port, cid.isSource());
0260: }
0261: }
0262: }
0263:
0264: // Create AttributeMap
0265: Map nested = new Hashtable();
0266: it = delayedAttributes.iterator();
0267: while (it.hasNext()) {
0268: DelayedAttributeID att = (DelayedAttributeID) it.next();
0269: Map attr = (Map) attrs.get(att.getMapID());
0270: if (attr == null)
0271: attr = new Hashtable();
0272: if (attr != null) {
0273: AttributeMap attr_temp = new AttributeMap(attr);
0274: attr = (Map) attr_temp.clone();
0275: if (att.getBounds() != null)
0276: GraphConstants.setBounds(attr, att.getBounds());
0277: if (att.getPoints() != null)
0278: GraphConstants.setPoints(attr, att.getPoints());
0279: nested.put(att.getCell(), attr);
0280: }
0281: }
0282:
0283: // Apply settings to graph
0284: applySettings(settings, graph);
0285:
0286: // Insert the cells (View stores attributes)
0287: graph.getGraphLayoutCache().insert(insert, nested, cs, null,
0288: null);
0289: }
0290:
0291: public void applySettings(Map s, JGraph graph) {
0292: Object tmp;
0293:
0294: tmp = s.get("editable");
0295: if (tmp != null)
0296: graph.setEditable(new Boolean(tmp.toString())
0297: .booleanValue());
0298:
0299: tmp = s.get("bendable");
0300: if (tmp != null)
0301: graph.setBendable(new Boolean(tmp.toString())
0302: .booleanValue());
0303:
0304: tmp = s.get("cloneable");
0305: if (tmp != null)
0306: graph.setCloneable(new Boolean(tmp.toString())
0307: .booleanValue());
0308:
0309: tmp = s.get("connectable");
0310: if (tmp != null)
0311: graph.setConnectable(new Boolean(tmp.toString())
0312: .booleanValue());
0313:
0314: tmp = s.get("disconnectable");
0315: if (tmp != null)
0316: graph.setDisconnectable(new Boolean(tmp.toString())
0317: .booleanValue());
0318:
0319: tmp = s.get("disconnectOnMove");
0320: if (tmp != null)
0321: graph.setDisconnectOnMove(new Boolean(tmp.toString())
0322: .booleanValue());
0323:
0324: tmp = s.get("doubleBuffered");
0325: if (tmp != null)
0326: graph.setDoubleBuffered(new Boolean(tmp.toString())
0327: .booleanValue());
0328:
0329: tmp = s.get("dragEnabled");
0330: if (tmp != null)
0331: graph.setDragEnabled(new Boolean(tmp.toString())
0332: .booleanValue());
0333:
0334: tmp = s.get("dropEnabled");
0335: if (tmp != null)
0336: graph.setDropEnabled(new Boolean(tmp.toString())
0337: .booleanValue());
0338:
0339: tmp = s.get("moveable");
0340: if (tmp != null)
0341: graph.setMoveable(new Boolean(tmp.toString())
0342: .booleanValue());
0343:
0344: tmp = s.get("sizeable");
0345: if (tmp != null)
0346: graph.setSizeable(new Boolean(tmp.toString())
0347: .booleanValue());
0348:
0349: tmp = s.get("gridVisible");
0350: if (tmp != null)
0351: graph.setGridVisible(new Boolean(tmp.toString())
0352: .booleanValue());
0353:
0354: tmp = s.get("gridEnabled");
0355: if (tmp != null)
0356: graph.setGridEnabled(new Boolean(tmp.toString())
0357: .booleanValue());
0358:
0359: tmp = s.get("gridSize");
0360: if (tmp != null)
0361: graph.setGridSize(Double.parseDouble(tmp.toString()));
0362:
0363: tmp = s.get("gridMode");
0364: if (tmp != null)
0365: graph.setGridMode(Integer.parseInt(tmp.toString()));
0366:
0367: tmp = s.get("scale");
0368: if (tmp != null)
0369: graph.setScale(Double.parseDouble(tmp.toString()));
0370:
0371: tmp = s.get("antiAlias");
0372: if (tmp != null)
0373: graph.setAntiAliased(new Boolean(tmp.toString())
0374: .booleanValue());
0375:
0376: }
0377:
0378: public Map augmentAttrs(Map attrs) {
0379: Map newAttrs = new Hashtable();
0380: Iterator it = attrs.entrySet().iterator();
0381: while (it.hasNext()) {
0382: Map.Entry entry = (Map.Entry) it.next();
0383: Object key = entry.getKey();
0384: Map map = (Map) entry.getValue();
0385: Stack s = new Stack();
0386: s.add(map);
0387: Object parentID = map.get(PARENT);
0388: Object hook = null;
0389: while (parentID != null) {
0390: hook = attrs.get(parentID);
0391: s.add(hook);
0392: parentID = ((Map) hook).get(PARENT);
0393: }
0394: Map newMap = new Hashtable();
0395: while (!s.isEmpty()) {
0396: newMap.putAll((Map) s.pop());
0397: }
0398: newMap.remove(PARENT);
0399: // Remove Empty values
0400: Iterator it2 = newMap.entrySet().iterator();
0401: while (it2.hasNext()) {
0402: entry = (Map.Entry) it2.next();
0403: if (entry.getValue() == EMPTY)
0404: it2.remove();
0405: }
0406: newAttrs.put(key, newMap);
0407: }
0408: return newAttrs;
0409: }
0410:
0411: public DefaultGraphCell parseCell(JGraph graph, Node node,
0412: Hashtable cells, ConnectionSet cs) {
0413: DefaultGraphCell cell = null;
0414: if (node.getNodeName().toLowerCase().equals("a")) {
0415: Node key = node.getAttributes().getNamedItem("id");
0416: Node type = node.getAttributes().getNamedItem("class");
0417: if (key != null && type != null) {
0418: Node value = node.getAttributes().getNamedItem("val");
0419: Object userObject = "";
0420: if (value != null)
0421: userObject = objs.get(value.getNodeValue());
0422: cell = createCell(graph, type.getNodeValue(),
0423: userObject);
0424: // attribute map
0425:
0426: if (cell != null) {
0427: cells.put(key.getNodeValue(), cell);
0428:
0429: DefaultGraphCell[] children = parseChildren(graph,
0430: node, cells, cs);
0431: for (int i = 0; i < children.length; i++)
0432: cell.add(children[i]);
0433:
0434: Node source = node.getAttributes().getNamedItem(
0435: "src");
0436: Node target = node.getAttributes().getNamedItem(
0437: "tgt");
0438: if (source != null) {
0439: ConnectionID cid = new ConnectionID(cell,
0440: source.getNodeValue(), true);
0441: connectionSetIDs.add(cid);
0442: }
0443: if (target != null) {
0444: ConnectionID cid = new ConnectionID(cell,
0445: target.getNodeValue(), false);
0446: connectionSetIDs.add(cid);
0447: }
0448:
0449: Node boundsNode = node.getAttributes()
0450: .getNamedItem("rect");
0451: Rectangle2D bounds = null;
0452: if (boundsNode != null) {
0453: Object rectangle = decodeValue(
0454: Rectangle2D.class, boundsNode
0455: .getNodeValue());
0456: if (rectangle instanceof Rectangle2D)
0457: bounds = (Rectangle2D) rectangle;
0458: }
0459:
0460: Node pointsNode = node.getAttributes()
0461: .getNamedItem("pts");
0462: List points = null;
0463: if (pointsNode != null) {
0464: Object pointList = decodeValue(List.class,
0465: pointsNode.getNodeValue());
0466: if (pointList instanceof List)
0467: points = (List) pointList;
0468: }
0469:
0470: Node attr = node.getAttributes().getNamedItem(
0471: "attr");
0472: String mapID = null;
0473: if (attr != null)
0474: mapID = attr.getNodeValue();
0475:
0476: if (mapID != null)
0477: delayedAttributes.add(new DelayedAttributeID(
0478: cell, bounds, points, mapID));
0479: }
0480: }
0481: }
0482: return cell;
0483: }
0484:
0485: public DefaultGraphCell[] parseChildren(JGraph graph, Node node,
0486: Hashtable cells, ConnectionSet cs) {
0487: List list = new LinkedList();
0488: for (int i = 0; i < node.getChildNodes().getLength(); i++) {
0489: Node child = node.getChildNodes().item(i);
0490: DefaultGraphCell cell = parseCell(graph, child, cells, cs);
0491: if (cell != null)
0492: list.add(cell);
0493: }
0494: DefaultGraphCell[] dgc = new DefaultGraphCell[list.size()];
0495: list.toArray(dgc);
0496: return dgc;
0497: }
0498:
0499: public Map parseAttrs(Node node) {
0500: Hashtable map = new Hashtable();
0501: for (int i = 0; i < node.getChildNodes().getLength(); i++) {
0502: Node child = node.getChildNodes().item(i);
0503: if (child.getNodeName().toLowerCase().equals("map")) {
0504: Node key = child.getAttributes().getNamedItem("id");
0505: Node pid = child.getAttributes().getNamedItem("pid");
0506: Map attrs = decodeMap(child, true, false);
0507: if (key != null && attrs.size() > 0) {
0508: if (pid != null)
0509: attrs.put(PARENT, pid.getNodeValue());
0510: map.put(key.getNodeValue(), attrs);
0511: }
0512: }
0513: }
0514: return map;
0515: }
0516:
0517: /**
0518: * Returns an attributeMap for the specified position and color.
0519: */
0520: public Map createDefaultAttributes() {
0521: // Create an AttributeMap
0522: AttributeMap map = new AttributeMap();
0523: // Set a Black Line Border (the Border-Attribute must be Null!)
0524: GraphConstants.setBorderColor(map, Color.black);
0525: // Return the Map
0526: return map;
0527: }
0528:
0529: public static class DelayedAttributeID {
0530:
0531: protected Object cell;
0532:
0533: protected Rectangle2D bounds;
0534:
0535: protected List points;
0536:
0537: protected String mapID;
0538:
0539: public DelayedAttributeID(Object cell, Rectangle2D bounds,
0540: List points, String mapID) {
0541: this .cell = cell;
0542: this .bounds = bounds;
0543: this .points = points;
0544: this .mapID = mapID;
0545: }
0546:
0547: /*
0548: * (non-Javadoc)
0549: */
0550: public Object getCell() {
0551: return cell;
0552: }
0553:
0554: /*
0555: * (non-Javadoc)
0556: */
0557: public Rectangle2D getBounds() {
0558: return bounds;
0559: }
0560:
0561: /*
0562: * (non-Javadoc)
0563: */
0564: public String getMapID() {
0565: return mapID;
0566: }
0567:
0568: /*
0569: * (non-Javadoc)
0570: */
0571: public List getPoints() {
0572: return points;
0573: }
0574:
0575: /*
0576: * (non-Javadoc)
0577: */
0578: public void setBounds(Rectangle2D rectangle) {
0579: bounds = rectangle;
0580: }
0581:
0582: /*
0583: * (non-Javadoc)
0584: */
0585: public void setCell(Object object) {
0586: cell = object;
0587: }
0588:
0589: /**
0590: * @param string
0591: */
0592: public void setMapID(String string) {
0593: mapID = string;
0594: }
0595:
0596: /*
0597: * (non-Javadoc)
0598: */
0599: public void setPoints(List list) {
0600: points = list;
0601: }
0602:
0603: }
0604:
0605: public static class ConnectionID {
0606:
0607: protected Object cell;
0608:
0609: protected String targetID;
0610:
0611: protected boolean source;
0612:
0613: public ConnectionID(Object cell, String targetID, boolean source) {
0614: this .cell = cell;
0615: this .targetID = targetID;
0616: this .source = source;
0617: }
0618:
0619: /*
0620: * (non-Javadoc)
0621: */
0622: public Object getCell() {
0623: return cell;
0624: }
0625:
0626: /*
0627: * (non-Javadoc)
0628: */
0629: public boolean isSource() {
0630: return source;
0631: }
0632:
0633: /*
0634: * (non-Javadoc)
0635: */
0636: public String getTargetID() {
0637: return targetID;
0638: }
0639:
0640: /**
0641: * @param object
0642: */
0643: public void setCell(Object object) {
0644: cell = object;
0645: }
0646:
0647: /**
0648: * @param b
0649: */
0650: public void setSource(boolean b) {
0651: source = b;
0652: }
0653:
0654: /**
0655: * @param string
0656: */
0657: public void setTargetID(String string) {
0658: targetID = string;
0659: }
0660:
0661: }
0662:
0663: public int getUserObjectID(Object object) {
0664: Integer index = (Integer) userObjectMap.get(object);
0665: if (index != null)
0666: return index.intValue();
0667: index = new Integer(userObjectMap.size() + 1);
0668: userObjectMap.put(object, index);
0669: return index.intValue();
0670: }
0671:
0672: public int getID(Object object) {
0673: Integer index = (Integer) cellMap.get(object);
0674: if (index != null)
0675: return index.intValue();
0676: index = new Integer(cellMap.size() + 1);
0677: cellMap.put(object, index);
0678: return index.intValue();
0679: }
0680:
0681: public class AttributeCollection {
0682:
0683: public List maps = new LinkedList();
0684:
0685: public int addMap(Map attr) {
0686: Iterator it = maps.iterator();
0687: Map storeMap = new Hashtable(attr);
0688: Map hook = storeMap;
0689: while (it.hasNext()) {
0690: Map ref = (Map) it.next();
0691: Map diff = diffMap(ref, attr);
0692: if (diff.size() < storeMap.size()) {
0693: hook = ref;
0694: storeMap = diff;
0695: }
0696: }
0697: if (storeMap.size() == 0 && hook != storeMap)
0698: return maps.indexOf(hook);
0699: if (hook != storeMap)
0700: storeMap.put(PARENT, hook);
0701: maps.add(storeMap);
0702: return maps.indexOf(storeMap);
0703: }
0704:
0705: public void clear() {
0706: maps.clear();
0707: }
0708:
0709: /**
0710: * Returns a new map that contains all (key, value)-pairs of
0711: * <code>newState</code> where either key is not used or value is
0712: * different for key in <code>oldState</code>. In other words, this
0713: * method removes the common entries from oldState and newState, and
0714: * returns the "difference" between the two.
0715: *
0716: * This method never returns null.
0717: */
0718: public Map diffMap(Map oldState, Map newState) {
0719: // Augment oldState
0720: Stack s = new Stack();
0721: s.add(oldState);
0722: Object hook = oldState.get(PARENT);
0723: while (hook instanceof Map) {
0724: s.add(hook);
0725: hook = ((Map) hook).get(PARENT);
0726: }
0727: oldState = new Hashtable();
0728: while (!s.isEmpty()) {
0729: oldState.putAll((Map) s.pop());
0730: }
0731: Map diff = new Hashtable();
0732: Iterator it = newState.entrySet().iterator();
0733: while (it.hasNext()) {
0734: Map.Entry entry = (Map.Entry) it.next();
0735: Object key = entry.getKey();
0736: Object oldValue = oldState.remove(key);
0737: if (key != PARENT) {
0738: Object newValue = entry.getValue();
0739: if (oldValue == null || !oldValue.equals(newValue))
0740: diff.put(key, newValue);
0741: }
0742: }
0743: it = oldState.keySet().iterator();
0744: while (it.hasNext()) {
0745: Object key = it.next();
0746: if (!oldState.get(key).equals(""))
0747: diff.put(key, "");
0748: }
0749: diff.remove(PARENT);
0750: return diff;
0751: }
0752:
0753: }
0754:
0755: //
0756: // Codec
0757: //
0758:
0759: protected String[] knownKeys = new String[] {
0760: GraphConstants.ABSOLUTEX, GraphConstants.ABSOLUTEY,
0761: GraphConstants.AUTOSIZE, GraphConstants.BACKGROUND,
0762: GraphConstants.GRADIENTCOLOR, GraphConstants.BEGINFILL,
0763: GraphConstants.BEGINSIZE, GraphConstants.BENDABLE,
0764: GraphConstants.BORDER, GraphConstants.BORDERCOLOR,
0765: GraphConstants.BOUNDS, GraphConstants.CHILDRENSELECTABLE,
0766: GraphConstants.CONNECTABLE, GraphConstants.CONSTRAINED,
0767: GraphConstants.DASHPATTERN, GraphConstants.DASHOFFSET,
0768: GraphConstants.DISCONNECTABLE, GraphConstants.EDITABLE,
0769: GraphConstants.ENDFILL, GraphConstants.ENDSIZE,
0770: GraphConstants.EXTRALABELS,
0771: GraphConstants.EXTRALABELPOSITIONS, GraphConstants.FONT,
0772: GraphConstants.FOREGROUND,
0773: GraphConstants.HORIZONTAL_ALIGNMENT,
0774: GraphConstants.VERTICAL_ALIGNMENT, GraphConstants.ICON,
0775: GraphConstants.INSET, GraphConstants.LABELALONGEDGE,
0776: GraphConstants.LABELPOSITION, GraphConstants.LINEBEGIN,
0777: GraphConstants.LINECOLOR, GraphConstants.LINEEND,
0778: GraphConstants.LINESTYLE, GraphConstants.LINEWIDTH,
0779: GraphConstants.MOVEABLE, GraphConstants.MOVEABLEAXIS,
0780: GraphConstants.MOVEHIDDENCHILDREN, GraphConstants.OFFSET,
0781: GraphConstants.OPAQUE, GraphConstants.POINTS,
0782: GraphConstants.RESIZE, GraphConstants.ROUTING,
0783: GraphConstants.SELECTABLE, GraphConstants.SIZE,
0784: GraphConstants.SIZEABLE, GraphConstants.SIZEABLEAXIS,
0785: GraphConstants.VALUE,
0786: GraphConstants.HORIZONTAL_TEXT_POSITION,
0787: GraphConstants.VERTICAL_TEXT_POSITION };
0788:
0789: protected Class[] keyTypes = new Class[] { Boolean.class, // ABSOLUTEX
0790: Boolean.class, Boolean.class, // ABSOLUTEY, AUTOSIZE
0791: Color.class, Color.class, // BACKGROUND, GRADIENTCOLOR,
0792: Boolean.class, Integer.class, // BEGINFILL, BEGINSIZE,
0793: Boolean.class, Border.class, // BENDABLE, BORDER,
0794: Color.class, Rectangle2D.class, // BORDERCOLOR, BOUNDS,
0795: Boolean.class, Boolean.class, // CHILDRENSELECTABLE, CONNECTABLE
0796: Boolean.class, float[].class, // CONSTRAINED, DASHPATTERN
0797: float.class, // DASHOFFSET
0798: Boolean.class, Boolean.class, // DISCONNECTABLE, EDITABLE,
0799: Boolean.class, Integer.class, // ENDFILL, ENDSIZE,
0800: Object[].class, Point[].class, // EXTRALABELS, EXTRALABELPOSITIONS
0801: Font.class, Color.class, // FONT, FOREGROUND,
0802: Integer.class, Integer.class, // HORIZONTAL_ALIGNMENT,
0803: // VERTICAL_ALIGNMENT
0804: Icon.class, Integer.class, // ICON, INSET,
0805: Boolean.class, Point.class, // LABELALONGEDGE, LABELPOSITION,
0806: Integer.class, Color.class, // LINEBEGIN, LINECOLOR,
0807: Integer.class, Integer.class, // LINEEND, LINESTYLE,
0808: Float.class, Boolean.class, // LINEWIDTH, MOVEABLE,
0809: Integer.class, Boolean.class, // MOVEABLEAXIS, MOVEHIDDENCHILDREN
0810: Point.class, Boolean.class, // OFFSET, OPAQUE,
0811: List.class, Boolean.class, Edge.Routing.class, // POINTS, RESIZE,
0812: // ROUTING,
0813: Boolean.class, // SELECTABLE
0814: Dimension.class, Boolean.class,// SIZE, SIZEABLE,
0815: Integer.class, // SIZEABLEAXIS
0816: Object.class, Integer.class, // VALUE, HORIZONTAL_TEXT_POSITION
0817: Integer.class }; // VERTICAL_TEXT_POSITION
0818:
0819: public Map decodeMap(Node node, boolean useKnownKeys,
0820: boolean URLdecodeValues) {
0821: Hashtable map = new Hashtable();
0822: for (int i = 0; i < node.getChildNodes().getLength(); i++) {
0823: Node child = node.getChildNodes().item(i);
0824: if (child.getNodeName().toLowerCase().equals("a")) {
0825: Node key = child.getAttributes().getNamedItem("key");
0826: Node value = child.getAttributes().getNamedItem("val");
0827: if (key != null && value != null) {
0828: String keyVal = key.getNodeValue().toString();
0829: Object valueS = value.getNodeValue().toString();
0830: if (useKnownKeys) {
0831: int index = -1;
0832: for (int j = 0; j < knownKeys.length; j++)
0833: if (keyVal.equals(knownKeys[j]))
0834: index = j;
0835: if (index != -1)
0836: valueS = decodeValue(keyTypes[index],
0837: valueS.toString());
0838: } else if (URLdecodeValues) {
0839:
0840: try {
0841: keyVal = URLDecoder.decode(keyVal
0842: .toString(), "UTF-8");
0843: valueS = URLDecoder.decode(valueS
0844: .toString(), "UTF-8");
0845: } catch (Exception e) {
0846: System.err.println(e.getMessage());
0847: }
0848: }
0849: if (valueS != null)
0850: map.put(keyVal, valueS);
0851: }
0852: }
0853: }
0854: return map;
0855: }
0856:
0857: public Map decodeUserObjects(Node node) {
0858: Hashtable map = new Hashtable();
0859: for (int i = 0; i < node.getChildNodes().getLength(); i++) {
0860: Node child = node.getChildNodes().item(i);
0861: if (child.getNodeName().toLowerCase().equals("a")) {
0862: Node key = child.getAttributes().getNamedItem("key");
0863: Node value = child.getAttributes().getNamedItem("val");
0864: if (key != null) {
0865: Map properties = decodeMap(child, false, true);
0866: String keyVal = key.getNodeValue().toString();
0867: String valueS = null;
0868: if (value != null) {
0869: valueS = value.getNodeValue().toString();
0870: if (valueS != null) {
0871: try {
0872: valueS = URLDecoder.decode(valueS
0873: .toString(), "UTF-8");
0874: } catch (Exception e) {
0875: System.err.println(e.getMessage());
0876: }
0877: }
0878: }
0879: if (valueS != null
0880: && (properties == null || properties
0881: .isEmpty()))
0882: map.put(keyVal, valueS);
0883: else {
0884: if (valueS != null
0885: && valueS.toString().length() > 0)
0886: properties.put(
0887: JGraphpadBusinessObject.valueKey,
0888: valueS);
0889: if (properties != null)
0890: map.put(keyVal, properties);
0891: }
0892: }
0893: }
0894: }
0895: return map;
0896: }
0897:
0898: public static final String[] tokenize(String s, String token) {
0899: StringTokenizer tokenizer = new StringTokenizer(s, token);
0900: String[] tok = new String[tokenizer.countTokens()];
0901: int i = 0;
0902: while (tokenizer.hasMoreElements()) {
0903: tok[i++] = tokenizer.nextToken();
0904: }
0905: return tok;
0906: }
0907:
0908: public Object decodeValue(Class key, String value) {
0909: if (key != String.class && key != Object.class
0910: && (value == null || value.equals("")))
0911: return EMPTY;
0912: if (key == Rectangle2D.class) {
0913: String[] tok = tokenize(value, ",");
0914: if (tok.length == 4) {
0915: double x = Double.parseDouble(tok[0]);
0916: double y = Double.parseDouble(tok[1]);
0917: double w = Double.parseDouble(tok[2]);
0918: double h = Double.parseDouble(tok[3]);
0919: return new Rectangle2D.Double(x, y, w, h);
0920: }
0921: } else if (key == List.class) { // FIX: Do not assume Points!
0922: List list = new LinkedList();
0923: String[] tok = tokenize(value, ",");
0924: for (int i = 0; i < tok.length; i = i + 2) {
0925: double x = Double.parseDouble(tok[i]);
0926: double y = Double.parseDouble(tok[i + 1]);
0927: AttributeMap dummyMap = new AttributeMap();
0928: Point2D point = dummyMap.createPoint(x, y);
0929: list.add(point);
0930: }
0931: return list;
0932: } else if (key == Font.class) {
0933: String[] tok = tokenize(value, ",");
0934: if (tok.length == 3) {
0935: String name = tok[0];
0936: int size = Integer.parseInt(tok[1]);
0937: int style = Integer.parseInt(tok[2]);
0938: return new Font(name, style, size);
0939: }
0940: } else if (key == Color.class) {
0941: String[] tok = tokenize(value, ",");
0942: if (tok.length == 3) {
0943: int r = Integer.parseInt(tok[0]);
0944: int g = Integer.parseInt(tok[1]);
0945: int b = Integer.parseInt(tok[2]);
0946: return new Color(r, g, b);
0947: }
0948: return new Color(Integer.parseInt(value));
0949: } else if (key == Point.class) {
0950: String[] tok = tokenize(value, ",");
0951: if (tok.length == 2) {
0952: int x = Integer.parseInt(tok[0]);
0953: int y = Integer.parseInt(tok[1]);
0954: return new Point(x, y);
0955: }
0956: } else if (key == float[].class) {
0957: String[] tok = tokenize(value, ",");
0958: float[] f = new float[tok.length];
0959: for (int i = 0; i < tok.length; i++)
0960: f[i] = Float.parseFloat(tok[i]);
0961: return f;
0962: } else if (key == Integer.class) {
0963: return new Integer(value);
0964: } else if (key == Border.class) {
0965: String[] tok = tokenize(value, ",");
0966: if (tok[0].equals("L")) { // LineBorder
0967: Color c = new Color(Integer.parseInt(tok[1]));
0968: int thickness = Integer.parseInt(tok[2]);
0969: return BorderFactory.createLineBorder(c, thickness);
0970: } else if (tok[0].equals("B")) { // BevelBorder
0971: int type = Integer.parseInt(tok[1]);
0972: return BorderFactory.createBevelBorder(type);
0973: } else if (tok[0].equals("S")) { // ShadowBorder
0974: return JGraphpadShadowBorder.sharedInstance;
0975: }
0976: return BorderFactory.createLineBorder(Color.black, 1);
0977: } else if (key == Boolean.class) {
0978: return new Boolean(value);
0979: } else if (key == Float.class) {
0980: return new Float(value);
0981: } else if (key == Icon.class) {
0982: try {
0983: return new JGraphpadImageIcon(new URL(value));
0984: } catch (Exception e) {
0985: System.err.println("Invalid URL: " + value);
0986: return new JGraphpadImageIcon(value);
0987: }
0988: } else if (key == Edge.Routing.class) {
0989: if (value.equals("simple"))
0990: return GraphConstants.ROUTING_SIMPLE;
0991: }
0992: return value;
0993: }
0994:
0995: /**
0996: * Bundle of all actions in this class.
0997: */
0998: public static class AllActions implements Bundle {
0999:
1000: /**
1001: * Holds the actions. All actions require an editor reference and are
1002: * therefore created at construction time.
1003: */
1004: public JGraphEditorAction actionImportJGX;
1005:
1006: /**
1007: * Constructs the action bundle for the enclosing class.
1008: */
1009: public AllActions(JGraphEditor editor) {
1010: Object vertexPrototype = editor.getSettings().getObject(
1011: JGraphpad.KEY_VERTEXPROTOTYPE);
1012: Object edgePrototype = editor.getSettings().getObject(
1013: JGraphpad.KEY_EDGEPROTOTYPE);
1014: actionImportJGX = new JGraphpadJGXAction(editor);
1015: actionImportJGX.putValue(KEY_VERTEXPROTOTYPE,
1016: vertexPrototype);
1017: actionImportJGX.putValue(KEY_EDGEPROTOTYPE, edgePrototype);
1018: }
1019:
1020: /*
1021: * (non-Javadoc)
1022: */
1023: public JGraphEditorAction[] getActions() {
1024: return new JGraphEditorAction[] { actionImportJGX };
1025: }
1026:
1027: /*
1028: * (non-Javadoc)
1029: */
1030: public void update() {
1031: Component component = getPermanentFocusOwner();
1032: boolean e = component instanceof JGraph;
1033: actionImportJGX.setEnabled(e);
1034: }
1035: }
1036:
1037: }
|