--- /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
+/*\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<?>, 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<?>, 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<?></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