]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/Selection.java
G2DParentNode handles "undefined" child bounds separately
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / diagram / participant / Selection.java
index c77584825526b4bdc4e69fc0cdd6351bae613d63..c7aa7872da2a7e21d94f80ed4e411f4d91fa0c49 100644 (file)
-/*******************************************************************************\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
-package org.simantics.g2d.diagram.participant;\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.Map;\r
-import java.util.Set;\r
-import java.util.Map.Entry;\r
-\r
-import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant;\r
-import org.simantics.g2d.diagram.DiagramHints;\r
-import org.simantics.g2d.diagram.IDiagram;\r
-import org.simantics.g2d.element.IElement;\r
-import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;\r
-import org.simantics.scenegraph.g2d.events.command.CommandEvent;\r
-import org.simantics.scenegraph.g2d.events.command.Commands;\r
-import org.simantics.utils.DataContainer;\r
-import org.simantics.utils.datastructures.collections.CollectionUtils;\r
-import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
-import org.simantics.utils.datastructures.hints.IHintContext.MouseSpecificKeyOf;\r
-import org.simantics.utils.threads.ThreadUtils;\r
-\r
-/**\r
- * Selection is a canvas utility used for managing selected elements.\r
- * <p>\r
- * There are multiple selection context. They are differentiated with selectionId.\r
- * Multiple selections are used in multi-user environments (such as multi touch screen).\r
- * In normal diagram setup SELECTION0 is the default selection.\r
- * \r
- * @author Toni Kalajainen\r
- */\r
-public class Selection extends AbstractCanvasParticipant {\r
-\r
-    /** Key for the most common Selection0 */\r
-    public static final SelectionHintKey SELECTION0 = new SelectionHintKey(0);\r
-\r
-    private static final Set<IElement> NO_SELECTION = Collections\r
-    .unmodifiableSet(new HashSet<IElement>(0));\r
-\r
-    public static SelectionHintKey getKeyForSelectionId(int selectionId) {\r
-        if (selectionId == 0)\r
-            return SELECTION0;\r
-        return new SelectionHintKey(selectionId);\r
-    }\r
-\r
-    @EventHandler(priority = 0)\r
-    public boolean handleCommand(CommandEvent e)\r
-    {\r
-        if (e.command.equals( Commands.SELECT_ALL )) {\r
-            IDiagram d = getHint( DiagramHints.KEY_DIAGRAM );\r
-            if (d==null) return true;\r
-            addAll(0, d.getElements());\r
-            return true;\r
-        }\r
-        if (e.command.equals( Commands.INVERT_SELECTION )) {\r
-            IDiagram d = getHint( DiagramHints.KEY_DIAGRAM );\r
-            if (d==null) return true;\r
-            Set<IElement> current = getSelection(0);\r
-            Set<IElement> inverted = new HashSet<IElement>(d.getElements());\r
-            inverted.removeAll(current);\r
-            setSelection(0, inverted);\r
-            return true;\r
-        }\r
-        return false;\r
-    }\r
-\r
-\r
-    /**\r
-     * Get selection\r
-     * \r
-     * @param selectionId\r
-     *            selectionId\r
-     * @return returns a set of pickables\r
-     */\r
-    public Set<IElement> getSelection(int selectionId) {\r
-        Key key = getKeyForSelectionId(selectionId);\r
-        Set<IElement> selection = getHint(key);\r
-        if (selection == null)\r
-            return NO_SELECTION;\r
-        return new HashSet<IElement>(selection);\r
-    }\r
-\r
-    /**\r
-     * Get all selections of all selection ids\r
-     * @return all selections\r
-     */\r
-    public Set<IElement> getAllSelections() {\r
-        Set<IElement> result = new HashSet<IElement>();\r
-        for (Entry<SelectionHintKey, Object> entry : getContext()\r
-                .getHintStack().getHintsOfClass(SelectionHintKey.class)\r
-                .entrySet()) {\r
-            @SuppressWarnings("unchecked")\r
-            Set<IElement> set = (Set<IElement>) entry.getValue();\r
-            if (set == null || set.isEmpty())\r
-                continue;\r
-            result.addAll(set);\r
-        }\r
-        return result;\r
-\r
-    }\r
-\r
-    /**\r
-     * Get selections by selection id\r
-     * \r
-     * @return map of selection ids and selections\r
-     */\r
-    @SuppressWarnings("unchecked")\r
-    public Map<Integer, Set<IElement>> getSelections() {\r
-        Map<Integer, Set<IElement>> result = new HashMap<Integer, Set<IElement>>();\r
-        for (Entry<SelectionHintKey, Object> entry : getContext()\r
-                .getHintStack().getHintsOfClass(SelectionHintKey.class)\r
-                .entrySet()) {\r
-            Set<IElement> set = (Set<IElement>) entry.getValue();\r
-            if (set == null || set.isEmpty())\r
-                continue;\r
-            result.put(entry.getKey().mouseId, set);\r
-        }\r
-        return result;\r
-    }\r
-\r
-    public int[] getSelectionIds() {\r
-        Map<SelectionHintKey, Object> map = getContext().getHintStack()\r
-        .getHintsOfClass(SelectionHintKey.class);\r
-        int result[] = new int[map.size()];\r
-        int i = 0;\r
-        for (SelectionHintKey key : map.keySet())\r
-            result[i++] = key.mouseId;\r
-        return result;\r
-    }\r
-\r
-    public boolean setSelection(final int selectionId,\r
-            final Collection<IElement> _selection) {\r
-        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);\r
-        ThreadUtils.syncExec(getThread(), new Runnable() {\r
-            @Override\r
-            public void run() {\r
-                Collection<IElement> selection = _selection;\r
-                Key key = getKeyForSelectionId(selectionId);\r
-                if (selection == null || selection.isEmpty())\r
-                    selection = NO_SELECTION;\r
-                Set<IElement> oldSelection = getHint(key);\r
-                if (oldSelection == null)\r
-                    oldSelection = NO_SELECTION;\r
-                if (oldSelection.equals(selection))\r
-                    return;\r
-                if (selection == NO_SELECTION) {\r
-                    removeHint(key);\r
-                    result.set(true);\r
-                }\r
-                Set<IElement> newSelection = Collections\r
-                .unmodifiableSet(new HashSet<IElement>(selection));\r
-                setHint(key, newSelection);\r
-                result.set(true);\r
-            }\r
-        });\r
-        return result.get();\r
-    }\r
-\r
-    public boolean setSelection(int selectionId, IElement selection) {\r
-        ArrayList<IElement> list = new ArrayList<IElement>(1);\r
-        list.add(selection);\r
-        return setSelection(selectionId, list);\r
-    }\r
-\r
-    /**\r
-     * Add item to selection\r
-     * \r
-     * @param pickable\r
-     */\r
-    public boolean add(final int selectionId, final IElement pickable) {\r
-        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);\r
-        ThreadUtils.syncExec(getThread(), new Runnable() {\r
-            @Override\r
-            public void run() {\r
-                Key key = getKeyForSelectionId(selectionId);\r
-                Set<IElement> oldSelection = getSelection(selectionId);\r
-                if (oldSelection.contains(pickable))\r
-                    return;\r
-                Set<IElement> newSelection = new HashSet<IElement>(\r
-                        oldSelection);\r
-                newSelection.add(pickable);\r
-                newSelection = Collections.unmodifiableSet(newSelection);\r
-                setHint(key, newSelection);\r
-                result.set(true);\r
-            }\r
-        });\r
-        return result.get();\r
-    }\r
-\r
-    /**\r
-     * Add items to mouse0's selection\r
-     * \r
-     * @param pickables\r
-     * @return\r
-     */\r
-    public boolean addAll(final int selectionId,\r
-            final Collection<IElement> pickables) {\r
-        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);\r
-        ThreadUtils.syncExec(getThread(), new Runnable() {\r
-            @Override\r
-            public void run() {\r
-\r
-                Key key = getKeyForSelectionId(selectionId);\r
-                Set<IElement> selection = getSelection(selectionId);\r
-                if (selection.containsAll(pickables))\r
-                    return;\r
-                Set<IElement> newSelection = new HashSet<IElement>(selection);\r
-                newSelection.addAll(pickables);\r
-                newSelection = Collections.unmodifiableSet(newSelection);\r
-                setHint(key, newSelection);\r
-                result.set(true);\r
-            }\r
-        });\r
-        return result.get();\r
-    }\r
-\r
-    /**\r
-     * Remove an item from mouse0's selection\r
-     * \r
-     * @param pickable\r
-     * @return\r
-     */\r
-    public boolean remove(final int selectionId, final IElement pickable) {\r
-        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);\r
-        ThreadUtils.syncExec(getThread(), new Runnable() {\r
-            @Override\r
-            public void run() {\r
-                Key key = getKeyForSelectionId(selectionId);\r
-                Set<IElement> oldSelection = getSelection(selectionId);\r
-                if (!oldSelection.contains(pickable))\r
-                    return;\r
-                Set<IElement> newSelection = new HashSet<IElement>(\r
-                        oldSelection);\r
-                newSelection.remove(pickable);\r
-                newSelection = Collections.unmodifiableSet(newSelection);\r
-                setHint(key, newSelection);\r
-                result.set(true);\r
-            }\r
-        });\r
-        return result.get();\r
-    }\r
-\r
-    /**\r
-     * Returns true if two collections have a common object\r
-     * \r
-     * @param x\r
-     * @param y\r
-     * @return\r
-     */\r
-    public static boolean containsAny(Collection<?> x, Collection<?> y) {\r
-        for (Object o : x)\r
-            if (y.contains(o))\r
-                return true;\r
-        return false;\r
-    }\r
-\r
-    /**\r
-     * Remove items from mouse0's selection\r
-     * \r
-     * @param pickables\r
-     * @return\r
-     */\r
-    public boolean removeAll(final int selectionId,\r
-            final Collection<IElement> pickables) {\r
-        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);\r
-        ThreadUtils.syncExec(getThread(), new Runnable() {\r
-            @Override\r
-            public void run() {\r
-                Key key = getKeyForSelectionId(selectionId);\r
-                Set<IElement> oldSelection = getSelection(selectionId);\r
-                if (!containsAny(oldSelection, pickables))\r
-                    return;\r
-                Set<IElement> newSelection = new HashSet<IElement>(\r
-                        oldSelection);\r
-                newSelection.removeAll(pickables);\r
-                newSelection = Collections.unmodifiableSet(newSelection);\r
-                setHint(key, newSelection);\r
-                result.set(true);\r
-            }\r
-        });\r
-        return result.get();\r
-    }\r
-\r
-    /**\r
-     * Retain items in mouse0's selection\r
-     * \r
-     * @param pickable\r
-     * @return\r
-     */\r
-    public boolean retainAll(final int selectionId,\r
-            final Collection<IElement> pickable) {\r
-        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);\r
-        ThreadUtils.syncExec(getThread(), new Runnable() {\r
-            @Override\r
-            public void run() {\r
-                Key key = getKeyForSelectionId(selectionId);\r
-                Set<IElement> oldSelection = getSelection(selectionId);\r
-                Set<IElement> newSelection = new HashSet<IElement>(\r
-                        oldSelection);\r
-                newSelection.retainAll(pickable);\r
-                if (oldSelection.equals(newSelection))\r
-                    return;\r
-                newSelection = Collections.unmodifiableSet(newSelection);\r
-                setHint(key, newSelection);\r
-                result.set(true);\r
-            }\r
-        });\r
-        return result.get();\r
-    }\r
-\r
-    public boolean contains(int selectionId, IElement pickable) {\r
-        Set<IElement> oldSelection = getSelection(selectionId);\r
-        return oldSelection.contains(pickable);\r
-    }\r
-\r
-    public synchronized void toggle(final int selectionId, final Set<IElement> toggleSet) {\r
-        ThreadUtils.syncExec(getThread(), new Runnable() {\r
-            @Override\r
-            public void run() {\r
-                Key key = getKeyForSelectionId(selectionId);\r
-                Set<IElement> oldSelection = getSelection(selectionId);\r
-                Set<IElement> newSelection = new HashSet<IElement>(oldSelection);\r
-                CollectionUtils.toggle(newSelection, toggleSet);\r
-                newSelection = Collections.unmodifiableSet(newSelection);\r
-                setHint(key, newSelection);\r
-            }\r
-        });\r
-    }\r
-\r
-    /**\r
-     * Toggle an item in a selection.\r
-     */\r
-    public synchronized void toggle(int selectionId, IElement pickable) {\r
-        Key key = getKeyForSelectionId(selectionId);\r
-        Set<IElement> oldSelection = getSelection(selectionId);\r
-        Set<IElement> newSelection = new HashSet<IElement>(oldSelection);\r
-\r
-        if (oldSelection.contains(pickable))\r
-            newSelection.remove(pickable);\r
-        else\r
-            newSelection.add(pickable);\r
-\r
-        newSelection = Collections.unmodifiableSet(newSelection);\r
-        setHint(key, newSelection);\r
-    }\r
-\r
-    /**\r
-     * Clear selection\r
-     */\r
-    public void clear(int selectionId) {\r
-        Key key = getKeyForSelectionId(selectionId);\r
-        removeHint(key);\r
-    }\r
-\r
-    /** Class for mouse specific hint keys */\r
-    public static class SelectionHintKey extends MouseSpecificKeyOf {\r
-        public SelectionHintKey(int mouseId) {\r
-            super(mouseId, Set.class);\r
-        }\r
-    }\r
-\r
-\r
-}\r
+/*******************************************************************************
+ * 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
+ *******************************************************************************/
+package org.simantics.g2d.diagram.participant;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant;
+import org.simantics.g2d.diagram.DiagramHints;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.element.IElement;
+import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
+import org.simantics.scenegraph.g2d.events.command.CommandEvent;
+import org.simantics.scenegraph.g2d.events.command.Commands;
+import org.simantics.utils.DataContainer;
+import org.simantics.utils.datastructures.collections.CollectionUtils;
+import org.simantics.utils.datastructures.hints.IHintContext.Key;
+import org.simantics.utils.datastructures.hints.IHintContext.MouseSpecificKeyOf;
+import org.simantics.utils.threads.ThreadUtils;
+
+/**
+ * Selection is a canvas utility used for managing selected elements.
+ * <p>
+ * There are multiple selection context. They are differentiated with selectionId.
+ * Multiple selections are used in multi-user environments (such as multi touch screen).
+ * In normal diagram setup SELECTION0 is the default selection.
+ * 
+ * @author Toni Kalajainen
+ */
+public class Selection extends AbstractCanvasParticipant {
+
+    /** Key for the most common Selection0 */
+    public static final SelectionHintKey SELECTION0 = new SelectionHintKey(0);
+
+    private static final Set<IElement> NO_SELECTION = Collections
+    .unmodifiableSet(new HashSet<IElement>(0));
+
+    public static SelectionHintKey getKeyForSelectionId(int selectionId) {
+        if (selectionId == 0)
+            return SELECTION0;
+        return new SelectionHintKey(selectionId);
+    }
+
+    @EventHandler(priority = 0)
+    public boolean handleCommand(CommandEvent e)
+    {
+        if (e.command.equals( Commands.SELECT_ALL )) {
+            IDiagram d = getHint( DiagramHints.KEY_DIAGRAM );
+            if (d==null) return true;
+            addAll(0, d.getElements());
+            return true;
+        }
+        if (e.command.equals( Commands.INVERT_SELECTION )) {
+            IDiagram d = getHint( DiagramHints.KEY_DIAGRAM );
+            if (d==null) return true;
+            Set<IElement> current = getSelection(0);
+            Set<IElement> inverted = new HashSet<IElement>(d.getElements());
+            inverted.removeAll(current);
+            setSelection(0, inverted);
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * Get selection
+     * 
+     * @param selectionId
+     *            selectionId
+     * @return returns a set of pickables
+     */
+    public Set<IElement> getSelection(int selectionId) {
+        Key key = getKeyForSelectionId(selectionId);
+        Set<IElement> selection = getHint(key);
+        if (selection == null)
+            return NO_SELECTION;
+        return new HashSet<IElement>(selection);
+    }
+
+    /**
+     * Get all selections of all selection ids
+     * @return all selections
+     */
+    public Set<IElement> getAllSelections() {
+        Set<IElement> result = new HashSet<IElement>();
+        for (Entry<SelectionHintKey, Object> entry : getContext()
+                .getHintStack().getHintsOfClass(SelectionHintKey.class)
+                .entrySet()) {
+            @SuppressWarnings("unchecked")
+            Set<IElement> set = (Set<IElement>) entry.getValue();
+            if (set == null || set.isEmpty())
+                continue;
+            result.addAll(set);
+        }
+        return result;
+
+    }
+
+    /**
+     * Get selections by selection id
+     * 
+     * @return map of selection ids and selections
+     */
+    @SuppressWarnings("unchecked")
+    public Map<Integer, Set<IElement>> getSelections() {
+        Map<Integer, Set<IElement>> result = new HashMap<Integer, Set<IElement>>();
+        for (Entry<SelectionHintKey, Object> entry : getContext()
+                .getHintStack().getHintsOfClass(SelectionHintKey.class)
+                .entrySet()) {
+            Set<IElement> set = (Set<IElement>) entry.getValue();
+            if (set == null || set.isEmpty())
+                continue;
+            result.put(entry.getKey().mouseId, set);
+        }
+        return result;
+    }
+
+    public int[] getSelectionIds() {
+        Map<SelectionHintKey, Object> map = getContext().getHintStack()
+        .getHintsOfClass(SelectionHintKey.class);
+        int result[] = new int[map.size()];
+        int i = 0;
+        for (SelectionHintKey key : map.keySet())
+            result[i++] = key.mouseId;
+        return result;
+    }
+
+    public boolean setSelection(final int selectionId,
+            final Collection<IElement> _selection) {
+        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);
+        ThreadUtils.syncExec(getThread(), new Runnable() {
+            @Override
+            public void run() {
+                Collection<IElement> selection = _selection;
+                Key key = getKeyForSelectionId(selectionId);
+                if (selection == null || selection.isEmpty())
+                    selection = NO_SELECTION;
+                Set<IElement> oldSelection = getHint(key);
+                if (oldSelection == null)
+                    oldSelection = NO_SELECTION;
+                if (oldSelection.equals(selection))
+                    return;
+                if (selection == NO_SELECTION) {
+                    removeHint(key);
+                    result.set(true);
+                }
+                Set<IElement> newSelection = Collections
+                .unmodifiableSet(new HashSet<IElement>(selection));
+                setHint(key, newSelection);
+                result.set(true);
+            }
+        });
+        return result.get();
+    }
+
+    public boolean setSelection(int selectionId, IElement selection) {
+        ArrayList<IElement> list = new ArrayList<IElement>(1);
+        list.add(selection);
+        return setSelection(selectionId, list);
+    }
+
+    /**
+     * Add item to selection
+     * 
+     * @param pickable
+     */
+    public boolean add(final int selectionId, final IElement pickable) {
+        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);
+        ThreadUtils.syncExec(getThread(), new Runnable() {
+            @Override
+            public void run() {
+                Key key = getKeyForSelectionId(selectionId);
+                Set<IElement> oldSelection = getSelection(selectionId);
+                if (oldSelection.contains(pickable))
+                    return;
+                Set<IElement> newSelection = new HashSet<IElement>(
+                        oldSelection);
+                newSelection.add(pickable);
+                newSelection = Collections.unmodifiableSet(newSelection);
+                setHint(key, newSelection);
+                result.set(true);
+            }
+        });
+        return result.get();
+    }
+
+    /**
+     * Add items to mouse0's selection
+     * 
+     * @param pickables
+     * @return
+     */
+    public boolean addAll(final int selectionId,
+            final Collection<IElement> pickables) {
+        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);
+        ThreadUtils.syncExec(getThread(), new Runnable() {
+            @Override
+            public void run() {
+
+                Key key = getKeyForSelectionId(selectionId);
+                Set<IElement> selection = getSelection(selectionId);
+                if (selection.containsAll(pickables))
+                    return;
+                Set<IElement> newSelection = new HashSet<IElement>(selection);
+                newSelection.addAll(pickables);
+                newSelection = Collections.unmodifiableSet(newSelection);
+                setHint(key, newSelection);
+                result.set(true);
+            }
+        });
+        return result.get();
+    }
+
+    /**
+     * Remove an item from mouse0's selection
+     * 
+     * @param pickable
+     * @return
+     */
+    public boolean remove(final int selectionId, final IElement pickable) {
+        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);
+        ThreadUtils.syncExec(getThread(), new Runnable() {
+            @Override
+            public void run() {
+                Key key = getKeyForSelectionId(selectionId);
+                Set<IElement> oldSelection = getSelection(selectionId);
+                if (!oldSelection.contains(pickable))
+                    return;
+                Set<IElement> newSelection = new HashSet<IElement>(
+                        oldSelection);
+                newSelection.remove(pickable);
+                newSelection = Collections.unmodifiableSet(newSelection);
+                setHint(key, newSelection);
+                result.set(true);
+            }
+        });
+        return result.get();
+    }
+
+    /**
+     * Returns true if two collections have a common object
+     * 
+     * @param x
+     * @param y
+     * @return
+     */
+    public static boolean containsAny(Collection<?> x, Collection<?> y) {
+        for (Object o : x)
+            if (y.contains(o))
+                return true;
+        return false;
+    }
+
+    /**
+     * Remove items from mouse0's selection
+     * 
+     * @param pickables
+     * @return
+     */
+    public boolean removeAll(final int selectionId,
+            final Collection<IElement> pickables) {
+        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);
+        ThreadUtils.syncExec(getThread(), new Runnable() {
+            @Override
+            public void run() {
+                Key key = getKeyForSelectionId(selectionId);
+                Set<IElement> oldSelection = getSelection(selectionId);
+                if (!containsAny(oldSelection, pickables))
+                    return;
+                Set<IElement> newSelection = new HashSet<IElement>(
+                        oldSelection);
+                newSelection.removeAll(pickables);
+                newSelection = Collections.unmodifiableSet(newSelection);
+                setHint(key, newSelection);
+                result.set(true);
+            }
+        });
+        return result.get();
+    }
+
+    /**
+     * Retain items in mouse0's selection
+     * 
+     * @param pickable
+     * @return
+     */
+    public boolean retainAll(final int selectionId,
+            final Collection<IElement> pickable) {
+        final DataContainer<Boolean> result = new DataContainer<Boolean>(false);
+        ThreadUtils.syncExec(getThread(), new Runnable() {
+            @Override
+            public void run() {
+                Key key = getKeyForSelectionId(selectionId);
+                Set<IElement> oldSelection = getSelection(selectionId);
+                Set<IElement> newSelection = new HashSet<IElement>(
+                        oldSelection);
+                newSelection.retainAll(pickable);
+                if (oldSelection.equals(newSelection))
+                    return;
+                newSelection = Collections.unmodifiableSet(newSelection);
+                setHint(key, newSelection);
+                result.set(true);
+            }
+        });
+        return result.get();
+    }
+
+    public boolean contains(int selectionId, IElement pickable) {
+        Set<IElement> oldSelection = getSelection(selectionId);
+        return oldSelection.contains(pickable);
+    }
+
+    public synchronized void toggle(final int selectionId, final Set<IElement> toggleSet) {
+        ThreadUtils.syncExec(getThread(), new Runnable() {
+            @Override
+            public void run() {
+                Key key = getKeyForSelectionId(selectionId);
+                Set<IElement> oldSelection = getSelection(selectionId);
+                Set<IElement> newSelection = new HashSet<IElement>(oldSelection);
+                CollectionUtils.toggle(newSelection, toggleSet);
+                newSelection = Collections.unmodifiableSet(newSelection);
+                setHint(key, newSelection);
+            }
+        });
+    }
+
+    /**
+     * Toggle an item in a selection.
+     */
+    public synchronized void toggle(int selectionId, IElement pickable) {
+        Key key = getKeyForSelectionId(selectionId);
+        Set<IElement> oldSelection = getSelection(selectionId);
+        Set<IElement> newSelection = new HashSet<IElement>(oldSelection);
+
+        if (oldSelection.contains(pickable))
+            newSelection.remove(pickable);
+        else
+            newSelection.add(pickable);
+
+        newSelection = Collections.unmodifiableSet(newSelection);
+        setHint(key, newSelection);
+    }
+
+    /**
+     * Clear selection
+     */
+    public void clear(int selectionId) {
+        Key key = getKeyForSelectionId(selectionId);
+        removeHint(key);
+    }
+
+    /** Class for mouse specific hint keys */
+    public static class SelectionHintKey extends MouseSpecificKeyOf {
+        public SelectionHintKey(int mouseId) {
+            super(mouseId, Set.class);
+        }
+    }
+
+
+}