/******************************************************************************* * Copyright (c) 2012 Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.scenegraph; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.io.StringReader; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.UUID; import org.simantics.databoard.Bindings; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.error.BindingException; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.scenegraph.utils.BufferedImage; import org.simantics.scl.runtime.function.Function1; import org.simantics.scl.runtime.function.FunctionImpl1; import org.simantics.utils.threads.IThreadWorkQueue; import org.simantics.utils.threads.ThreadUtils; import com.kitfox.svg.SVGDiagram; import com.kitfox.svg.SVGException; import com.kitfox.svg.SVGUniverse; public class ScenegraphUtils { final static protected void dispatch(IThreadWorkQueue queue, final Runnable runnable) { if(queue == null) runnable.run(); else if(queue.currentThreadAccess()) runnable.run(); else { ThreadUtils.asyncExec(queue, new Runnable() { @Override public void run() { runnable.run(); } }); } } private static Class getPropertyType(Method method) { return (Class)method.getGenericParameterTypes()[0]; } private static Binding getPropertyBinding(Method method) { try { return Bindings.getBindingUnchecked(getPropertyType(method)); } catch (Throwable t) { return null; } } private static Binding getGenericPropertyBinding(Method method) { try { Binding specific = getPropertyBinding(method); return Bindings.getBinding(specific.type()); } catch (Throwable t) { return null; } } private static Method getSynchronizeMethod(Object node, String propertyName) { try { String methodName = "synchronize" + propertyName.substring(0,1).toUpperCase() + propertyName.substring(1); for(Method method : node.getClass().getMethods()) { if(method.getName().equals(methodName)) return method; } } catch (SecurityException e) { e.printStackTrace(); } return null; } public static Function1 getMethodPropertyFunction(final IThreadWorkQueue queue, final Object node, final String propertyName) { final Method synchronizeMethod = getSynchronizeMethod(node, propertyName); if(synchronizeMethod == null) throw new NodeException("Did not find synchronize method for property '" + propertyName + "'"); final Class type = getPropertyType(synchronizeMethod); final Binding binding = getPropertyBinding(synchronizeMethod); final Binding genericBinding = getGenericPropertyBinding(synchronizeMethod); return new FunctionImpl1() { @Override public Boolean apply(final Object value) { dispatch(queue, new Runnable() { @Override public void run() { try { if(type.isPrimitive()) { synchronizeMethod.invoke(node, value); } else if (value == null) { synchronizeMethod.invoke(node, value); } else if(type.isInstance(value)) { synchronizeMethod.invoke(node, value); } else if (type.isArray()) { synchronizeMethod.invoke(node, value); } else { Object instance = binding.createDefaultUnchecked(); binding.readFrom(genericBinding, value, instance); synchronizeMethod.invoke(node, instance); } } catch (IllegalArgumentException e1) { e1.printStackTrace(); } catch (IllegalAccessException e1) { e1.printStackTrace(); } catch (BindingException e) { e.printStackTrace(); } catch (Throwable t) { t.printStackTrace(); } } }); return false; } }; } public static SVGDiagram loadSVGDiagram(SVGUniverse univ, String text) throws SVGException { SVGDiagram diagram = univ.getDiagram(univ.loadSVG(new StringReader(text), UUID.randomUUID().toString()), false); diagram.setIgnoringClipHeuristic(true); return diagram; } public static java.awt.image.BufferedImage loadSVG(SVGUniverse univ, String text, double scale) throws SVGException { SVGDiagram diagram = loadSVGDiagram(univ, text); return paintSVG(diagram, scale); } public static java.awt.image.BufferedImage paintSVG(SVGDiagram diagram, double scale) throws SVGException { BufferedImage bi = new BufferedImage(diagram); bi.paintToBuffer(AffineTransform.getScaleInstance(scale, scale), 0); return bi.getBuffer(); } public static java.awt.image.BufferedImage paintSVG(SVGDiagram diagram, AffineTransform transform, float margin) throws SVGException { BufferedImage bi = new BufferedImage(diagram); bi.paintToBuffer(transform, margin); return bi.getBuffer(); } /* * NOTE! This is not re-entrant */ public static synchronized java.awt.image.BufferedImage loadSVG(SVGUniverse univ, String text, int maxDimension) throws SVGException { SVGDiagram diagram = univ.getDiagram(univ.loadSVG(new StringReader(text), UUID.randomUUID().toString()), false); diagram.setIgnoringClipHeuristic(true); BufferedImage bi = new BufferedImage(diagram); Rectangle2D bounds = diagram.getViewRect(); double xScale = (double)maxDimension / bounds.getWidth(); double yScale = (double)maxDimension / bounds.getHeight(); double scale = Math.min(xScale, yScale); bi.paintToBuffer(AffineTransform.getScaleInstance(scale, scale), 0); return bi.getBuffer(); } private static Variant extractVariant(Object value) { if(value instanceof Variant) return (Variant)value; else return Variant.ofInstance(value); } public static Map parameters(Object ... keyValuePairs) { assert keyValuePairs.length % 2 == 0; HashMap result = new HashMap(); for(int i=0;i