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>
246 * @param clazz desired class of the objects to look for in the selection
247 * @return a single objects matching the search criteria. If there are no or
248 * several matches, <code>null</code> is returned
250 @SuppressWarnings("unchecked")
251 public static <T> T getSinglePossibleKey(Object object, Key key, Class<T> clazz) {
252 return getSinglePossibleKey(object, key, clazz, true);
256 * Try to extract a single object that is an instance of the specified class
257 * out of the provided selection object.
259 * This tries everything even remotely plausible - and then some.
261 * This method works as follows:
263 * <li>Supported input selection objects: IStructuredSelection and
264 * Collection<?>, IHintContext, IAdaptable, direct instances of the
265 * requested class</li>
266 * <li>Selection elements are assumed to be either instances of
267 * IHintContext, IAdaptable or direct instances of the requested class</li>
268 * <li>If an IHintContext is found, the result object is searched within it
269 * with the specified key.</li>
270 * <li>Searching involves testing whether the hint value is an instance of
271 * clazz or adaptable to it through {@link IAdaptable}.</li>
278 * @param clazz desired class of the objects to look for in the selection
279 * @return a single objects matching the search criteria. If there are no or
280 * several matches, <code>null</code> is returned
282 @SuppressWarnings("unchecked")
283 public static <T> T getSinglePossibleKey(Object object, Key key, Class<T> clazz, boolean allowDirectMatch) {
287 // Direct match is returned without key analysis
288 if (allowDirectMatch && clazz.isInstance(object))
291 if (object instanceof ISelection) {
292 ISelection sel = (ISelection) object;
294 if (sel.isEmpty() || (!(sel instanceof IStructuredSelection)))
297 IStructuredSelection ss = (IStructuredSelection) sel;
301 // The result must now be in the first and only element
302 return getSinglePossibleKey(ss.getFirstElement(), key, clazz, allowDirectMatch);
305 if (object instanceof Collection<?>) {
306 Collection<?> c = (Collection<?>) object;
310 return getSinglePossibleKey(c.iterator().next(), key, clazz, allowDirectMatch);
313 // If there was no success so far now we must take the Key into account
314 if (object instanceof IHintContext) {
315 IHintContext context = (IHintContext) object;
316 Object hint = context.getHint(key);
318 // We had a hint context and a matching key was not available - now try single hint - TODO: this somewhat questionable
320 // NOTE: Removed because of a bug:
321 // https://www.simantics.org/redmine/issues/3061
322 // Hope this doesn't break existing code.
323 Map<Key, Object> hints = context.getHints();
324 // There are multiple hints, thats it, there is no result
325 if(hints.size() != 1) return null;
326 hint = hints.values().iterator().next();
328 T t = getSinglePossibleKey(hint, key, clazz);
330 // System.out.println("******************** GEEZ: " + t);
331 // new Exception().printStackTrace();
337 if (clazz.isInstance(hint)) {
339 } else if (hint instanceof IAdaptable) {
340 T adapter = (T) ((IAdaptable) hint).getAdapter(clazz);
344 return getSinglePossibleKey(hint, key, clazz);
348 if (object instanceof IAdaptable)
349 return getSinglePossibleKey(((IAdaptable) object).getAdapter(IHintContext.class), key, clazz, allowDirectMatch);
356 * Try to extract the possible objects that are instances of the specified
357 * class out of the provided selection object.
359 * This method works as follows:
361 * <li>Supported input selection objects: IStructuredSelection and
362 * Collection<?></li>
363 * <li>Selection elements are assumed to be IHintContext instances</li>
364 * <li>The result objects are searched for in the IHintContexts with the
365 * specified key.</li>
366 * <li>Searching involves testing whether the hint value is an instance of
367 * clazz or adaptable to it through {@link IAdaptable}.</li>
370 * All objects that pass through this filter are returned as the result.
374 * @param clazz desired class of the objects to look for in the selection
375 * @return list of the criteria matching elements in the selection or empty
376 * list if nothing suitable was found
378 public static <T> List<T> getPossibleKeys(Object selection, Key key, Class<T> clazz) {
379 if (selection == null)
380 return Collections.emptyList();
382 if (selection instanceof IStructuredSelection) {
383 IStructuredSelection ss = (IStructuredSelection) selection;
385 return Collections.emptyList();
386 return extractPossibleKeys(ss.toList(), key, clazz);
389 if (selection instanceof Collection<?>) {
390 Collection<?> c = (Collection<?>) selection;
391 return extractPossibleKeys(c, key, clazz);
394 if (selection.getClass().isArray()) {
395 Object[] c = (Object[]) selection;
396 return extractPossibleKeys(c, key, clazz);
399 return extractPossibleKeys(Collections.singleton(selection), key, clazz);
402 @SuppressWarnings("unchecked")
403 private static <T> List<T> extractPossibleKeys(Collection<?> objects, Key key, Class<T> clazz) {
404 if (objects.isEmpty())
405 return Collections.emptyList();
407 ArrayList<T> result = new ArrayList<T>(objects.size());
408 for (Object o : objects) {
409 if (o instanceof IHintContext) {
410 IHintContext context = (IHintContext) o;
411 Object object = context.getHint(key);
412 if (object != null) {
413 if (clazz.isInstance(object)) {
414 result.add((T) object);
415 } else if (object instanceof IAdaptable) {
416 Object adapter = ((IAdaptable) object).getAdapter(clazz);
418 result.add((T) adapter);
426 @SuppressWarnings("unchecked")
427 private static <T> List<T> extractPossibleKeys(Object[] objects, Key key, Class<T> clazz) {
428 if (objects.length==0)
429 return Collections.emptyList();
431 ArrayList<T> result = new ArrayList<T>(objects.length);
432 for (Object o : objects) {
433 if (o instanceof IHintContext) {
434 IHintContext context = (IHintContext) o;
435 Object object = context.getHint(key);
436 if (object != null) {
437 if (clazz.isInstance(object)) {
438 result.add((T) object);
439 } else if (object instanceof IAdaptable) {
440 Object adapter = ((IAdaptable) object).getAdapter(clazz);
442 result.add((T) adapter);
451 * This method creates selection from set of objects
453 * @param objects objects
456 public static ISelection createSelection(Object ... objects)
458 return new StructuredSelection(objects);
467 public static void main(String[] args) {
468 Object o1 = new Integer(9);
469 Object o2 = new HashMap<Object, Object>();
470 Object o3 = new Long(1);
472 ISelection s1 = createSelection(o1, o2, o3);
474 List<Number> f1 = convertSelection(s1);
475 List<Number> f2 = filterSelection(s1, Number.class);
477 System.out.println(f1.toString());
478 System.out.println(f2.toString());
480 Assert.isTrue(f2.contains(o1) && f2.contains(o3) && !f2.contains(o2));
481 Assert.isTrue(f1.contains(o1) && f1.contains(o3) && !f1.contains(o2));