1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
15 package org.simantics.utils.ui;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
26 import org.eclipse.core.runtime.Assert;
27 import org.eclipse.core.runtime.IAdaptable;
28 import org.eclipse.jface.viewers.ISelection;
29 import org.eclipse.jface.viewers.IStructuredSelection;
30 import org.eclipse.jface.viewers.StructuredSelection;
31 import org.simantics.utils.datastructures.hints.IHintContext;
32 import org.simantics.utils.datastructures.hints.IHintContext.Key;
35 * ISelectionUtils contains static utility methods for dealing with the
36 * ISelection interface.
38 * @author Toni Kalajainen
40 public class ISelectionUtils<T> {
43 * This method converts selection sel for to collection of instances of T.
44 * All elements of the selection are assumed to be instances of T.
46 * @param <T> type of interest
47 * @param sel selection
49 * @throws ClassCastException if the selection contains elements not
52 @SuppressWarnings("unchecked")
53 public static <T> List<T> convertSelection(ISelection sel) throws ClassCastException
55 if (sel == null || sel.isEmpty() || (!(sel instanceof IStructuredSelection)))
56 return Collections.emptyList();
58 List<T> result = new ArrayList<T>();
59 //Class<T> tClass = (Class<T>)result.getClass().getTypeParameters()[0].getBounds()[0];
60 IStructuredSelection ss = (IStructuredSelection) sel;
61 for (Object o : ss.toArray())
62 //if (tClass.isAssignableFrom(o.getClass()))
68 * This method reads selection sel for all instances of T.
69 * All elements of the selection are assumed to be instances of T.
71 * @param <T> type of interest
72 * @param sel selection
74 * @throws ClassCastException if the selection contains elements not
77 @SuppressWarnings("unchecked")
78 public static <T> Set<T> convertSetSelection(ISelection sel) throws ClassCastException
80 if (sel.isEmpty() || (!(sel instanceof IStructuredSelection)))
81 return Collections.emptySet();
83 Set<T> result = new HashSet<T>();
84 //Class<T> tClass = (Class<T>)result.getClass().getTypeParameters()[0].getBounds()[0];
85 IStructuredSelection ss = (IStructuredSelection) sel;
86 for (Object o : ss.toArray())
87 //if (tClass.isAssignableFrom(o.getClass()))
93 @SuppressWarnings("unchecked")
94 public static <T> T convertSingleSelection(ISelection sel)
96 if (sel.isEmpty() || (!(sel instanceof IStructuredSelection)))
98 IStructuredSelection ss = (IStructuredSelection) sel;
99 return (ss.size() == 1) ? (T) ss.getFirstElement() : null;
103 * This method converts selection sel to collection of instances of T
104 * @param <T> type of interest
105 * @param sel selection
108 @SuppressWarnings("unchecked")
109 public static <T> List<T> filterSelection(ISelection sel, Class<T> assignableFrom)
111 if (sel == null || sel.isEmpty() || (!(sel instanceof IStructuredSelection)))
112 return Collections.emptyList();
114 List<T> result = new ArrayList<T>();
115 IStructuredSelection ss = (IStructuredSelection) sel;
116 for (Object o : ss.toArray()) {
117 if (o != null && assignableFrom.isAssignableFrom(o.getClass())) {
119 } else if (o instanceof IAdaptable) {
120 T t = (T) ((IAdaptable) o).getAdapter(assignableFrom);
129 * This method reads selection sel for all instances of T.
131 * @param <T> type of interest
132 * @param sel selection
133 * @return all instances of T in sel
135 public static <T> Set<T> filterSetSelection(Object sel, Class<T> assignableFrom)
137 if (sel instanceof IStructuredSelection) {
138 IStructuredSelection ss = (IStructuredSelection) sel;
140 return filterCollection(ss.toList(), assignableFrom, new HashSet<T>());
141 } else if (sel instanceof Collection<?>) {
142 Collection<?> c = (Collection<?>) sel;
144 return filterCollection(c, assignableFrom, new HashSet<T>());
147 return Collections.emptySet();
150 @SuppressWarnings("unchecked")
151 public static <T> T filterSingleSelection(Object sel, Class<T> assignableTo)
155 } else if (sel instanceof IStructuredSelection) {
156 IStructuredSelection ss = (IStructuredSelection) sel;
158 return tryAdapt(ss.getFirstElement(), assignableTo);
159 } else if (sel instanceof Collection<?>) {
160 Collection<?> c = (Collection<?>) sel;
162 return tryAdapt(c.iterator().next(), assignableTo);
163 } else if (sel.getClass().isArray()) {
164 Object[] os = (Object[])sel;
165 Object result = null;
167 Object r = tryAdapt(o, assignableTo);
169 if(result != null) return null;
178 public static <T> T findFirstAdaptable(Object sel, Class<T> assignableTo)
180 if (sel instanceof IStructuredSelection) {
181 IStructuredSelection ss = (IStructuredSelection) sel;
183 return findFirstAdaptable_(ss.toList(), assignableTo);
184 } else if (sel instanceof Collection<?>) {
185 Collection<?> c = (Collection<?>) sel;
187 return findFirstAdaptable_(c, assignableTo);
192 private static <T> T findFirstAdaptable_(Collection<?> objects, Class<T> assignableTo) {
193 for (Object o : objects) {
194 T t = tryAdapt(o, assignableTo);
201 private static <T, C extends Collection<T>> C filterCollection(Collection<?> objects, Class<T> assignableTo, C result) {
202 for (Object o : objects) {
203 T t = tryAdapt(o, assignableTo);
210 @SuppressWarnings("unchecked")
211 private static <T> T tryAdapt(Object o, Class<T> assignableTo) {
212 if (o != null && assignableTo.isAssignableFrom(o.getClass())) {
214 } else if (o instanceof IAdaptable) {
215 T t = (T) ((IAdaptable) o).getAdapter(assignableTo);
224 * Try to extract a single object that is an instance of the specified class
225 * out of the provided selection object.
227 * This tries everything even remotely plausible - and then some.
229 * This method works as follows:
231 * <li>Supported input selection objects: IStructuredSelection and
232 * Collection<?>, IHintContext, IAdaptable, direct instances of the
233 * requested class</li>
234 * <li>Selection elements are assumed to be either instances of
235 * IHintContext, IAdaptable or direct instances of the requested class</li>
236 * <li>If an IHintContext is found, the result object is searched within it
237 * with the specified key.</li>
238 * <li>Searching involves testing whether the hint value is an instance of
239 * clazz or adaptable to it through {@link IAdaptable}.</li>
244 * @param clazz desired class of the objects to look for in the selection
245 * @return a single objects matching the search criteria. If there are no or
246 * several matches, <code>null</code> is returned
248 public static <T> T getSinglePossibleKey(Object object, Key key, Class<T> clazz) {
249 return getSinglePossibleKey(object, key, clazz, true);
253 * Try to extract a single object that is an instance of the specified class
254 * out of the provided selection object.
256 * This tries everything even remotely plausible - and then some.
258 * This method works as follows:
260 * <li>Supported input selection objects: IStructuredSelection and
261 * Collection<?>, IHintContext, IAdaptable, direct instances of the
262 * requested class</li>
263 * <li>Selection elements are assumed to be either instances of
264 * IHintContext, IAdaptable or direct instances of the requested class</li>
265 * <li>If an IHintContext is found, the result object is searched within it
266 * with the specified key.</li>
267 * <li>Searching involves testing whether the hint value is an instance of
268 * clazz or adaptable to it through {@link IAdaptable}.</li>
275 * @param clazz desired class of the objects to look for in the selection
276 * @return a single objects matching the search criteria. If there are no or
277 * several matches, <code>null</code> is returned
279 @SuppressWarnings("unchecked")
280 public static <T> T getSinglePossibleKey(Object object, Key key, Class<T> clazz, boolean allowDirectMatch) {
284 // Direct match is returned without key analysis
285 if (allowDirectMatch && clazz.isInstance(object))
288 if (object instanceof ISelection) {
289 ISelection sel = (ISelection) object;
291 if (sel.isEmpty() || (!(sel instanceof IStructuredSelection)))
294 IStructuredSelection ss = (IStructuredSelection) sel;
298 // The result must now be in the first and only element
299 return getSinglePossibleKey(ss.getFirstElement(), key, clazz, allowDirectMatch);
302 if (object instanceof Collection<?>) {
303 Collection<?> c = (Collection<?>) object;
307 return getSinglePossibleKey(c.iterator().next(), key, clazz, allowDirectMatch);
310 // If there was no success so far now we must take the Key into account
311 if (object instanceof IHintContext) {
312 IHintContext context = (IHintContext) object;
313 Object hint = context.getHint(key);
315 // We had a hint context and a matching key was not available - now try single hint - TODO: this somewhat questionable
317 // NOTE: Removed because of a bug:
318 // https://www.simantics.org/redmine/issues/3061
319 // Hope this doesn't break existing code.
320 Map<Key, Object> hints = context.getHints();
321 // There are multiple hints, thats it, there is no result
322 if(hints.size() != 1) return null;
323 hint = hints.values().iterator().next();
325 T t = getSinglePossibleKey(hint, key, clazz);
327 // System.out.println("******************** GEEZ: " + t);
328 // new Exception().printStackTrace();
334 if (clazz.isInstance(hint)) {
336 } else if (hint instanceof IAdaptable) {
337 T adapter = (T) ((IAdaptable) hint).getAdapter(clazz);
341 return getSinglePossibleKey(hint, key, clazz);
345 if (object instanceof IAdaptable)
346 return getSinglePossibleKey(((IAdaptable) object).getAdapter(IHintContext.class), key, clazz, allowDirectMatch);
353 * Try to extract the possible objects that are instances of the specified
354 * class out of the provided selection object.
356 * This method works as follows:
358 * <li>Supported input selection objects: IStructuredSelection and
359 * Collection<?></li>
360 * <li>Selection elements are assumed to be IHintContext instances</li>
361 * <li>The result objects are searched for in the IHintContexts with the
362 * specified key.</li>
363 * <li>Searching involves testing whether the hint value is an instance of
364 * clazz or adaptable to it through {@link IAdaptable}.</li>
367 * All objects that pass through this filter are returned as the result.
371 * @param clazz desired class of the objects to look for in the selection
372 * @return list of the criteria matching elements in the selection or empty
373 * list if nothing suitable was found
375 public static <T> List<T> getPossibleKeys(Object selection, Key key, Class<T> clazz) {
376 if (selection == null)
377 return Collections.emptyList();
379 if (selection instanceof IStructuredSelection) {
380 IStructuredSelection ss = (IStructuredSelection) selection;
382 return Collections.emptyList();
383 return extractPossibleKeys(ss.toList(), key, clazz);
386 if (selection instanceof Collection<?>) {
387 Collection<?> c = (Collection<?>) selection;
388 return extractPossibleKeys(c, key, clazz);
391 if (selection.getClass().isArray()) {
392 Object[] c = (Object[]) selection;
393 return extractPossibleKeys(c, key, clazz);
396 return extractPossibleKeys(Collections.singleton(selection), key, clazz);
399 @SuppressWarnings("unchecked")
400 private static <T> List<T> extractPossibleKeys(Collection<?> objects, Key key, Class<T> clazz) {
401 if (objects.isEmpty())
402 return Collections.emptyList();
404 ArrayList<T> result = new ArrayList<T>(objects.size());
405 for (Object o : objects) {
406 if (o instanceof IHintContext) {
407 IHintContext context = (IHintContext) o;
408 Object object = context.getHint(key);
409 if (object != null) {
410 if (clazz.isInstance(object)) {
411 result.add((T) object);
412 } else if (object instanceof IAdaptable) {
413 Object adapter = ((IAdaptable) object).getAdapter(clazz);
415 result.add((T) adapter);
423 @SuppressWarnings("unchecked")
424 private static <T> List<T> extractPossibleKeys(Object[] objects, Key key, Class<T> clazz) {
425 if (objects.length==0)
426 return Collections.emptyList();
428 ArrayList<T> result = new ArrayList<T>(objects.length);
429 for (Object o : objects) {
430 if (o instanceof IHintContext) {
431 IHintContext context = (IHintContext) o;
432 Object object = context.getHint(key);
433 if (object != null) {
434 if (clazz.isInstance(object)) {
435 result.add((T) object);
436 } else if (object instanceof IAdaptable) {
437 Object adapter = ((IAdaptable) object).getAdapter(clazz);
439 result.add((T) adapter);
448 * This method creates selection from set of objects
450 * @param objects objects
453 public static ISelection createSelection(Object ... objects)
455 return new StructuredSelection(objects);
464 public static void main(String[] args) {
465 Object o1 = new Integer(9);
466 Object o2 = new HashMap<Object, Object>();
467 Object o3 = new Long(1);
469 ISelection s1 = createSelection(o1, o2, o3);
471 List<Number> f1 = convertSelection(s1);
472 List<Number> f2 = filterSelection(s1, Number.class);
474 System.out.println(f1.toString());
475 System.out.println(f2.toString());
477 Assert.isTrue(f2.contains(o1) && f2.contains(o3) && !f2.contains(o2));
478 Assert.isTrue(f1.contains(o1) && f1.contains(o3) && !f1.contains(o2));