]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/ISelectionUtils.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.utils.ui / src / org / simantics / utils / ui / ISelectionUtils.java
diff --git a/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/ISelectionUtils.java b/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/ISelectionUtils.java
new file mode 100644 (file)
index 0000000..1f4e228
--- /dev/null
@@ -0,0 +1,484 @@
+/*******************************************************************************\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
+/*\r
+ * 25.8.2006\r
+ */\r
+package org.simantics.utils.ui;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.eclipse.core.runtime.Assert;\r
+import org.eclipse.core.runtime.IAdaptable;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.jface.viewers.StructuredSelection;\r
+import org.simantics.utils.datastructures.hints.IHintContext;\r
+import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
+\r
+/**\r
+ * ISelectionUtils contains static utility methods for dealing with the\r
+ * ISelection interface.\r
+ * \r
+ * @author Toni Kalajainen\r
+ */\r
+public class ISelectionUtils<T> {\r
+\r
+    /**\r
+     * This method converts selection sel for to collection of instances of T.\r
+     * All elements of the selection are assumed to be instances of T.\r
+     * \r
+     * @param <T> type of interest\r
+     * @param sel selection\r
+     * @return list\r
+     * @throws ClassCastException if the selection contains elements not\r
+     *         instance of T\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    public static <T> List<T> convertSelection(ISelection sel) throws ClassCastException\r
+    {\r
+        if (sel == null || sel.isEmpty() || (!(sel instanceof IStructuredSelection)))\r
+            return Collections.emptyList();\r
+\r
+        List<T> result = new ArrayList<T>();\r
+        //Class<T> tClass = (Class<T>)result.getClass().getTypeParameters()[0].getBounds()[0];\r
+        IStructuredSelection ss = (IStructuredSelection) sel;\r
+        for (Object o : ss.toArray())\r
+            //if (tClass.isAssignableFrom(o.getClass()))\r
+            result.add((T)o);\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * This method reads selection sel for all instances of T.\r
+     * All elements of the selection are assumed to be instances of T.\r
+     * \r
+     * @param <T> type of interest\r
+     * @param sel selection\r
+     * @return set\r
+     * @throws ClassCastException if the selection contains elements not\r
+     *         instance of T\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    public static <T> Set<T> convertSetSelection(ISelection sel) throws ClassCastException\r
+    {\r
+        if (sel.isEmpty() || (!(sel instanceof IStructuredSelection)))\r
+            return Collections.emptySet();\r
+\r
+        Set<T> result = new HashSet<T>();\r
+        //Class<T> tClass = (Class<T>)result.getClass().getTypeParameters()[0].getBounds()[0];\r
+        IStructuredSelection ss = (IStructuredSelection) sel;\r
+        for (Object o : ss.toArray())\r
+            //if (tClass.isAssignableFrom(o.getClass()))\r
+            result.add((T)o);\r
+        return result;\r
+    }\r
+\r
+\r
+    @SuppressWarnings("unchecked")\r
+    public static <T> T convertSingleSelection(ISelection sel)\r
+    {\r
+        if (sel.isEmpty() || (!(sel instanceof IStructuredSelection)))\r
+            return null;\r
+        IStructuredSelection ss = (IStructuredSelection) sel;\r
+        return (ss.size() == 1) ? (T) ss.getFirstElement() : null;\r
+    }\r
+\r
+    /**\r
+     * This method converts selection sel to collection of instances of T\r
+     * @param <T> type of interest\r
+     * @param sel selection\r
+     * @return list\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    public static <T> List<T> filterSelection(ISelection sel, Class<T> assignableFrom)\r
+    {\r
+        if (sel == null || sel.isEmpty() || (!(sel instanceof IStructuredSelection)))\r
+            return Collections.emptyList();\r
+\r
+        List<T> result = new ArrayList<T>();\r
+        IStructuredSelection ss = (IStructuredSelection) sel;\r
+        for (Object o : ss.toArray()) {\r
+            if (o != null && assignableFrom.isAssignableFrom(o.getClass())) {\r
+                result.add((T)o);\r
+            } else if (o instanceof IAdaptable) {\r
+                T t = (T) ((IAdaptable) o).getAdapter(assignableFrom);\r
+                if (t != null)\r
+                    result.add(t);\r
+            }\r
+        }\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * This method reads selection sel for all instances of T.\r
+     * \r
+     * @param <T> type of interest\r
+     * @param sel selection\r
+     * @return all instances of T in sel\r
+     */\r
+    public static <T> Set<T> filterSetSelection(Object sel, Class<T> assignableFrom)\r
+    {\r
+        if (sel instanceof IStructuredSelection) {\r
+            IStructuredSelection ss = (IStructuredSelection) sel;\r
+            if (!ss.isEmpty())\r
+                return filterCollection(ss.toList(), assignableFrom, new HashSet<T>());\r
+        } else if (sel instanceof Collection<?>) {\r
+            Collection<?> c = (Collection<?>) sel;\r
+            if (!c.isEmpty())\r
+                return filterCollection(c, assignableFrom, new HashSet<T>());\r
+        }\r
+\r
+        return Collections.emptySet();\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    public static <T> T filterSingleSelection(Object sel, Class<T> assignableTo)\r
+    {\r
+       if (sel == null) {\r
+               return null;\r
+       } else if (sel instanceof IStructuredSelection) {\r
+            IStructuredSelection ss = (IStructuredSelection) sel;\r
+            if (ss.size() == 1)\r
+                return tryAdapt(ss.getFirstElement(), assignableTo);\r
+        } else if (sel instanceof Collection<?>) {\r
+            Collection<?> c = (Collection<?>) sel;\r
+            if (c.size() == 1)\r
+                return tryAdapt(c.iterator().next(), assignableTo);\r
+        } else if (sel.getClass().isArray()) {\r
+               Object[] os = (Object[])sel;\r
+               Object result = null;\r
+               for(Object o : os) {\r
+                       Object r = tryAdapt(o, assignableTo);\r
+                       if(r != null) {\r
+                               if(result != null) return null;\r
+                               result = r;\r
+                       }\r
+               }\r
+               return (T)result;\r
+        }\r
+        return null;\r
+    }\r
+\r
+    public static <T> T findFirstAdaptable(Object sel, Class<T> assignableTo)\r
+    {\r
+        if (sel instanceof IStructuredSelection) {\r
+            IStructuredSelection ss = (IStructuredSelection) sel;\r
+            if (!ss.isEmpty())\r
+                return findFirstAdaptable_(ss.toList(), assignableTo);\r
+        } else if (sel instanceof Collection<?>) {\r
+            Collection<?> c = (Collection<?>) sel;\r
+            if (!c.isEmpty())\r
+                return findFirstAdaptable_(c, assignableTo);\r
+        }\r
+        return null;\r
+    }\r
+\r
+    private static <T> T findFirstAdaptable_(Collection<?> objects, Class<T> assignableTo) {\r
+        for (Object o : objects) {\r
+            T t = tryAdapt(o, assignableTo);\r
+            if (t != null)\r
+                return t;\r
+        }\r
+        return null;\r
+    }\r
+\r
+    private static <T, C extends Collection<T>> C filterCollection(Collection<?> objects, Class<T> assignableTo, C result) {\r
+        for (Object o : objects) {\r
+            T t = tryAdapt(o, assignableTo);\r
+            if (t != null)\r
+                result.add(t);\r
+        }\r
+        return result;\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    private static <T> T tryAdapt(Object o, Class<T> assignableTo) {\r
+        if (o != null && assignableTo.isAssignableFrom(o.getClass())) {\r
+            return (T) o;\r
+        } else if (o instanceof IAdaptable) {\r
+            T t = (T) ((IAdaptable) o).getAdapter(assignableTo);\r
+            if (t != null) {\r
+                return t;\r
+            }\r
+        }\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     * Try to extract a single object that is an instance of the specified class\r
+     * out of the provided selection object.\r
+     * \r
+     * This tries everything even remotely plausible - and then some.\r
+     * \r
+     * This method works as follows:\r
+     * <ul>\r
+     * <li>Supported input selection objects: IStructuredSelection and\r
+     * Collection&lt;?&gt;, IHintContext, IAdaptable, direct instances of the\r
+     * requested class</li>\r
+     * <li>Selection elements are assumed to be either instances of\r
+     * IHintContext, IAdaptable or direct instances of the requested class</li>\r
+     * <li>If an IHintContext is found, the result object is searched within it\r
+     * with the specified key.</li>\r
+     * <li>Searching involves testing whether the hint value is an instance of\r
+     * clazz or adaptable to it through {@link IAdaptable}.</li>\r
+     * </ul>\r
+     * \r
+     * \r
+     * \r
+     * @param selection\r
+     * @param key\r
+     * @param clazz desired class of the objects to look for in the selection\r
+     * @return a single objects matching the search criteria. If there are no or\r
+     *         several matches, <code>null</code> is returned\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    public static <T> T getSinglePossibleKey(Object object, Key key, Class<T> clazz) {\r
+        return getSinglePossibleKey(object, key, clazz, true);\r
+    }\r
+\r
+    /**\r
+     * Try to extract a single object that is an instance of the specified class\r
+     * out of the provided selection object.\r
+     * \r
+     * This tries everything even remotely plausible - and then some.\r
+     * \r
+     * This method works as follows:\r
+     * <ul>\r
+     * <li>Supported input selection objects: IStructuredSelection and\r
+     * Collection&lt;?&gt;, IHintContext, IAdaptable, direct instances of the\r
+     * requested class</li>\r
+     * <li>Selection elements are assumed to be either instances of\r
+     * IHintContext, IAdaptable or direct instances of the requested class</li>\r
+     * <li>If an IHintContext is found, the result object is searched within it\r
+     * with the specified key.</li>\r
+     * <li>Searching involves testing whether the hint value is an instance of\r
+     * clazz or adaptable to it through {@link IAdaptable}.</li>\r
+     * </ul>\r
+     * \r
+     * \r
+     * \r
+     * @param selection\r
+     * @param key\r
+     * @param clazz desired class of the objects to look for in the selection\r
+     * @return a single objects matching the search criteria. If there are no or\r
+     *         several matches, <code>null</code> is returned\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    public static <T> T getSinglePossibleKey(Object object, Key key, Class<T> clazz, boolean allowDirectMatch) {\r
+        if (object == null)\r
+            return null;\r
+\r
+        // Direct match is returned without key analysis\r
+        if (allowDirectMatch && clazz.isInstance(object))\r
+            return (T) object;\r
+\r
+        if (object instanceof ISelection) {\r
+            ISelection sel = (ISelection) object;\r
+\r
+            if (sel.isEmpty() || (!(sel instanceof IStructuredSelection)))\r
+                return null;\r
+\r
+            IStructuredSelection ss = (IStructuredSelection) sel;\r
+            if (ss.size() != 1)\r
+                return null;\r
+\r
+            // The result must now be in the first and only element\r
+            return getSinglePossibleKey(ss.getFirstElement(), key, clazz, allowDirectMatch);\r
+        }\r
+\r
+        if (object instanceof Collection<?>) {\r
+            Collection<?> c = (Collection<?>) object;\r
+            if (c.size() != 1)\r
+                return null;\r
+\r
+            return getSinglePossibleKey(c.iterator().next(), key, clazz, allowDirectMatch);\r
+        }\r
+\r
+        // If there was no success so far now we must take the Key into account\r
+        if (object instanceof IHintContext) {\r
+            IHintContext context = (IHintContext) object;\r
+            Object hint = context.getHint(key);\r
+\r
+            // We had a hint context and a matching key was not available - now try single hint - TODO: this somewhat questionable\r
+            if (hint == null) {\r
+                // NOTE: Removed because of a bug:\r
+                // https://www.simantics.org/redmine/issues/3061\r
+                // Hope this doesn't break existing code.\r
+                Map<Key, Object> hints = context.getHints();\r
+                // There are multiple hints, thats it, there is no result\r
+                if(hints.size() != 1) return null;\r
+                hint = hints.values().iterator().next();\r
+\r
+                T t = getSinglePossibleKey(hint, key, clazz);\r
+//                if (t != null) {\r
+//                    System.out.println("******************** GEEZ: " + t);\r
+//                    new Exception().printStackTrace();\r
+//                }\r
+                return t;\r
+//                return null;\r
+            }\r
+\r
+            if (clazz.isInstance(hint)) {\r
+                return (T) hint;\r
+            } else if (hint instanceof IAdaptable) {\r
+                T adapter = (T) ((IAdaptable) hint).getAdapter(clazz);\r
+                if (adapter != null)\r
+                    return adapter;\r
+            } else {\r
+                return getSinglePossibleKey(hint, key, clazz);\r
+            }\r
+        }\r
+\r
+        if (object instanceof IAdaptable)\r
+            return getSinglePossibleKey(((IAdaptable) object).getAdapter(IHintContext.class), key, clazz, allowDirectMatch);\r
+\r
+        return null;\r
+\r
+    }\r
+\r
+    /**\r
+     * Try to extract the possible objects that are instances of the specified\r
+     * class out of the provided selection object.\r
+     * \r
+     * This method works as follows:\r
+     * <ul>\r
+     * <li>Supported input selection objects: IStructuredSelection and\r
+     * Collection&lt;?&gt;</li>\r
+     * <li>Selection elements are assumed to be IHintContext instances</li>\r
+     * <li>The result objects are searched for in the IHintContexts with the\r
+     * specified key.</li>\r
+     * <li>Searching involves testing whether the hint value is an instance of\r
+     * clazz or adaptable to it through {@link IAdaptable}.</li>\r
+     * </ul>\r
+     * \r
+     * All objects that pass through this filter are returned as the result.\r
+     * \r
+     * @param selection\r
+     * @param key\r
+     * @param clazz desired class of the objects to look for in the selection\r
+     * @return list of the criteria matching elements in the selection or empty\r
+     *         list if nothing suitable was found\r
+     */\r
+    public static <T> List<T> getPossibleKeys(Object selection, Key key, Class<T> clazz) {\r
+        if (selection == null)\r
+            return Collections.emptyList();\r
+\r
+        if (selection instanceof IStructuredSelection) {\r
+            IStructuredSelection ss = (IStructuredSelection) selection;\r
+            if (ss.isEmpty())\r
+                return Collections.emptyList();\r
+            return extractPossibleKeys(ss.toList(), key, clazz);\r
+        }\r
+\r
+        if (selection instanceof Collection<?>) {\r
+            Collection<?> c = (Collection<?>) selection;\r
+            return extractPossibleKeys(c, key, clazz);\r
+        }\r
+\r
+        if (selection.getClass().isArray()) {\r
+               Object[] c = (Object[]) selection;\r
+            return extractPossibleKeys(c, key, clazz);\r
+        }\r
+\r
+        return extractPossibleKeys(Collections.singleton(selection), key, clazz);\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    private static <T> List<T> extractPossibleKeys(Collection<?> objects, Key key, Class<T> clazz) {\r
+        if (objects.isEmpty())\r
+            return Collections.emptyList();\r
+\r
+        ArrayList<T> result = new ArrayList<T>(objects.size());\r
+        for (Object o : objects) {\r
+            if (o instanceof IHintContext) {\r
+                IHintContext context = (IHintContext) o;\r
+                Object object = context.getHint(key);\r
+                if (object != null) {\r
+                    if (clazz.isInstance(object)) {\r
+                        result.add((T) object);\r
+                    } else if (object instanceof IAdaptable) {\r
+                        Object adapter = ((IAdaptable) object).getAdapter(clazz);\r
+                        if (adapter != null)\r
+                            result.add((T) adapter);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        return result;\r
+    }\r
+\r
+    @SuppressWarnings("unchecked")\r
+    private static <T> List<T> extractPossibleKeys(Object[] objects, Key key, Class<T> clazz) {\r
+        if (objects.length==0)\r
+            return Collections.emptyList();\r
+\r
+        ArrayList<T> result = new ArrayList<T>(objects.length);\r
+        for (Object o : objects) {\r
+            if (o instanceof IHintContext) {\r
+                IHintContext context = (IHintContext) o;\r
+                Object object = context.getHint(key);\r
+                if (object != null) {\r
+                    if (clazz.isInstance(object)) {\r
+                        result.add((T) object);\r
+                    } else if (object instanceof IAdaptable) {\r
+                        Object adapter = ((IAdaptable) object).getAdapter(clazz);\r
+                        if (adapter != null)\r
+                            result.add((T) adapter);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * This method creates selection from set of objects\r
+     * \r
+     * @param objects objects\r
+     * @return selection\r
+     */\r
+    public static ISelection createSelection(Object ... objects)\r
+    {\r
+        return new StructuredSelection(objects);\r
+    }\r
+\r
+\r
+    /**\r
+     * A testcase.\r
+     * \r
+     * @param args\r
+     */\r
+    public static void main(String[] args) {\r
+        Object o1 = new Integer(9);\r
+        Object o2 = new HashMap<Object, Object>();\r
+        Object o3 = new Long(1);\r
+\r
+        ISelection s1 = createSelection(o1, o2, o3);\r
+\r
+        List<Number> f1 = convertSelection(s1);\r
+        List<Number> f2 = filterSelection(s1, Number.class);\r
+\r
+        System.out.println(f1.toString());\r
+        System.out.println(f2.toString());\r
+\r
+        Assert.isTrue(f2.contains(o1) && f2.contains(o3) && !f2.contains(o2));\r
+        Assert.isTrue(f1.contains(o1) && f1.contains(o3) && !f1.contains(o2));\r
+    }\r
+\r
+}\r