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