/*****************************************************************************
* 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.common.helper;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.commands.UnexecutableCommand;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
import org.eclipse.gef.tools.ToolUtilities;
import org.eclipse.papyrus.uml.diagram.common.layout.EditPartRepresentation;
import org.eclipse.papyrus.uml.diagram.common.layout.SameAlignment;
/**
* This class provides a custom method to do an align action using links and not
* nodes. This action moves node to set the selected link vertically or
* horizontally. The anchor connection don't move on the node.
*
*/
public class AlignmentLinkHelper {
/** the alignment */
private int alignment;
/** the selected editparts */
private List<?> linkEditparts;
/** the families of editparts */
private List<SameAlignment> families = new ArrayList<SameAlignment>();
/**
*
* Constructor.
*
* @param editparts
* the selected editpart for the alignment action
* @param alignment
* the alignment
*/
public AlignmentLinkHelper(List<?> editparts, int alignment) {
this.linkEditparts = editparts;
this.alignment = alignment;
}
/**
* Returns the command for this link representation
*
* @return <ul>
* <li>the command for this link representation</li>
* <li> {@linkplain UnexecutableCommand#INSTANCE} if the alignment is {@linkplain PositionConstants#MIDDLE} or
* {@linkplain PositionConstants#CENTER}</li>
* </ul>
*/
public Command createCommand() {
if(this.alignment == PositionConstants.MIDDLE || this.alignment == PositionConstants.CENTER || this.linkEditparts.size() == 0) {
return UnexecutableCommand.INSTANCE;
}
organizeSelection();
if(isAncestorSelected()) {
return UnexecutableCommand.INSTANCE;
}
return getCommand();
}
/**
* Tests if a parent and one of these children are selected
*
* @return <ul>
* <li>{@code true}</li>if a parent and one of these children are selected
* <li>{@code false}</li>if not
* </ul>
*
*/
protected boolean isAncestorSelected() {
List<EditPart> nodesEditPart = new ArrayList<EditPart>();
// get all the sources and target for the selected links
for(Object currentEP : linkEditparts) {
EditPart source = ((AbstractConnectionEditPart)currentEP).getSource();
EditPart target = ((AbstractConnectionEditPart)currentEP).getTarget();
nodesEditPart.add(source);
nodesEditPart.add(target);
}
// test if a selected editpart is included another selected editpart
for(EditPart ep : nodesEditPart) {
if(ToolUtilities.isAncestorContainedIn(nodesEditPart, ep)) {
return true;
}
}
return false;
}
/**
* Builds and returns the command for this link representation
*
* @return the command for this link representation
*/
protected Command getCommand() {
CompoundCommand cmd = new CompoundCommand("Command for alignment by links"); //$NON-NLS-1$
Command tmp;
for(SameAlignment currentFamily : families) {
tmp = currentFamily.getCommand();
if(tmp != null && tmp.canExecute()) {
cmd.add(tmp);
}
}
return cmd;
}
/**
* This function organizes the selection following the links : all selected
* links which share nodes are owned by the same {@linkplain SameAlignment}.
*/
protected void organizeSelection() {
for(Object currentEP : this.linkEditparts) {
// get the editPart source and target for the link
EditPart source = ((AbstractConnectionEditPart)currentEP).getSource();
EditPart target = ((AbstractConnectionEditPart)currentEP).getTarget();
SameAlignment familySource = null;
SameAlignment familyTarget = null;
EditPartRepresentation sourceRep = null;
EditPartRepresentation targetRep = null;
// we look for a representation of these source and target
for(SameAlignment family : families) {
if(family.getEditPartRepresentationFor(source) != null) {
sourceRep = family.getEditPartRepresentationFor(source);
}
if(family.getEditPartRepresentationFor(target) != null) {
targetRep = family.getEditPartRepresentationFor(target);
}
if(sourceRep != null) {
familySource = family;
}
if(targetRep != null) {
familyTarget = family;
}
}
/*
* if source and target representation exist, we keep the source
* representation, and we add it the element containing by the
* target representation
*/
if(familySource != null && familyTarget != null) {
familySource.addFamily(familyTarget);
families.remove(familyTarget);
} else if(familySource != null) {// a source representation exists
// yet, we add it this link
familySource.addTriplet((EditPart)currentEP, sourceRep, new EditPartRepresentation(target));
} else if(familyTarget != null) {// a target representation exists
// yet, we add it this link
familyTarget.addTriplet((EditPart)currentEP, new EditPartRepresentation(source), targetRep);
} else {// nothing exists, we create a new link representation
SameAlignment newFamily = new SameAlignment(this.alignment);
newFamily.addTriplet((EditPart)currentEP, new EditPartRepresentation(source), new EditPartRepresentation(target));
families.add(newFamily);
}
}
}
}