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