/***************************************************************************** * Copyright (c) 2009-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.Comparator; import java.util.List; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PointList; import org.eclipse.draw2d.geometry.PrecisionPoint; import org.eclipse.draw2d.geometry.PrecisionRectangle; import org.eclipse.gef.ConnectionEditPart; import org.eclipse.gef.EditPart; import org.eclipse.gef.Request; import org.eclipse.gef.commands.Command; import org.eclipse.gef.commands.CompoundCommand; import org.eclipse.gef.commands.UnexecutableCommand; import org.eclipse.gef.requests.ChangeBoundsRequest; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants; import org.eclipse.gmf.runtime.diagram.ui.requests.SetAllBendpointRequest; import org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator; import org.eclipse.papyrus.uml.diagram.common.editparts.BorderNamedElementEditPart; import org.eclipse.papyrus.uml.diagram.common.layout.DistributionConstants; import org.eclipse.papyrus.uml.diagram.common.layout.LayoutUtils; import org.eclipse.papyrus.uml.diagram.common.layout.LinkRepresentationForLayoutAction; import org.eclipse.papyrus.uml.diagram.common.util.Util; import org.eclipse.papyrus.uml.diagram.menu.Activator; /** * This class provides the action to distribute links and ports on a side of a node * Two modes are available for this action : * <ul> * <li>DISTRIBUTE_ON_ONE_END : the user selects links(and affixed child nodes) and nodes to do the distribution the distribution is done only on this * node</li> * <li>DISTRIBUTE_ON_TWO_END: the user selects only links (and affixed child nodes) ,the distribution is done on the source node and one the target * node</li> * </ul> * The behavior for Affixed child nodes is the same in the 2 modes, they are distributed in the same time that links. */ public class DistributeAffixedChildNodeLinkAction extends AbstractDistributeAction { /** This list is used to regroup the selected elements by their common parent. */ private List<NodeRepresentation> commonParentRepresentations; /** mode used for this action. */ private int mode; /** constant for the link selection mode. */ public final static int DISTRIBUTE_ON_ONE_END = 1; /** constant for the link/node selection. */ public final static int DISTRIBUTE_ON_TWO_END = DISTRIBUTE_ON_ONE_END + 1; /** * * Constructor. * * @param distribution * the distribution * @param selectedElements * the selected elements to do the distribution */ public DistributeAffixedChildNodeLinkAction(int distribution, List<IGraphicalEditPart> selectedElements) { super(distribution, selectedElements); } /** * Builds the action. * * @param list * the list * @see org.eclipse.papyrus.uml.diagram.common.actions.AbstractDistributeAction#buildAction(java.util.List) */ @Override protected void buildAction(List<?> list) { this.commonParentRepresentations = new ArrayList<DistributeAffixedChildNodeLinkAction.NodeRepresentation>(); // we sort the list to get this order: // 1: possible parents EditPart // 2: Affixed Child Node // 3: ConnectionEditPart Collections.sort(list, new TypeComparator()); this.mode = getMode(list); for(Object current : list) { if((current instanceof ConnectionEditPart)) { switch(this.mode) { case DISTRIBUTE_ON_ONE_END: //the link representation is owned by only one NodeRepresentation NodeRepresentation representation = getCorrespondingRepresentation((EditPart)current); if(representation != null) { LinkRepresentationForLayoutAction link = new LinkRepresentationForLayoutAction((ConnectionEditPart)current); representation.addElements(link); } else {//no source and no target are in the selection, this link will no be managed } break; case DISTRIBUTE_ON_TWO_END://the link representation is owned by two NodeRepresentation NodeRepresentation representationSource = getCorrespondingRepresentation(((ConnectionEditPart)current).getSource()); NodeRepresentation representationTarget = getCorrespondingRepresentation(((ConnectionEditPart)current).getTarget()); LinkRepresentationForLayoutAction linkRep = new LinkRepresentationForLayoutAction((ConnectionEditPart)current); //we add the source and the target of the link in the commonParentRepresentations if(representationSource == null) { representationSource = new NodeRepresentation(((ConnectionEditPart)current).getSource()); this.commonParentRepresentations.add(representationSource); } if(representationTarget == null) { representationTarget = new NodeRepresentation(((ConnectionEditPart)current).getTarget()); this.commonParentRepresentations.add(representationTarget); } representationSource.addElements(linkRep); representationTarget.addElements(linkRep); break; default: break; } } else if(Util.isAffixedChildNode((EditPart)current)) { NodeRepresentation representation = getCorrespondingRepresentation((EditPart)current); if(representation != null) { representation.addElements(new AffixedChildNodeRepresentation((EditPart)current)); } else { representation = new NodeRepresentation(((EditPart)current).getParent()); this.commonParentRepresentations.add(representation); representation.addElements(new AffixedChildNodeRepresentation((EditPart)current));; } } else { this.commonParentRepresentations.add(new NodeRepresentation((EditPart)current)); } } } /** * Return the mode for this selection. * * @param list * the list of the elements to distribute * @return the mode * the mode for this selection */ protected int getMode(List<?> list) { for(Object current : list) { if(current instanceof ConnectionEditPart) { EditPart source = ((ConnectionEditPart)current).getSource(); EditPart target = ((ConnectionEditPart)current).getTarget(); if(list.contains(source) || list.contains(target)) { return DISTRIBUTE_ON_ONE_END; } } } return DISTRIBUTE_ON_TWO_END; } /** * Gets the command. * * @return the command * @see org.eclipse.papyrus.uml.diagram.common.actions.AbstractDistributeAction#getCommand() */ @Override public Command getCommand() { CompoundCommand command = new CompoundCommand("Distribute Affixed Child Nodes and Links"); //$NON-NLS-1$ if(canExistCommand(this.selectedElements) && onOppositeSide()) { for(NodeRepresentation current : this.commonParentRepresentations) { Command cmd = current.getCommand(); if(cmd != null && cmd.canExecute()) { command.add(cmd); } } } return command.isEmpty() ? UnexecutableCommand.INSTANCE : (Command)command; } /** * On opposite side. * * @return true, if successful */ protected boolean onOppositeSide() { for(NodeRepresentation current : this.commonParentRepresentations) { if(!current.onCorrectSide()) { return false; } } return true; } /** * Return The {@link NodeRepresentation} owning the editpart or <code>null</code> if not found. * * @param ep * an editpart * @return the corresponding representation * The {@link NodeRepresentation} owning the editpart or <code>null</code> if not found */ protected NodeRepresentation getCorrespondingRepresentation(EditPart ep) { if(ep instanceof ConnectionEditPart) { EditPart source = ((ConnectionEditPart)ep).getSource(); EditPart target = ((ConnectionEditPart)ep).getTarget(); for(NodeRepresentation current : commonParentRepresentations) { EditPart node = current.getRepresentedNode(); if(node == source || node == target) { return current; } } } else if(Util.isAffixedChildNode(ep)) { EditPart parent = ep.getParent(); for(NodeRepresentation current : commonParentRepresentations) { if(current.getRepresentedNode() == parent) { return current; } } } else {// we look for a represented node for(NodeRepresentation current : commonParentRepresentations) { EditPart node = current.getRepresentedNode(); if(node == ep) { return current; } } } return null; } //Replaced by a new method in util.Util // /** // * Test if the EditPart is an Affixed Child Node. // * // * @param ep // * an EditPart // * @return true, if is affixed child node <code>true</code> if the {@link EditPart} is an affixed child node and <code>false</code> if not // */ // protected boolean isAffixedChildNode(EditPart ep) { // if(ep.getParent() instanceof CompartmentEditPart) { // return false; // } else if(ep.getParent() instanceof DiagramEditPart) { // return false; // } // return true; // } /** * This class provides facilities to represent a parent with its children that we want to distribute. * The element to distribute should be {@link LinkRepresentationForLayoutAction} of {@link AffixedChildNodeRepresentation} * */ protected class NodeRepresentation { /** the node represented by this class. */ private EditPart representedNode; /** the elements to distribute. */ private List<Object> elementsToDistribute; /** * * Constructor. * * @param representedNode * the represented EditPart */ public NodeRepresentation(EditPart representedNode) { this.representedNode = representedNode; elementsToDistribute = new ArrayList<Object>(); } /** * Test if the elements to distribute are on a correct side. * * @return <code>true</code>, if successful, <code>false</code> if not */ public boolean onCorrectSide() { for(Object current : elementsToDistribute) { if(current instanceof AffixedChildNodeRepresentation) { int side = ((AffixedChildNodeRepresentation)current).getSideOnParent(); if(distribution == DistributionConstants.DISTRIBUTE_H_CONTAINER_INT || distribution == DistributionConstants.DISTRIBUTE_H_NODES_INT) { if(!DistributionConstants.horizontalValuesList.contains(side)) { return false; } } else {//vertical distribution if(!DistributionConstants.verticalValuesList.contains(side)) { return false; } } } else if(current instanceof LinkRepresentationForLayoutAction) { int sourceSide = ((LinkRepresentationForLayoutAction)current).getSideOnSource(); int targetSide = ((LinkRepresentationForLayoutAction)current).getSideOnTarget(); if(distribution == DistributionConstants.DISTRIBUTE_H_CONTAINER_INT || distribution == DistributionConstants.DISTRIBUTE_H_NODES_INT) { if(!DistributionConstants.horizontalValuesList.contains(sourceSide) && !DistributionConstants.horizontalValuesList.contains(targetSide)) { return false; } } else {//vertical distribution if(!DistributionConstants.verticalValuesList.contains(sourceSide) && !DistributionConstants.verticalValuesList.contains(targetSide)) { return false; } } } } return true; } /** * This method calculates the new position for the elements */ public void calculateNewLocations() { //we sort the element by coordinates Collections.sort(this.elementsToDistribute, new CoordinatesComparator(representedNode)); PrecisionRectangle boundsArea = calcultateArea(this.representedNode); double[] hSpaceAndvSpace = calculatesSpaceBetweenNodes(boundsArea, this.elementsToDistribute, representedNode); //variable containing the new position for the editpart (x or y following the distribution) double newPosition = 0; //we determine the location for the first editpart switch(distribution) { case DistributionConstants.DISTRIBUTE_H_CONTAINER_INT: newPosition = (horizontalDegradedMode == false) ? (boundsArea.preciseX + hSpaceAndvSpace[0]) : boundsArea.preciseX(); break; case DistributionConstants.DISTRIBUTE_H_NODES_INT: newPosition = boundsArea.preciseX; break; case DistributionConstants.DISTRIBUTE_V_CONTAINER_INT: newPosition = (verticalDegradedMode == false) ? (boundsArea.preciseY + hSpaceAndvSpace[1]) : boundsArea.preciseY(); break; case DistributionConstants.DISTRIBUTE_V_NODES_INT: newPosition = boundsArea.preciseY; break; default: break; } //these 4 booleans indicates if we have already consider a port located on a bad side for the chosen action boolean eastPort = false; boolean westPort = false; boolean northPort = false; boolean southPort = false; for(Object current : elementsToDistribute) { int side = PositionConstants.NONE; PrecisionRectangle absolutePosition = null; //the new location for the editpart PrecisionPoint ptLocation = null; if(current instanceof LinkRepresentationForLayoutAction) { side = ((LinkRepresentationForLayoutAction)current).getCurrentSideOn(representedNode); absolutePosition = ((LinkRepresentationForLayoutAction)current).getAbsolutePositionOn(representedNode); } else if(current instanceof AffixedChildNodeRepresentation) { side = ((AffixedChildNodeRepresentation)current).getSideOnParent(); absolutePosition = ((AffixedChildNodeRepresentation)current).getAbsolutePosition(); } switch(distribution) { case DistributionConstants.DISTRIBUTE_H_CONTAINER_INT: if(DistributionConstants.horizontalValuesList.contains(side)) { ptLocation = new PrecisionPoint(newPosition, absolutePosition.preciseY); newPosition += absolutePosition.preciseWidth() + hSpaceAndvSpace[0]; } break; case DistributionConstants.DISTRIBUTE_H_NODES_INT: if(DistributionConstants.horizontalValuesList.contains(side)) { ptLocation = new PrecisionPoint(newPosition, absolutePosition.preciseY); newPosition += absolutePosition.preciseWidth() + hSpaceAndvSpace[0]; } else if(eastPort == false && side == PositionConstants.EAST) { eastPort = true; ptLocation = new PrecisionPoint(absolutePosition.preciseX, absolutePosition.preciseY); newPosition += absolutePosition.preciseWidth() + hSpaceAndvSpace[0]; } else if(westPort == false && side == PositionConstants.WEST) { westPort = true; ptLocation = new PrecisionPoint(absolutePosition.preciseX, absolutePosition.preciseY); newPosition += absolutePosition.preciseWidth() + hSpaceAndvSpace[0]; } break; case DistributionConstants.DISTRIBUTE_V_CONTAINER_INT: if(DistributionConstants.verticalValuesList.contains(side)) { ptLocation = new PrecisionPoint(absolutePosition.preciseX, newPosition); newPosition += absolutePosition.preciseHeight() + hSpaceAndvSpace[1]; } break; case DistributionConstants.DISTRIBUTE_V_NODES_INT: if(DistributionConstants.verticalValuesList.contains(side)) { ptLocation = new PrecisionPoint(absolutePosition.preciseX, newPosition); newPosition += absolutePosition.preciseHeight() + hSpaceAndvSpace[1]; } else if(northPort == false && side == PositionConstants.NORTH) { northPort = true; ptLocation = new PrecisionPoint(absolutePosition.preciseX, absolutePosition.preciseY); newPosition += absolutePosition.preciseHeight() + hSpaceAndvSpace[1]; } else if(southPort == false && side == PositionConstants.SOUTH) { southPort = true; ptLocation = new PrecisionPoint(absolutePosition.preciseX, absolutePosition.preciseY); newPosition += absolutePosition.preciseHeight() + hSpaceAndvSpace[1]; } break; default: break; } if(current instanceof LinkRepresentationForLayoutAction) { ((LinkRepresentationForLayoutAction)current).setNewLocationFor(representedNode, ptLocation); } else if(current instanceof AffixedChildNodeRepresentation) { ((AffixedChildNodeRepresentation)current).setNewLocation(ptLocation); } } } /** * Return the command for this aciton * * @return * the command for this action */ public Command getCommand() { calculateNewLocations(); CompoundCommand command = new CompoundCommand("Distribute Command"); //$NON-NLS-1$ for(Object obj : elementsToDistribute) { Command cmd = null; if(obj instanceof AffixedChildNodeRepresentation) { cmd = ((AffixedChildNodeRepresentation)obj).getCommand(); } else if(obj instanceof LinkRepresentationForLayoutAction) { cmd = new CompoundCommand("Move Link and remove bendpoints"); //$NON-NLS-1$ ((CompoundCommand)cmd).add(((LinkRepresentationForLayoutAction)obj).getCommand()); //we remove the bendpoints Request noBendpoints = new SetAllBendpointRequest(RequestConstants.REQ_SET_ALL_BENDPOINT, new PointList(), null, null); ((CompoundCommand)cmd).add(((LinkRepresentationForLayoutAction)obj).getRepresentedLink().getCommand(noBendpoints)); } if(cmd != null && cmd.canExecute()) { command.add(cmd); } } return command; } /** * Calculate the area to do the distribution. * * @param node * the EditPart owning the elements to distribute * @return the precision rectangle * the area used to do the distribution */ protected PrecisionRectangle calcultateArea(EditPart node) { PrecisionRectangle bounds = new PrecisionRectangle(); Object first = elementsToDistribute.get(0); Object last = elementsToDistribute.get(elementsToDistribute.size() - 1); Point locStart = new Point(); PrecisionRectangle locEnd = new PrecisionRectangle(); switch(distribution) { case DistributionConstants.DISTRIBUTE_H_CONTAINER_INT: case DistributionConstants.DISTRIBUTE_V_CONTAINER_INT: bounds = LayoutUtils.getAbsolutePosition(node); break; case DistributionConstants.DISTRIBUTE_H_NODES_INT: if(first instanceof LinkRepresentationForLayoutAction) { locStart = ((LinkRepresentationForLayoutAction)first).getAbsoluteLocationOn(representedNode); } else if(first instanceof AffixedChildNodeRepresentation) { locStart = ((AffixedChildNodeRepresentation)first).getAbsoluteLocation(); } if(last instanceof LinkRepresentationForLayoutAction) { locEnd = ((LinkRepresentationForLayoutAction)last).getAbsolutePositionOn(representedNode); } else if(last instanceof AffixedChildNodeRepresentation) { locEnd = ((AffixedChildNodeRepresentation)last).getAbsolutePosition(); } bounds.setLocation(locStart); bounds.setHeight(0); bounds.setWidth(locEnd.getRight().preciseX() - locStart.preciseX()); break; case DistributionConstants.DISTRIBUTE_V_NODES_INT: if(first instanceof LinkRepresentationForLayoutAction) { locStart = ((LinkRepresentationForLayoutAction)first).getAbsoluteLocationOn(representedNode); } else if(first instanceof AffixedChildNodeRepresentation) { locStart = ((AffixedChildNodeRepresentation)first).getAbsoluteLocation(); } if(last instanceof LinkRepresentationForLayoutAction) { locEnd = ((LinkRepresentationForLayoutAction)last).getAbsolutePositionOn(representedNode); } else if(last instanceof AffixedChildNodeRepresentation) { locEnd = ((AffixedChildNodeRepresentation)last).getAbsolutePosition(); } bounds.setLocation(locStart); bounds.setHeight(locEnd.getBottom().preciseY() - locStart.preciseY()); bounds.setWidth(0); break; default: break; } return bounds; } /** * Add an element to {@link #elementsToDistribute}. * * @param obj * the obj */ public void addElements(Object obj) { if(!(obj instanceof AffixedChildNodeRepresentation)) { if(!(obj instanceof LinkRepresentationForLayoutAction)) { Activator.log.debug("The added element has not a correct type"); //$NON-NLS-1$ } } this.elementsToDistribute.add(obj); } /** * Gets the represented node. * * @return the represented node */ public EditPart getRepresentedNode() { return representedNode; } /** * Calculates the horizontal space and the vertical space to distribute the nodes * Set the fields {@link #horizontalDegradedMode} and {@link #verticalDegradedMode} to {@code true} or {@code false}. * * @param boundsArea * the Rectangle used to do the distribution * @param nodeChild * the node to distribute in the Rectangle * @param node * the node * @return {@code double[2]} with : * */ protected double[] calculatesSpaceBetweenNodes(PrecisionRectangle boundsArea, List<Object> nodeChild, EditPart node) { //reset these 2 fields setHorizontalDegradedMode(false); setVerticalDegradedMode(false); //variables used to calculate the spacing double vertical = 0; double horizontal = 0; double vSpace = 0; double hSpace = 0; double[] hSpaceAndvSpace = new double[]{ 0, 0 }; //-------variables used when it's a port selection double nbPort = 0;//used to know the number of necessary spaces //if a port is on a bad side for the current alignment, we need to count it only one time! boolean eastPort = false; boolean westPort = false; boolean northPort = false; boolean southPort = false; //we calculate the length take by the element for(Object current : nodeChild) { PrecisionRectangle rect = new PrecisionRectangle(); int side = 0; if(current instanceof LinkRepresentationForLayoutAction) { rect = ((LinkRepresentationForLayoutAction)current).getAbsolutePositionOn(node); side = ((LinkRepresentationForLayoutAction)current).getCurrentSideOn(node); } else if(current instanceof AffixedChildNodeRepresentation) { rect = ((AffixedChildNodeRepresentation)current).getAbsolutePosition(); side = ((AffixedChildNodeRepresentation)current).getSideOnParent(); } switch(distribution) { case DistributionConstants.DISTRIBUTE_H_CONTAINER_INT: if(DistributionConstants.horizontalValuesList.contains(side)) { vertical += rect.preciseHeight(); horizontal += rect.preciseWidth(); nbPort++; } break; case DistributionConstants.DISTRIBUTE_H_NODES_INT: if(DistributionConstants.horizontalValuesList.contains(side)) { vertical += rect.preciseHeight(); horizontal += rect.preciseWidth(); nbPort++; } else if(side == PositionConstants.EAST && eastPort == false) { /* * the port located on this side are a limit for the action, * so we consider only one port located on the east side */ eastPort = true; vertical += rect.preciseHeight(); horizontal += rect.preciseWidth(); nbPort++; } else if(side == PositionConstants.WEST && westPort == false) { /* * the port located on this side are a limit for the action, * so we consider only one port located on the west side */ westPort = true; vertical += rect.preciseHeight(); horizontal += rect.preciseWidth(); nbPort++; } break; case DistributionConstants.DISTRIBUTE_V_CONTAINER_INT: if(DistributionConstants.verticalValuesList.contains(side)) { vertical += rect.preciseHeight(); horizontal += rect.preciseWidth(); nbPort++; } break; case DistributionConstants.DISTRIBUTE_V_NODES_INT: if(DistributionConstants.verticalValuesList.contains(side)) { vertical += rect.preciseHeight(); horizontal += rect.preciseWidth(); nbPort++; } else if(side == PositionConstants.NORTH && northPort == false) { /* * the port located on this side are a limit for the action, * so we consider only one port located on the north side */ northPort = true; vertical += rect.preciseHeight(); horizontal += rect.preciseWidth(); nbPort++; } else if(side == PositionConstants.SOUTH && southPort == false) { /* * the port located on this side are a limit for the action, * so we consider only one port located on the south side */ southPort = true; vertical += rect.preciseHeight(); horizontal += rect.preciseWidth(); nbPort++; } break; default: break; } } //we determine the divisor double divisor; if(distribution == DistributionConstants.DISTRIBUTE_H_CONTAINER_INT || distribution == DistributionConstants.DISTRIBUTE_V_CONTAINER_INT) { divisor = nbPort + 1; } else { divisor = nbPort - 1; } hSpace = ((boundsArea.preciseWidth() - horizontal) / divisor); vSpace = ((boundsArea.preciseHeight() - vertical) / divisor); if(hSpace < 0/* && parentContainer */) { setHorizontalDegradedMode(true); double diff = boundsArea.preciseWidth() - horizontal; hSpace = diff / (divisor - 2); } if(vSpace < 0 /* && parentContainer */) { setVerticalDegradedMode(true); double diff = boundsArea.preciseHeight() - vertical; vSpace = diff / (divisor - 2); } hSpaceAndvSpace[0] = hSpace; hSpaceAndvSpace[1] = vSpace; return hSpaceAndvSpace; } } /** * The Class CoordinatesComparator. */ protected class CoordinatesComparator implements Comparator<Object> { /** The reference. */ private EditPart reference; /** * Instantiates a new coordinates comparator. * * @param ep * the ep */ public CoordinatesComparator(EditPart ep) { this.reference = ep; } /** * Compare. * * @param o1 * the o1 * @param o2 * the o2 * @return the int * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ public int compare(Object o1, Object o2) { Point location1 = new Point(); Point location2 = new Point(); if(o1 instanceof LinkRepresentationForLayoutAction) { location1 = ((LinkRepresentationForLayoutAction)o1).getAbsoluteLocationOn(reference); } else if(o1 instanceof AffixedChildNodeRepresentation) { location1 = ((AffixedChildNodeRepresentation)o1).getAbsoluteLocation(); } if(o2 instanceof LinkRepresentationForLayoutAction) { location2 = ((LinkRepresentationForLayoutAction)o2).getAbsoluteLocationOn(reference); } else if(o2 instanceof AffixedChildNodeRepresentation) { location2 = ((AffixedChildNodeRepresentation)o2).getAbsoluteLocation(); } if(distribution == DistributionConstants.DISTRIBUTE_H_CONTAINER_INT || distribution == DistributionConstants.DISTRIBUTE_H_NODES_INT) { if(location1.x < location2.x) { return -1; } else if(location1.x == location2.x) { return 0; } else { return 1; } } else { //vertical distribution if(location1.y < location2.y) { return -1; } else if(location1.y == location2.y) { return 0; } else { return 1; } } } } /** * This comparator sorts an EditPart list, the sorted elements are in this order : * <ul> * <li>1/ The EditPart which are not included in the following criterias</li> * <li>2/ The Affixed Child Node</li> * <li>3/ The ConnectionEditPart</li> * </ul> * . */ protected class TypeComparator implements Comparator<Object> { /** * Compare. * * @param o1 * the o1 * @param o2 * the o2 * @return the int * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ public int compare(Object o1, Object o2) { int index1 = getIndex((EditPart)o1); int index2 = getIndex((EditPart)o2); if(index1 == index2) { return 0; } else if(index1 < index2) { return -1; } else { return 1; } } /** * Return a int representing the type of EditPart. * * @param ep * an EditPart * @return the index * <ul> * <li>3 : if the EditPart is an Affixed ChildNode EditPart</li> * <li>2 : if the EditPart is a {@link ConnectionEditPart}</li> * <li>1 : in other cases</li> * </ul> */ protected int getIndex(EditPart ep) { if(ep instanceof ConnectionEditPart) { return 2; } else if(Util.isAffixedChildNode(ep)) { return 3; } else { return 1; } } } /** * The Class AffixedChildNodeRepresentation. */ protected class AffixedChildNodeRepresentation { /** the represented affixed child node. */ private EditPart affixedChildNode; /** the new location for the affixed child node. */ private Point newLocation; /** * Instantiates a new affixed child node representation. * * @param affixedChildNode * the affixed child node */ public AffixedChildNodeRepresentation(EditPart affixedChildNode) { this.affixedChildNode = affixedChildNode; } /** * Gets the absolute location. * * @return the absolute location */ public Point getAbsoluteLocation() { return getAbsolutePosition().getTopLeft(); } /** * Gets the side on parent. * * @return the side on parent */ public int getSideOnParent() { IBorderItemLocator loc = ((BorderNamedElementEditPart)this.affixedChildNode).getBorderItemLocator(); return loc.getCurrentSideOfParent(); } /** * Gets the absolute position. * * @return the absolute position */ public PrecisionRectangle getAbsolutePosition() { return LayoutUtils.getAbsolutePosition(this.affixedChildNode); } /** * Gets the command. * * @return the command */ public Command getCommand() { Request req = getRequest(); if(req == null) { return UnexecutableCommand.INSTANCE; } else { return this.affixedChildNode.getCommand(req); } } /** * Gets the request. * * @return the request */ public Request getRequest() { if(newLocation != null) { ChangeBoundsRequest req = new ChangeBoundsRequest(RequestConstants.REQ_MOVE); req.setEditParts(this.affixedChildNode); PrecisionRectangle absolutePosition = LayoutUtils.getAbsolutePosition(this.affixedChildNode); PrecisionPoint oldLocation = new PrecisionPoint(absolutePosition.preciseX, absolutePosition.preciseY); Dimension delta = newLocation.getDifference(oldLocation); req.setMoveDelta(new Point(delta.width, delta.height)); req.setSizeDelta(absolutePosition.getSize().getDifference(absolutePosition.getSize())); return req; } return null; } /** * Sets the new location. * * @param pt * the new new location */ public void setNewLocation(Point pt) { this.newLocation = pt; } } }