--- /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.g2d.canvas.impl;\r
+\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.lang.reflect.Method;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import org.simantics.utils.datastructures.hints.IHintListener;\r
+import org.simantics.utils.datastructures.hints.IHintObservable;\r
+import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
+\r
+/**\r
+ * @author Toni Kalajainen\r
+ */\r
+public class HintReflection {\r
+\r
+ private final static HintListenerDefinition[] EMPTY = new HintListenerDefinition[0]; \r
+ \r
+ @Retention(RetentionPolicy.RUNTIME)\r
+ @Target(ElementType.METHOD)\r
+ public static @interface HintListener {\r
+ Class<?> Class();\r
+ String Field(); \r
+ }\r
+ \r
+ /**\r
+ * Scans an object for reflections of hint listeners \r
+ * <p>\r
+ * Example:\r
+ * \r
+ * @HintListener(Class=Hints.class, Field="KEY_CANVAS_TRANSFORM")\r
+ * public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {\r
+ * ...\r
+ * }\r
+ * @HintListener(Class=Hints.class, Field="KEY_CANVAS_TRANSFORM")\r
+ * public void hintRemoved(IHintObservable sender, Key key, Object oldValue) { \r
+ * ...\r
+ * }\r
+ * \r
+ * @param obj object to scan\r
+ * @return an array of painters and their priorities\r
+ */\r
+ public static HintListenerDefinition[] getDependencies(final Object obj)\r
+ {\r
+ Map<Key, HintListenerDefinition> result = new HashMap<Key, HintListenerDefinition>();\r
+ Class<?> clazz = obj.getClass();\r
+ _add(obj, clazz, result);\r
+ //if (result==null) return EMPTY;\r
+ return result.values().toArray(EMPTY);\r
+ }\r
+\r
+ private static void _add(final Object obj, Class<?> clazz, Map<Key, HintListenerDefinition> result)\r
+ {\r
+ try {\r
+ for (final Method m : clazz.getDeclaredMethods()) {\r
+ HintListener anno = (HintListener) m\r
+ .getAnnotation(HintListener.class);\r
+ if (anno == null)\r
+ continue;\r
+\r
+ Class<?> keyContainerClass = anno.Class();\r
+ assert (keyContainerClass != null);\r
+ String fieldName = anno.Field();\r
+ assert (fieldName != null);\r
+ Field field;\r
+ field = keyContainerClass.getField(fieldName);\r
+ assert (field != null);\r
+ field.setAccessible(true);\r
+ Object value = field.get(field != null);\r
+ assert (value != null);\r
+ assert (value instanceof Key);\r
+ Key key = (Key) value;\r
+\r
+ Class<?> returnType = m.getReturnType();\r
+ assert (returnType == void.class);\r
+ Class<?>[] params = m.getParameterTypes();\r
+ assert (params.length == 4 || params.length == 3);\r
+ assert (params[0].equals(IHintObservable.class));\r
+ assert (params[1].equals(Key.class));\r
+ assert (params[2].equals(Object.class));\r
+\r
+ if (params.length == 4) \r
+ assert (params[3].equals(Object.class));\r
+\r
+ HintListenerDefinition def = result.get(key);\r
+ if (def==null) {\r
+ def = new HintListenerDefinition(key, obj);\r
+ result.put(key, def);\r
+ } \r
+ \r
+ m.setAccessible(true); \r
+ if (params.length == 4)\r
+ def.changedHandlerMethod = m;\r
+ else\r
+ def.removedHandlerMethod = m;\r
+ }\r
+ } catch (SecurityException e) {\r
+ throw new Error(e);\r
+ } catch (NoSuchFieldException e) {\r
+ throw new Error(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new Error(e);\r
+ }\r
+ /*\r
+ for (final Field f : clazz.getDeclaredFields()) {\r
+ Class c = f.getType();\r
+ Dependency dep = (Dependency) f.getAnnotation(Dependency.class);\r
+ Reference ref = (Reference) f.getAnnotation(Reference.class);\r
+ if (dep==null && ref==null) continue;\r
+ assert(ICanvasParticipant.class.isAssignableFrom( c )); \r
+ assert(!(dep!=null && ref!=null));\r
+ ReferenceDefinition rd = new ReferenceDefinition();\r
+ rd.dependency = dep!=null;\r
+ rd.field = f;\r
+ rd.requirement = c;\r
+ f.setAccessible(true);\r
+ result.add(rd);\r
+ }\r
+ */\r
+ \r
+ Class<?> superClass = clazz.getSuperclass();\r
+ if (superClass!=null)\r
+ _add(obj, superClass, result);\r
+ }\r
+\r
+ \r
+ public final static class HintListenerDefinition implements IHintListener {\r
+ public final Key key;\r
+ public final Object object;\r
+ public Method changedHandlerMethod;\r
+ public Method removedHandlerMethod;\r
+ \r
+ public HintListenerDefinition(Key key, Object object) {\r
+ this.key = key;\r
+ this.object = object;\r
+ }\r
+ \r
+ @Override\r
+ public void hintChanged(IHintObservable sender, Key key,\r
+ Object oldValue, Object newValue) {\r
+ if (changedHandlerMethod==null) return;\r
+ try {\r
+ changedHandlerMethod.invoke(object, sender, key, oldValue, newValue);\r
+ } catch (IllegalArgumentException e) {\r
+ throw new Error(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new Error(e);\r
+ } catch (InvocationTargetException e) {\r
+ throw new RuntimeException(e);\r
+ }\r
+ }\r
+ @Override\r
+ public void hintRemoved(IHintObservable sender, Key key, Object oldValue) {\r
+ if (removedHandlerMethod==null) return;\r
+ try {\r
+ removedHandlerMethod.invoke(object, sender, key, oldValue);\r
+ } catch (IllegalArgumentException e) {\r
+ throw new Error(e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new Error(e);\r
+ } catch (InvocationTargetException e) {\r
+ throw new RuntimeException(e.getCause());\r
+ }\r
+ }\r
+ \r
+ \r
+ } \r
+ \r
+}\r