--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.scenegraph.tests;\r
+\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.simantics.scenegraph.INode;\r
+import org.simantics.scenegraph.ParentNode;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+import org.simantics.scenegraph.g2d.G2DSceneGraph;\r
+import org.simantics.scenegraph.g2d.IG2DNode;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class SceneGraphComparator {\r
+\r
+ private Map<INode, INode> aChildrenDiffer = new HashMap<INode, INode>();\r
+ private Map<INode, INode> bChildrenDiffer = new HashMap<INode, INode>();\r
+ private Set<Pair<INode, INode>> different = new HashSet<Pair<INode, INode>>();\r
+\r
+ private INode a;\r
+ private INode b;\r
+\r
+ public SceneGraphComparator(INode a, INode b) {\r
+ this.a = a;\r
+ this.b = b;\r
+ }\r
+\r
+ public void analyze() {\r
+ analyze(a.getParent(), a, b.getParent(), b);\r
+ }\r
+\r
+ public boolean equal() {\r
+ return aChildrenDiffer.isEmpty() && bChildrenDiffer.isEmpty() && different.isEmpty();\r
+ }\r
+\r
+ private void analyze(ParentNode<?> pa, INode a, ParentNode<?> pb, INode b) {\r
+ if (a == b)\r
+ return;\r
+ if (!equals(a, b)) {\r
+ different.add(Pair.<INode, INode>make(a, b));\r
+ if (pa != null && pb != null) {\r
+ aChildrenDiffer.put(pa, pb);\r
+ bChildrenDiffer.put(pb, pa);\r
+ }\r
+ return;\r
+ }\r
+ if (a instanceof ParentNode<?>) {\r
+ ParentNode<?> ppa = (ParentNode<?>) a;\r
+ ParentNode<?> ppb = (ParentNode<?>) b;\r
+\r
+ Collection<String> aids = ppa.getNodeIds();\r
+ Collection<String> bids = ppb.getNodeIds();\r
+ if (!aids.equals(bids)) {\r
+ aChildrenDiffer.put(ppa, ppb);\r
+ bChildrenDiffer.put(ppb, ppa);\r
+ }\r
+\r
+ // Both nodes have an identically named set of child nodes.\r
+ if (a instanceof G2DParentNode) {\r
+ IG2DNode[] sac = ((G2DParentNode) a).getSortedNodes();\r
+ IG2DNode[] sbc = ((G2DParentNode) b).getSortedNodes();\r
+ for (int i = 0; i < sac.length; ++i) {\r
+ analyze(ppa, sac[i], ppb, sbc[i]);\r
+ }\r
+ } else {\r
+ for (String id : aids) {\r
+ INode ac = ppa.getNode(id);\r
+ INode bc = ppb.getNode(id);\r
+ analyze(ppa, ac, ppb, bc);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ private boolean equals(INode a, INode b) {\r
+ Class<?> clazz = a.getClass();\r
+ if (!clazz.equals(b.getClass()))\r
+ return false;\r
+\r
+ // TODO: use reflection to compare field by field\r
+ // ignore transient fields\r
+ // ignore Node.id field\r
+\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ if (equal())\r
+ return "no differences";\r
+ StringBuilder sb = new StringBuilder();\r
+ sb.append("Differences between nodes:\n");\r
+ for (Pair<INode, INode> p : different) {\r
+ sb.append(p.first.getClass().getSimpleName()).append(p.first).append("\nvs.\n").append(p.second.getClass().getSimpleName()).append(p.second).append("\n");\r
+ }\r
+ return sb.toString();\r
+ }\r
+\r
+ public static void main(String[] args) {\r
+ G2DSceneGraph sg1 = new G2DSceneGraph();\r
+ G2DSceneGraph sg2 = new G2DSceneGraph();\r
+\r
+ SceneGraphComparator sgc = new SceneGraphComparator(sg1, sg1);\r
+ sgc.analyze();\r
+ System.out.println(sgc);\r
+ sgc = new SceneGraphComparator(sg1, sg2);\r
+ sgc.analyze();\r
+ System.out.println(sgc);\r
+ }\r
+\r
+}\r