/***************************************************************************** * 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.layout; 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.Point; import org.eclipse.gef.EditPart; import org.eclipse.gef.commands.Command; import org.eclipse.gef.commands.CompoundCommand; import org.eclipse.gef.editparts.AbstractConnectionEditPart; import org.eclipse.gmf.runtime.draw2d.ui.figures.PolylineConnectionEx; /** * * This class allows to regroup all the nodes which are linked by the selected * links. * */ public class SameAlignment { /** the alignment */ private int alignment; /** list of the links representation */ private List<LinkRepresentation> linksRepresentation; /** list of the editpart representation */ private List<EditPartRepresentation> editpartRepresentation; /** * * Constructor. * * @param align */ public SameAlignment(int align) { this.alignment = align; this.linksRepresentation = new ArrayList<LinkRepresentation>(); this.editpartRepresentation = new ArrayList<EditPartRepresentation>(); } /** * Returns the command to align all the selected {@linkplain EditPart} * * @return the command to align all the selected {@linkplain EditPart} */ public Command getCommand() { Collections.sort(linksRepresentation, new LinkComparator()); if(this.alignment == PositionConstants.RIGHT || this.alignment == PositionConstants.BOTTOM) {// we need to // inverse the // selection to // do the // correct // action Collections.reverse(linksRepresentation); } // we remove the selected link which are not interesting removeBadSideLink(); CompoundCommand cmd = new CompoundCommand("command for alignment"); //$NON-NLS-1$ if(isCorrectSelection()) { Command tmp; for(LinkRepresentation currentLink : linksRepresentation) { tmp = currentLink.getCommand(); if(tmp != null) { cmd.add(tmp); } } } return cmd; } /** * Returns a list with the link linked to the {@link EditPartRepresentation} {@code epRepresentation} * * @param epRepresentation * an {@linkplain EditPartRepresentation} * @return a list with the link linked to the {@link EditPartRepresentation} {@code epRepresentation} */ protected List<LinkRepresentation> getLinkFor(EditPartRepresentation epRepresentation) { List<LinkRepresentation> list = new ArrayList<LinkRepresentation>(); for(LinkRepresentation link : linksRepresentation) { if(link.getSource() == epRepresentation || link.getTarget() == epRepresentation) { list.add(link); } } return list; } /** * Tests if each editpart is linked with only one or two other editparts * * @return <ul> * <li>{@code true}</li> all the node are linked with only one or two other editparts * <li> {@code false}</li> if not * * </ul> */ protected boolean isCorrectSelection() { for(EditPartRepresentation current : editpartRepresentation) { if(getLinkFor(current).size() > 2) { return false; } } return true; } /** * Adds a link, with its source and target to the {@link SameAlignment} * * @param link * the link * @param sourceRep * the source representation for this link * @param targetRep * the target representation for this link */ public void addTriplet(EditPart link, EditPartRepresentation sourceRep, EditPartRepresentation targetRep) { addEditPartRepresentation(sourceRep); addEditPartRepresentation(targetRep); linksRepresentation.add(new LinkRepresentation(link, sourceRep, targetRep, alignment)); } /** * Adds an {@link EditPartRepresentation} to the {@link SameAlignment} * * @param rep * the {@link EditPartRepresentation} to add */ protected void addEditPartRepresentation(EditPartRepresentation rep) { if(!editpartRepresentation.contains(rep)) { editpartRepresentation.add(rep); } } /** * Adds {@code family} to this family * * @param family * adds this {@code family} to the family */ public void addFamily(SameAlignment family) { for(LinkRepresentation currentLink : family.getLinks()) { addEditPartRepresentation(currentLink.getSource()); addEditPartRepresentation(currentLink.getTarget()); } linksRepresentation.addAll(family.getLinks()); } /** * Getter for {@link #alignment} * * @return * @link {@link #alignment} */ public int getAlignment() { return this.alignment; } /** * Getter for {@link #linksRepresentation} * * @return {@link #linksRepresentation} */ public List<LinkRepresentation> getLinks() { return this.linksRepresentation; } /** * * @param representedEditPart * the {@linkplain EditPart} that we are looking for * @return <ul> * <li>the {@linkplain EditPartRepresentation} for this editpart if it exists</li> * <li>{@code null}if the representation for this editpart doesn't exist</li> * </ul> * */ public EditPartRepresentation getEditPartRepresentationFor(EditPart representedEditPart) { for(EditPartRepresentation currentRepresentation : editpartRepresentation) { if(currentRepresentation.getRepresentedEditPart() == representedEditPart) { return currentRepresentation; } } return null; } /** * This method removes the following links : * <ul> * <li>links which are not on a correct side to do the action</li> * <li>links whose Figure is not an instanceof PolylineConnectionEx</li> * </ul> */ protected void removeBadSideLink() { List<LinkRepresentation> linksToRemove = new ArrayList<LinkRepresentation>(); // we test if the tow anchors for the selected link are opposite or not for(LinkRepresentation link : linksRepresentation) { int side1 = link.getLinkSideOnSource(); int side2 = link.getLinkSideOnTarget(); if(alignment == PositionConstants.LEFT || alignment == PositionConstants.RIGHT) { if(!DistributionConstants.verticalValuesList.contains(side1) || !DistributionConstants.verticalValuesList.contains(side2)) { linksToRemove.add(link); } } else if(alignment == PositionConstants.TOP || alignment == PositionConstants.BOTTOM) { if(!DistributionConstants.horizontalValuesList.contains(side1) || !DistributionConstants.horizontalValuesList.contains(side2)) { linksToRemove.add(link); } } if(!(((AbstractConnectionEditPart)link.getLink()).getFigure() instanceof PolylineConnectionEx)) { linksToRemove.add(link); } } linksRepresentation.removeAll(linksToRemove); } /** * * This class provides a comparator for the {@link EditPart}, using the * coordinates of the representing {@link EditPart} The used coordinate is * the top left corner */ protected class LinkComparator implements Comparator<Object> { /** * * * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) * * @param o1 * @param o2 * @return */ public int compare(Object o1, Object o2) { // the two figures to compare PolylineConnectionEx figure1 = (PolylineConnectionEx)((AbstractConnectionEditPart)((LinkRepresentation)o1).getLink()).getFigure(); PolylineConnectionEx figure2 = (PolylineConnectionEx)((AbstractConnectionEditPart)((LinkRepresentation)o2).getLink()).getFigure(); // the point for the first figure Point pt11; Point pt12; // the point for the second figure Point pt21; Point pt22; // we want pt11.x<pt12.x<pt21.x<pt22.x if(alignment == PositionConstants.LEFT || alignment == PositionConstants.RIGHT) { pt11 = (figure1.getStart().x < figure1.getEnd().x) ? figure1.getStart() : figure1.getEnd(); if(pt11.equals(figure1.getStart())) { pt12 = figure1.getEnd(); } else { pt12 = figure1.getStart(); } pt21 = (figure2.getStart().x < figure2.getEnd().x) ? figure2.getStart() : figure2.getEnd(); if(pt21.equals(figure2.getStart())) { pt22 = figure2.getEnd(); } else { pt22 = figure2.getStart(); } if(pt11.x < pt21.x && pt12.x < pt22.x) { return -1; } else if(pt11.equals(pt21) && pt12.equals(pt22)) { return 0; } else if(pt11.x > pt21.x && pt12.x > pt22.x) { return 1; } else { return 0; // it's a strange model, if we come here } } else if(alignment == PositionConstants.TOP || alignment == PositionConstants.BOTTOM) { pt11 = (figure1.getStart().y < figure1.getEnd().y) ? figure1.getStart() : figure1.getEnd(); if(pt11.equals(figure1.getStart())) { pt12 = figure1.getEnd(); } else { pt12 = figure1.getStart(); } pt21 = (figure2.getStart().y < figure2.getEnd().y) ? figure2.getStart() : figure2.getEnd(); if(pt21.equals(figure2.getStart())) { pt22 = figure2.getEnd(); } else { pt22 = figure2.getStart(); } if(pt11.y < pt21.y && pt12.y < pt22.y) { return -1; } else if(pt11.equals(pt21) && pt12.equals(pt22)) { return 0; } else if(pt11.y > pt21.y && pt12.y > pt22.y) { return 1; } else { return 0; // it's a strange model, if we come here } } return 0; } } }