/******************************************************************************* * Copyright (c) 2000, 2010, 2012 IBM Corporation, Gerhardt Informatics Kft. and others. * 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: * IBM Corporation - initial API and implementation * Gerhardt Informatics Kft. - GEFGWT port *******************************************************************************/ package org.eclipse.gef; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.widgets.Control; /** * Manages a viewer's selection model. Selection management includes * representing a form of selection which is available to clients of a viewer as * an ISelection. It also includes managing the notion of focus, which is * closely tied to the current selection. The selection manager provides the * mechanism for modifying the selection and any validation. * <P> * WARNING: Subclassing this class is considered experimental at this point. * * @since 3.2 */ public class SelectionManager { private EditPart focusPart; private Runnable notifier; private List selection; private EditPartViewer viewer; /** * Default Constructor * * @since 3.2 */ protected SelectionManager() { } /** * Creates the default implementation for a selection manager. * * @return the default selection manager * @since 3.2 */ public static SelectionManager createDefault() { return new SelectionManager(); } /** * Appends the <code>EditPart</code> to the current selection. The EditPart * becomes the new primary selection. Fires selection changed to all * {@link org.eclipse.jface.viewers.ISelectionChangedListener}s. * * @param editpart * the EditPart to append * @since 3.2 */ public void appendSelection(EditPart editpart) { if (editpart != getFocus()) viewer.setFocus(null); if (!selection.isEmpty()) { EditPart primary = (EditPart) selection.get(selection.size() - 1); primary.setSelected(EditPart.SELECTED); } // if the editpart is already in the list, re-order it to be the last // one selection.remove(editpart); selection.add(editpart); editpart.setSelected(EditPart.SELECTED_PRIMARY); fireSelectionChanged(); } /** * Removes the <code>EditPart</code> from the current selection. * * @param editpart * the editpart * @since 3.2 */ public void deselect(EditPart editpart) { editpart.setSelected(EditPart.SELECTED_NONE); selection.remove(editpart); if (!selection.isEmpty()) { // IMPORTANT: it may (temporarily) happen that the selection list // contains edit parts, which are not selectable (any more) when // this method gets called. Consider e.g. that the selectable state // of an edit part may bound to its activation state (by overwriting // isSelectable()); in this case, when deleting a selected edit part // and its primary selected child simultaneously, the parent edit // part may have already become non selectable, while not having // been deselected yet (because deselection is performed within // removeNotify() after deactivation), when the child edit part gets // deselected. Therefore, we do not simply choose the last edit part // in the list as the new primary selection, but reverse-search the // list for the first that is (still) selectable. for (int i = selection.size() - 1; i >= 0; i--) { EditPart primaryCandidate = (EditPart) selection.get(i); if (primaryCandidate.isSelectable()) { primaryCandidate.setSelected(EditPart.SELECTED_PRIMARY); break; } } } fireSelectionChanged(); } /** * Deselects everything. * * @since 3.2 */ public void deselectAll() { EditPart part; setFocus(null); for (int i = 0; i < selection.size(); i++) { part = (EditPart) selection.get(i); part.setSelected(EditPart.SELECTED_NONE); } selection.clear(); fireSelectionChanged(); } /** * Causes the viewer to fire selection changed notification to all * listeners. * * @since 3.2 */ protected final void fireSelectionChanged() { notifier.run(); } /** * Returns the focus editpart. * * @return the focus editpart * @since 3.2 */ protected EditPart getFocus() { return focusPart; } /** * Returns the current selection. * * @return the selection * @since 3.2 */ public ISelection getSelection() { if (selection.isEmpty() && viewer.getContents() != null) return new StructuredSelection(viewer.getContents()); return new StructuredSelection(selection); } /** * Returns <code>null</code> or the viewer whose selection is managed. * * @return <code>null</code> or the viewer * @since 3.2 */ protected EditPartViewer getViewer() { return viewer; } /** * For internal use only. This API is subject to change. * * @param control * the control * @since 3.2 */ public void internalHookControl(Control control) { } /** * For internal use only. This API is subject to change. * * @since 3.2 */ public void internalUninstall() { } /** * Provides a hook for when the viewer has been set. * * @param viewer * the viewer. * @since 3.2 */ protected void hookViewer(EditPartViewer viewer) { } /** * For internal use only. * * @param viewer * viewer * @param selection * selection * @param notifier * notifier * @since 3.2 */ public void internalInitialize(EditPartViewer viewer, List selection, Runnable notifier) { this.viewer = viewer; this.selection = selection; this.notifier = notifier; hookViewer(viewer); } /** * Sets the focus part. * * @param part * the focus part * @since 3.2 */ public void setFocus(EditPart part) { if (focusPart == part) return; if (focusPart != null) focusPart.setFocus(false); focusPart = part; if (focusPart != null) focusPart.setFocus(true); } /** * Sets the selection. * * @param newSelection * the new selection * @since 3.2 */ public void setSelection(ISelection newSelection) { if (!(newSelection instanceof IStructuredSelection)) return; List orderedSelection = ((IStructuredSelection) newSelection).toList(); // Convert to HashSet to optimize performance. Collection hashset = new HashSet(orderedSelection); setFocus(null); for (int i = 0; i < selection.size(); i++) { EditPart part = (EditPart) selection.get(i); if (!hashset.contains(part)) part.setSelected(EditPart.SELECTED_NONE); } selection.clear(); if (!orderedSelection.isEmpty()) { Iterator itr = orderedSelection.iterator(); while (true) { EditPart part = (EditPart) itr.next(); selection.add(part); if (!itr.hasNext()) { part.setSelected(EditPart.SELECTED_PRIMARY); break; } part.setSelected(EditPart.SELECTED); } } fireSelectionChanged(); } }