--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2012 Association for Decentralized Information Management in\r
+ * 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;\r
+\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Rectangle2D;\r
+import java.io.StringReader;\r
+import java.lang.reflect.Method;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.UUID;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.mutable.Variant;\r
+import org.simantics.scenegraph.utils.BufferedImage;\r
+import org.simantics.scl.runtime.function.Function1;\r
+import org.simantics.scl.runtime.function.FunctionImpl1;\r
+import org.simantics.utils.threads.IThreadWorkQueue;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+import com.kitfox.svg.SVGDiagram;\r
+import com.kitfox.svg.SVGException;\r
+import com.kitfox.svg.SVGUniverse;\r
+\r
+public class ScenegraphUtils {\r
+ \r
+ final static protected void dispatch(IThreadWorkQueue queue, final Runnable runnable) {\r
+ if(queue == null) runnable.run();\r
+ else if(queue.currentThreadAccess()) runnable.run();\r
+ else {\r
+ ThreadUtils.asyncExec(queue, new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ runnable.run();\r
+ }\r
+ });\r
+ }\r
+ }\r
+ \r
+ private static Class<?> getPropertyType(Method method) {\r
+ return (Class<?>)method.getGenericParameterTypes()[0]; \r
+ }\r
+ \r
+ private static Binding getPropertyBinding(Method method) {\r
+ try {\r
+ return Bindings.getBindingUnchecked(getPropertyType(method));\r
+ } catch (Throwable t) {\r
+ return null;\r
+ }\r
+ }\r
+ \r
+ private static Binding getGenericPropertyBinding(Method method) {\r
+ try {\r
+ Binding specific = getPropertyBinding(method);\r
+ return Bindings.getBinding(specific.type());\r
+ } catch (Throwable t) {\r
+ return null;\r
+ }\r
+ }\r
+\r
+ private static Method getSynchronizeMethod(Object node, String propertyName) {\r
+ try {\r
+ String methodName = "synchronize" + propertyName.substring(0,1).toUpperCase() + propertyName.substring(1);\r
+ for(Method method : node.getClass().getMethods()) {\r
+ if(method.getName().equals(methodName)) return method;\r
+ }\r
+ } catch (SecurityException e) {\r
+ e.printStackTrace();\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ public static Function1<Object, Boolean> getMethodPropertyFunction(final IThreadWorkQueue queue, final Object node, final String propertyName) {\r
+ \r
+ final Method synchronizeMethod = getSynchronizeMethod(node, propertyName);\r
+ if(synchronizeMethod == null) throw new NodeException("Did not find synchronize method for property '" + propertyName + "'");\r
+ final Class<?> type = getPropertyType(synchronizeMethod);\r
+ final Binding binding = getPropertyBinding(synchronizeMethod);\r
+ final Binding genericBinding = getGenericPropertyBinding(synchronizeMethod);\r
+\r
+ return new FunctionImpl1<Object, Boolean>() {\r
+\r
+ @Override\r
+ public Boolean apply(final Object value) {\r
+ \r
+ dispatch(queue, new Runnable() {\r
+\r
+ @Override\r
+ public void run() {\r
+ \r
+ try {\r
+ if(type.isPrimitive()) {\r
+ synchronizeMethod.invoke(node, value);\r
+ } else if (value == null) {\r
+ synchronizeMethod.invoke(node, value);\r
+ } else if(type.isInstance(value)) {\r
+ synchronizeMethod.invoke(node, value);\r
+ } else if (type.isArray()) {\r
+ synchronizeMethod.invoke(node, value);\r
+ } else {\r
+ Object instance = binding.createDefaultUnchecked();\r
+ binding.readFrom(genericBinding, value, instance);\r
+ synchronizeMethod.invoke(node, instance);\r
+ }\r
+ } catch (IllegalArgumentException e1) {\r
+ e1.printStackTrace();\r
+ } catch (IllegalAccessException e1) {\r
+ e1.printStackTrace();\r
+ } catch (BindingException e) {\r
+ e.printStackTrace();\r
+ } catch (Throwable t) {\r
+ t.printStackTrace();\r
+ }\r
+ }\r
+ \r
+ });\r
+ return false;\r
+ }\r
+\r
+ };\r
+ \r
+ }\r
+\r
+ public static SVGDiagram loadSVGDiagram(SVGUniverse univ, String text) throws SVGException {\r
+ SVGDiagram diagram = univ.getDiagram(univ.loadSVG(new StringReader(text), UUID.randomUUID().toString()), false);\r
+ diagram.setIgnoringClipHeuristic(true);\r
+ return diagram;\r
+ }\r
+\r
+ public static java.awt.image.BufferedImage loadSVG(SVGUniverse univ, String text, double scale) throws SVGException {\r
+ SVGDiagram diagram = loadSVGDiagram(univ, text);\r
+ return paintSVG(diagram, scale);\r
+ }\r
+\r
+ public static java.awt.image.BufferedImage paintSVG(SVGDiagram diagram, double scale) throws SVGException {\r
+ BufferedImage bi = new BufferedImage(diagram);\r
+ bi.paintToBuffer(AffineTransform.getScaleInstance(scale, scale), 0);\r
+ return bi.getBuffer();\r
+ }\r
+\r
+ public static java.awt.image.BufferedImage paintSVG(SVGDiagram diagram, AffineTransform transform, float margin) throws SVGException {\r
+ BufferedImage bi = new BufferedImage(diagram);\r
+ bi.paintToBuffer(transform, margin);\r
+ return bi.getBuffer();\r
+ }\r
+\r
+ /*\r
+ * NOTE! This is not re-entrant\r
+ */\r
+ public static synchronized java.awt.image.BufferedImage loadSVG(SVGUniverse univ, String text, int maxDimension) throws SVGException {\r
+ SVGDiagram diagram = univ.getDiagram(univ.loadSVG(new StringReader(text), UUID.randomUUID().toString()), false);\r
+ diagram.setIgnoringClipHeuristic(true);\r
+ BufferedImage bi = new BufferedImage(diagram);\r
+ Rectangle2D bounds = diagram.getViewRect();\r
+ double xScale = (double)maxDimension / bounds.getWidth();\r
+ double yScale = (double)maxDimension / bounds.getHeight();\r
+ double scale = Math.min(xScale, yScale);\r
+ bi.paintToBuffer(AffineTransform.getScaleInstance(scale, scale), 0);\r
+ return bi.getBuffer();\r
+ }\r
+ \r
+ private static Variant extractVariant(Object value) {\r
+ if(value instanceof Variant) return (Variant)value;\r
+ else return Variant.ofInstance(value);\r
+ }\r
+ \r
+ public static Map<String, Variant> parameters(Object ... keyValuePairs) {\r
+ assert keyValuePairs.length % 2 == 0;\r
+ HashMap<String, Variant> result = new HashMap<String, Variant>();\r
+ for(int i=0;i<keyValuePairs.length;i+=2) {\r
+ String key = (String)keyValuePairs[i];\r
+ Variant value = extractVariant(keyValuePairs[i+1]);\r
+ result.put(key, value);\r
+ }\r
+ return result;\r
+ }\r
+ \r
+}\r