-/*******************************************************************************\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.element;\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.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Collection;\r
-import java.util.HashSet;\r
-import java.util.Set;\r
-\r
-import org.simantics.g2d.diagram.impl.AbstractHandlerClass;\r
-import org.simantics.g2d.element.handler.ElementHandler;\r
-import org.simantics.g2d.element.handler.HandleMouseEvent;\r
-import org.simantics.g2d.element.handler.InternalSize;\r
-import org.simantics.g2d.element.handler.Move;\r
-import org.simantics.g2d.element.handler.Rotate;\r
-import org.simantics.g2d.element.handler.SceneGraph;\r
-import org.simantics.g2d.element.handler.Transform;\r
-import org.simantics.g2d.element.handler.Validator;\r
-\r
-/**\r
- * ElementClass is a class of elements. It consists of element handlers.\r
- * Each handler contributes functions to some aspects of the diagram.\r
- * <p>\r
- * Handlers are ordered. For instance, if there are multiple Paint handlers,\r
- * the paint order is determined by the order of the handlers in the class.\r
- * <p>\r
- * The minimum requirement is implementation for the following interfaces:\r
- * @see Transform\r
- * @see InternalSize\r
- * \r
- * Typical element class has the following implementations:\r
- * @see Transform\r
- * @see SceneGraph\r
- * @see Move\r
- * @see Rotate\r
- * @see InternalSize or @see Scale\r
- * @see Selectable\r
- * \r
- * Interactive element classes have implementation to:\r
- * @see HandleMouseEvent\r
- * \r
- * See also:\r
- * @see Validator\r
- * \r
- * See package org.simantics.g2d.element.handler for handler interfaces.\r
- * See package org.simantics.g2d.element.handler.impl for common implementations.\r
- * Note that some implementations implement several interface. Also note that\r
- * some handler interfaces may be implemented several times (e.g. Paint,\r
- * Validator, ToolTip, Pick). In contrast, some handlers may have at most one\r
- * implementation, such as Transform, Move, Rotate, Scale, Size.\r
- * <p>\r
- * Tip: Use SymbolUtil (CanvasParticipant) to manage graphical resources (images).\r
- * \r
- * @author Toni Kalajainen\r
- */\r
-public final class ElementClass extends AbstractHandlerClass<ElementHandler> {\r
-\r
- private static final long serialVersionUID = -446421782709451743L;\r
-\r
- /** Handler with this annotation may have at most one implementation */\r
- @Retention(RetentionPolicy.RUNTIME)\r
- @Target(ElementType.TYPE)\r
- public static @interface Single {}\r
-\r
- /** Handler with this annotation must be implemented (once or more) */\r
- @Retention(RetentionPolicy.RUNTIME)\r
- @Target(ElementType.TYPE)\r
- public static @interface Required {}\r
-\r
- private static final Class<?>[] REQUIRED_HANDLERS =\r
- new Class<?>[] {Transform.class, InternalSize.class};\r
-\r
- private String id = "";\r
-\r
- /**\r
- * Compile new element class from a set of handler\r
- * @param contributions\r
- * @return\r
- */\r
- public static ElementClass compile(Collection<ElementHandler> contributions)\r
- {\r
- assertClassValid(contributions);\r
- return new ElementClass(contributions);\r
- }\r
-\r
- public static ElementClass compile(Collection<ElementHandler> contributions, boolean check)\r
- {\r
- if(check) assertClassValid(contributions);\r
- return new ElementClass(contributions, check);\r
- }\r
-\r
- /**\r
- * Compile new element class from a set of handler\r
- * @param contributions\r
- * @return\r
- */\r
- public static ElementClass compile(ElementHandler... contributions)\r
- {\r
- if (contributions.length == 0)\r
- return new ElementClass(Arrays.asList(contributions));\r
- ArrayList<ElementHandler> al = new ArrayList<ElementHandler>(contributions.length);\r
- for (ElementHandler eh : contributions)\r
- al.add(eh);\r
- return new ElementClass(al);\r
- }\r
-\r
- ElementClass(Collection<ElementHandler> contributions) {\r
- super(contributions);\r
- assertClassValid(contributions);\r
- }\r
-\r
- ElementClass(Collection<ElementHandler> contributions, boolean check) {\r
- super(contributions);\r
- if(check) assertClassValid(contributions);\r
- }\r
-\r
- /**\r
- * Validates that handler is valid.\r
- * \r
- * @param contributions\r
- * @return\r
- */\r
- public static void assertClassValid(Collection<ElementHandler> contributions)\r
- {\r
- // 1. Verify requirements\r
- nextRequirement:\r
- for (Class<?> requiredClass : REQUIRED_HANDLERS) {\r
- for (ElementHandler eh : contributions)\r
- if (requiredClass.isInstance(eh))\r
- continue nextRequirement;\r
- throw new Error("Element class does not implement "+requiredClass.getName());\r
- }\r
-\r
- // 2. Verify singletons\r
- // 2.1. Collect implemented handlers\r
- Set<Class<ElementHandler>> implementedHandlerInterfaces = new HashSet<Class<ElementHandler>>();\r
- for (ElementHandler eh : contributions)\r
- _traverseElementHandlerInterfaces(eh.getClass(), implementedHandlerInterfaces);\r
-\r
- // 2.2. Verify singletons are implemented only once\r
- for (Class<ElementHandler> ehc : implementedHandlerInterfaces)\r
- {\r
- if (!_isSingletonHandler(ehc)) continue;\r
- int implementationCount = 0;\r
- for (ElementHandler eh : contributions)\r
- {\r
- if (!ehc.isInstance(eh)) continue;\r
- implementationCount++;\r
- }\r
- if (implementationCount>1)\r
- throw new Error("Element class has "+implementationCount+" implementations to a _singleton_ element handler \""+ehc.getName()+"\": " + contributions);\r
- }\r
- }\r
-\r
- private static boolean _isSingletonHandler(Class<ElementHandler> elementHandlerClass)\r
- {\r
- Single s = elementHandlerClass.getAnnotation(Single.class);\r
- return s != null;\r
- }\r
-\r
- @SuppressWarnings("unchecked")\r
- private static void _traverseElementHandlerInterfaces(Class<?> clazz, Collection<Class<ElementHandler>> result)\r
- {\r
- // Add implemented interfaces (that are inherited from ElementHandler)\r
- for (Class<?> inf : clazz.getInterfaces())\r
- {\r
- if (!ElementHandler.class.isAssignableFrom(inf)) continue;\r
- result.add((Class<ElementHandler>)inf);\r
- }\r
-\r
- // Traverse parent\r
- Class<?> superType = clazz.getSuperclass();\r
- if (superType!=null)\r
- _traverseElementHandlerInterfaces(superType, result);\r
- }\r
-\r
- @Override\r
- public String toString() {\r
- if (!id.isEmpty())\r
- return id;\r
-\r
- StringBuilder sb = new StringBuilder();\r
- sb.append("[");\r
- int i=0;\r
- for (ElementHandler eh : super.getAll())\r
- {\r
- if (i++>0) sb.append(", ");\r
- sb.append( eh.getClass().getSimpleName() );\r
- }\r
- sb.append("]");\r
- return sb.toString();\r
- }\r
-\r
- public ElementClass newClassWith(ElementHandler... addedHandlers) {\r
- if (addedHandlers.length == 0)\r
- return this;\r
- Collection<ElementHandler> newHandlers = new ArrayList<ElementHandler>(getAll());\r
- for (ElementHandler h : addedHandlers)\r
- newHandlers.add(h);\r
- return ElementClass.compile(newHandlers).setId(id);\r
- }\r
-\r
- public ElementClass newClassWith(boolean check, ElementHandler... addedHandlers) {\r
- if (addedHandlers.length == 0)\r
- return this;\r
- Collection<ElementHandler> newHandlers = new ArrayList<ElementHandler>(getAll());\r
- for (ElementHandler h : addedHandlers)\r
- newHandlers.add(h);\r
- return ElementClass.compile(newHandlers, check).setId(id);\r
- }\r
-\r
- public ElementClass newClassWith(Collection<ElementHandler> addedHandlers) {\r
- if (addedHandlers.isEmpty())\r
- return this;\r
- Collection<ElementHandler> newHandlers = new ArrayList<ElementHandler>(getAll());\r
- newHandlers.addAll(addedHandlers);\r
- return ElementClass.compile(newHandlers).setId(id);\r
- }\r
-\r
- public ElementClass setId(String id) {\r
- this.id = id;\r
- return this;\r
- }\r
-\r
- public String getId() {\r
- return id;\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 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.g2d.element;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.simantics.g2d.diagram.impl.AbstractHandlerClass;
+import org.simantics.g2d.element.handler.ElementHandler;
+import org.simantics.g2d.element.handler.HandleMouseEvent;
+import org.simantics.g2d.element.handler.InternalSize;
+import org.simantics.g2d.element.handler.Move;
+import org.simantics.g2d.element.handler.Rotate;
+import org.simantics.g2d.element.handler.SceneGraph;
+import org.simantics.g2d.element.handler.Transform;
+import org.simantics.g2d.element.handler.Validator;
+
+/**
+ * ElementClass is a class of elements. It consists of element handlers.
+ * Each handler contributes functions to some aspects of the diagram.
+ * <p>
+ * Handlers are ordered. For instance, if there are multiple Paint handlers,
+ * the paint order is determined by the order of the handlers in the class.
+ * <p>
+ * The minimum requirement is implementation for the following interfaces:
+ * @see Transform
+ * @see InternalSize
+ *
+ * Typical element class has the following implementations:
+ * @see Transform
+ * @see SceneGraph
+ * @see Move
+ * @see Rotate
+ * @see InternalSize or @see Scale
+ * @see Selectable
+ *
+ * Interactive element classes have implementation to:
+ * @see HandleMouseEvent
+ *
+ * See also:
+ * @see Validator
+ *
+ * See package org.simantics.g2d.element.handler for handler interfaces.
+ * See package org.simantics.g2d.element.handler.impl for common implementations.
+ * Note that some implementations implement several interface. Also note that
+ * some handler interfaces may be implemented several times (e.g. Paint,
+ * Validator, ToolTip, Pick). In contrast, some handlers may have at most one
+ * implementation, such as Transform, Move, Rotate, Scale, Size.
+ * <p>
+ * Tip: Use SymbolUtil (CanvasParticipant) to manage graphical resources (images).
+ *
+ * @author Toni Kalajainen
+ */
+public final class ElementClass extends AbstractHandlerClass<ElementHandler> {
+
+ private static final long serialVersionUID = -446421782709451743L;
+
+ /** Handler with this annotation may have at most one implementation */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ public static @interface Single {}
+
+ /** Handler with this annotation must be implemented (once or more) */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ public static @interface Required {}
+
+ private static final Class<?>[] REQUIRED_HANDLERS =
+ new Class<?>[] {Transform.class, InternalSize.class};
+
+ private String id = "";
+
+ /**
+ * Compile new element class from a set of handler
+ * @param contributions
+ * @return
+ */
+ public static ElementClass compile(Collection<ElementHandler> contributions)
+ {
+ assertClassValid(contributions);
+ return new ElementClass(contributions);
+ }
+
+ public static ElementClass compile(Collection<ElementHandler> contributions, boolean check)
+ {
+ if(check) assertClassValid(contributions);
+ return new ElementClass(contributions, check);
+ }
+
+ /**
+ * Compile new element class from a set of handler
+ * @param contributions
+ * @return
+ */
+ public static ElementClass compile(ElementHandler... contributions)
+ {
+ if (contributions.length == 0)
+ return new ElementClass(Arrays.asList(contributions));
+ ArrayList<ElementHandler> al = new ArrayList<ElementHandler>(contributions.length);
+ for (ElementHandler eh : contributions)
+ al.add(eh);
+ return new ElementClass(al);
+ }
+
+ ElementClass(Collection<ElementHandler> contributions) {
+ super(contributions);
+ assertClassValid(contributions);
+ }
+
+ ElementClass(Collection<ElementHandler> contributions, boolean check) {
+ super(contributions);
+ if(check) assertClassValid(contributions);
+ }
+
+ /**
+ * Validates that handler is valid.
+ *
+ * @param contributions
+ * @return
+ */
+ public static void assertClassValid(Collection<ElementHandler> contributions)
+ {
+ // 1. Verify requirements
+ nextRequirement:
+ for (Class<?> requiredClass : REQUIRED_HANDLERS) {
+ for (ElementHandler eh : contributions)
+ if (requiredClass.isInstance(eh))
+ continue nextRequirement;
+ throw new Error("Element class does not implement "+requiredClass.getName());
+ }
+
+ // 2. Verify singletons
+ // 2.1. Collect implemented handlers
+ Set<Class<ElementHandler>> implementedHandlerInterfaces = new HashSet<Class<ElementHandler>>();
+ for (ElementHandler eh : contributions)
+ _traverseElementHandlerInterfaces(eh.getClass(), implementedHandlerInterfaces);
+
+ // 2.2. Verify singletons are implemented only once
+ for (Class<ElementHandler> ehc : implementedHandlerInterfaces)
+ {
+ if (!_isSingletonHandler(ehc)) continue;
+ int implementationCount = 0;
+ for (ElementHandler eh : contributions)
+ {
+ if (!ehc.isInstance(eh)) continue;
+ implementationCount++;
+ }
+ if (implementationCount>1)
+ throw new Error("Element class has "+implementationCount+" implementations to a _singleton_ element handler \""+ehc.getName()+"\": " + contributions);
+ }
+ }
+
+ private static boolean _isSingletonHandler(Class<ElementHandler> elementHandlerClass)
+ {
+ Single s = elementHandlerClass.getAnnotation(Single.class);
+ return s != null;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void _traverseElementHandlerInterfaces(Class<?> clazz, Collection<Class<ElementHandler>> result)
+ {
+ // Add implemented interfaces (that are inherited from ElementHandler)
+ for (Class<?> inf : clazz.getInterfaces())
+ {
+ if (!ElementHandler.class.isAssignableFrom(inf)) continue;
+ result.add((Class<ElementHandler>)inf);
+ }
+
+ // Traverse parent
+ Class<?> superType = clazz.getSuperclass();
+ if (superType!=null)
+ _traverseElementHandlerInterfaces(superType, result);
+ }
+
+ @Override
+ public String toString() {
+ if (!id.isEmpty())
+ return id;
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ int i=0;
+ for (ElementHandler eh : super.getAll())
+ {
+ if (i++>0) sb.append(", ");
+ sb.append( eh.getClass().getSimpleName() );
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public ElementClass newClassWith(ElementHandler... addedHandlers) {
+ if (addedHandlers.length == 0)
+ return this;
+ Collection<ElementHandler> newHandlers = new ArrayList<ElementHandler>(getAll());
+ for (ElementHandler h : addedHandlers)
+ newHandlers.add(h);
+ return ElementClass.compile(newHandlers).setId(id);
+ }
+
+ public ElementClass newClassWith(boolean check, ElementHandler... addedHandlers) {
+ if (addedHandlers.length == 0)
+ return this;
+ Collection<ElementHandler> newHandlers = new ArrayList<ElementHandler>(getAll());
+ for (ElementHandler h : addedHandlers)
+ newHandlers.add(h);
+ return ElementClass.compile(newHandlers, check).setId(id);
+ }
+
+ public ElementClass newClassWith(Collection<ElementHandler> addedHandlers) {
+ if (addedHandlers.isEmpty())
+ return this;
+ Collection<ElementHandler> newHandlers = new ArrayList<ElementHandler>(getAll());
+ newHandlers.addAll(addedHandlers);
+ return ElementClass.compile(newHandlers).setId(id);
+ }
+
+ public ElementClass setId(String id) {
+ this.id = id;
+ return this;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+}