/***************************************************************************** * Copyright (c) 2010 CEA LIST. * * * 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: * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.menu.actions; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Set; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.gef.ConnectionEditPart; import org.eclipse.gef.EditPart; import org.eclipse.gef.EditPartViewer; import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.GroupEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IPrimaryEditPart; import org.eclipse.gmf.runtime.diagram.ui.internal.editparts.ISurfaceEditPart; import org.eclipse.jface.viewers.StructuredSelection; /** * Adapted from {@link SelectAllAction} * * * */ public class SelectAction extends AbstractParametricAction { /** parameters for the action */ /** * the parameter for select all * This parameter should not be used, because, in the plugin.xml file, * we use the command org.eclipse.ui.edit.selectAll for this action. * GMF seems provide an handler for this action, because with this command, we visit the class {@link SelectAllAction} */ public static final String SELECT_ALL = "selectAll"; //$NON-NLS-1$ /** the parameter for select all shapes action */ public static final String SELECT_ALL_SHAPES = "selectAllShapes"; //$NON-NLS-1$ /** the parameter for select all connectors action */ public static final String SELECT_ALL_CONNECTORS = "selectAllConnectors"; //$NON-NLS-1$ /** * this value indicates if we select the shapes or not */ protected boolean selectShapes = false; /** * this value indicates if we select the connections or not */ protected boolean selectConnections = false; /** * * Constructor. * * @param parameter */ public SelectAction(String parameter, List<IGraphicalEditPart> selectedElements) { super(parameter, selectedElements); initAction(); } protected void initAction() { if(SELECT_ALL.equals(getParameter())) { this.selectShapes = true; this.selectConnections = true; } else if(SELECT_ALL_SHAPES.equals(getParameter())) { this.selectShapes = true; } else if(SELECT_ALL_CONNECTORS.equals(getParameter())) { this.selectConnections = true; } } /** * * @see org.eclipse.papyrus.uml.diagram.menu.actions.AbstractParametricAction#isEnabled() * * @return */ @Override public boolean isEnabled() { return !getSelection().isEmpty(); } @Override public void doRun(IProgressMonitor progressMonitor) { getDiagramGraphicalViewer().setSelection(new StructuredSelection(createOperationSet())); } /** * * @see org.eclipse.papyrus.uml.diagram.menu.actions.AbstractParametricAction#getSelection() * * @return */ @Override protected List<IGraphicalEditPart> getSelection() { // TODO Auto-generated method stub return super.getSelection(); } /** * The operation set is the shapes, connections or both on the diagram edit part */ protected List createOperationSet() { List selection = getSelection(); if(selection.isEmpty() || !(selection.get(0) instanceof IGraphicalEditPart)) return Collections.EMPTY_LIST; List selectables = new ArrayList(); EditPart primaryEP = (EditPart)selection.get(selection.size() - 1); List nodeEditParts = new ArrayList(); nodeEditParts.addAll(getSelectableNodes(primaryEP)); if(selectShapes) selectables.addAll(nodeEditParts); if(selectConnections) selectables.addAll(addSelectableConnections(nodeEditParts)); return filterEditPartsMatching(selectables, getSelectionConditional()); } /** * Determines the candidate list of node editparts for selection * * @param editpart * @return */ protected List getSelectableNodes(EditPart editpart) { if(editpart == null) { return Collections.EMPTY_LIST; } List retval = new ArrayList(); getSelectableNodesInside(editpart, true, retval); return retval; } /** * Determines the candidate list of node editparts for selection * * @param editpart * @param topLevel * <code>boolean</code> is this the initial entry point into the recursive method. * @param retval * <code>List</code> to modify */ private void getSelectableNodesInside(EditPart editpart, boolean topLevel, List retval) { if(editpart instanceof ISurfaceEditPart) { getSelectableChildrenNodes(editpart, retval); } else if(editpart instanceof IPrimaryEditPart) { if(topLevel) { if(editpart instanceof ConnectionEditPart) { ConnectionEditPart connection = (ConnectionEditPart)editpart; EditPart source = connection.getSource(); EditPart target = connection.getTarget(); if(source != null && target != null) { getSelectableNodesInside(source, true, retval); if(target.getParent() != source.getParent()) getSelectableNodesInside(target, true, retval); } } else getSelectableNodesInside(editpart.getParent(), true, retval); } else { if(editpart.isSelectable()) retval.add(editpart); // Do not dig into groups -- just select the group, but not the // shapes inside. if(!(editpart instanceof GroupEditPart)) { getSelectableChildrenNodes(editpart, retval); } } } } /** * * @param editpart * an editpart * @param retval * the selectable node inside this editpart */ private void getSelectableChildrenNodes(EditPart editpart, List retval) { Iterator iter = editpart.getChildren().iterator(); while(iter.hasNext()) { EditPart child = (EditPart)iter.next(); getSelectableNodesInside(child, false, retval); } } /** * This method searches an edit part for a child that is a border item edit part * * @param parent * part needed to search * @param set * to be modified of border item edit parts that are direct children of the parent */ private void getBorderItemEditParts(EditPart parent, Set retval) { Iterator iter = parent.getChildren().iterator(); while(iter.hasNext()) { EditPart child = (EditPart)iter.next(); if(child instanceof IBorderItemEditPart) { retval.add(child); retval.addAll(child.getChildren()); } getBorderItemEditParts(child, retval); } } /** * Determines the candidate list of connection edit for selection * A connection is included if atleast the source or the target is * included in the given list * * @param editparts */ protected List addSelectableConnections(List editparts) { List selectableConnections = new ArrayList(); DiagramEditPart diagramEditPart = getDiagramEditPart(); Set connnectableEditParts = new HashSet(editparts); ListIterator li = editparts.listIterator(); while(li.hasNext()) { EditPart ep = (EditPart)li.next(); getBorderItemEditParts(ep, connnectableEditParts); if(ep instanceof GroupEditPart) { connnectableEditParts.addAll(((GroupEditPart)ep).getShapeChildren()); } } if(diagramEditPart != null) { Iterator connections = diagramEditPart.getConnections().iterator(); while(connections.hasNext()) { ConnectionEditPart connection = (ConnectionEditPart)connections.next(); if(canSelectConnection(connection, connnectableEditParts)) selectableConnections.add(connection); } } return selectableConnections; } /** * Determines whether the given connection can be selected. First checks * whether the source or target of the connection is in the given * connetableEditPart list. If it isn't it checks recursively whether the source * or target of the connection is another connection and if that connection's * source or target is in the given connectableEditPart list. This is in * response to Bugzilla #162083. * * @param connection * connection to check * @param connectableEditParts */ private boolean canSelectConnection(ConnectionEditPart connection, Set connectableEditParts) { EditPart connectionSource = connection.getSource(); EditPart connectionTarget = connection.getTarget(); boolean sourceHasSelectable = false; boolean targetHasSelectable = false; if(connectableEditParts.contains(connectionSource) || connectableEditParts.contains(connectionTarget)) return true; if(connectionSource instanceof ConnectionEditPart) sourceHasSelectable = canSelectConnection((ConnectionEditPart)connectionSource, connectableEditParts); if(!sourceHasSelectable && connectionTarget instanceof ConnectionEditPart) targetHasSelectable = canSelectConnection((ConnectionEditPart)connectionTarget, connectableEditParts); return sourceHasSelectable || targetHasSelectable; } /** * @return The Selection Conditional which tests if the editpart is selectable */ protected EditPartViewer.Conditional getSelectionConditional() { return new EditPartViewer.Conditional() { public boolean evaluate(EditPart editpart) { return editpart.isSelectable(); } }; } /** * Filters the given list of EditParts so that the list only contains the * EditParts that matches the given condition. * * @param list * the list of edit parts to filter * @param condition * the condition * @return a modified list containing those editparts that matched the * condition */ protected List filterEditPartsMatching(List list, EditPartViewer.Conditional condition) { List matchList = new ArrayList(); Iterator iter = list.iterator(); while(iter.hasNext()) { EditPart ep = (EditPart)iter.next(); if(condition.evaluate(ep)) matchList.add(ep); } return matchList; } }