diff options
| author | Laurent Redor | 2014-08-08 09:15:07 +0000 |
|---|---|---|
| committer | Laurent Redor | 2014-08-11 12:41:34 +0000 |
| commit | bb8455cabc233ad43ef27f64a559599417fbb248 (patch) | |
| tree | 6fd4027c8c5c157a0a46734ecd383776b56bf788 | |
| parent | 5d3cfb58c9d91b1ab69d26d2cb9329b2bea54c33 (diff) | |
| download | org.eclipse.sirius-bb8455cabc233ad43ef27f64a559599417fbb248.tar.gz org.eclipse.sirius-bb8455cabc233ad43ef27f64a559599417fbb248.tar.xz org.eclipse.sirius-bb8455cabc233ad43ef27f64a559599417fbb248.zip | |
[441417] Avoid same GMF locations after moving several border nodes.
During a move of several border nodes simultaneously, the feedbacks of
these nodes are ignored for conflict detection (in DBorderItemLocator).
This causes that all border nodes have the same GMF location after the
move. This is not acceptable, because this can cause unexpected moves of
border node later.
Add a new list of figures to the DBorderItemLocator.conflicts() method
to allow to complete the brother figures with other figures. In our case
these figures are the feedback figures. Several methods are completed to
have this new parameter.
This list of figures is filled during the showChangeBoundsFeedback()
method (and cleaned during eraseSourceFeedback() method).
Bug: 441417
Change-Id: Icfd8f93a2cb35969d78d319c36fd592f85ac9331
Signed-off-by: Laurent Redor <laurent.redor@obeo.fr>
5 files changed, 242 insertions, 66 deletions
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/graphical/edit/policies/SpecificBorderItemSelectionEditPolicy.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/graphical/edit/policies/SpecificBorderItemSelectionEditPolicy.java index 4c37d3c7b9..04d67db117 100644 --- a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/graphical/edit/policies/SpecificBorderItemSelectionEditPolicy.java +++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/graphical/edit/policies/SpecificBorderItemSelectionEditPolicy.java @@ -61,13 +61,14 @@ import org.eclipse.sirius.diagram.ui.business.api.query.NodeQuery; import org.eclipse.sirius.diagram.ui.business.internal.query.RequestQuery; import org.eclipse.sirius.diagram.ui.edit.api.part.AbstractDiagramBorderNodeEditPart; import org.eclipse.sirius.diagram.ui.edit.internal.part.PortLayoutHelper; -import org.eclipse.sirius.diagram.ui.internal.edit.parts.DDiagramEditPart; import org.eclipse.sirius.diagram.ui.internal.edit.parts.DNodeNameEditPart; import org.eclipse.sirius.diagram.ui.tools.api.figure.locator.DBorderItemLocator; import org.eclipse.sirius.diagram.ui.tools.api.graphical.edit.styles.IBorderItemOffsets; import org.eclipse.sirius.diagram.ui.tools.internal.figure.locator.FeedbackDBorderItemLocator; import org.eclipse.sirius.diagram.ui.tools.internal.ui.NoCopyDragEditPartsTrackerEx; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; /** @@ -81,6 +82,14 @@ import com.google.common.collect.Lists; public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx { /** + * Key for extended data of request. This key corresponds to feedback + * figures. This figures are added during drawing of feedback when several + * border nodes are move simultaneously. The last moved figure is not added + * to this list (because there will be no further feedback after this one). + */ + private static final String BORDER_NODE_FEEDBACKS_KEY = "borderNodeFeedbacks"; + + /** * We keep all created feedbacks to delete them at the end of the drag * action. */ @@ -113,6 +122,8 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx if (!(request instanceof ChangeBoundsRequest)) { return; } + // Remove the feedback from request extended data + getBorderNodeFeedbacks(request).remove(getDragSourceFeedbackFigure()); if ((REQ_MOVE.equals(request.getType()) && isDragAllowed()) || REQ_CLONE.equals(request.getType()) || REQ_ADD.equals(request.getType())) { eraseChangeBoundsFeedback((ChangeBoundsRequest) request); } @@ -123,6 +134,25 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx } } + /** + * Return the list of existing feedback figures containing in the request. + * If the request does not contains feedback figures, an empty list is + * returned. + * + * @param request + * The request containing the extended data. + * @return the list of existing feedback figures contained in the request. + */ + @SuppressWarnings("unchecked") + private List<IFigure> getBorderNodeFeedbacks(Request request) { + Object result = request.getExtendedData().get(BORDER_NODE_FEEDBACKS_KEY); + if (result instanceof List<?> && Iterables.all((List<?>) result, Predicates.instanceOf(IFigure.class))) { + return (List<IFigure>) result; + } else { + return new ArrayList<IFigure>(); + } + } + private void eraseChangeBoundsProhibitedFeedbackWhenDrop() { for (IFigure figure : feedbacks) { removeFeedback(figure); @@ -181,7 +211,6 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx Rectangle realLocation = null; // Only necessary in the case of bordered node dropping if (isFeedbackForBorderedNodeDropping(request, targetAbstractGraphicalEditPart)) { - activateProhibitedFeedbacks(targetAbstractGraphicalEditPart, request); DBorderItemLocator borderItemLocator = new FeedbackDBorderItemLocator(targetFigure); @@ -213,14 +242,13 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx borderItemLocator.setBorderItemOffset(IBorderItemOffsets.DEFAULT_OFFSET); rect.setBounds(newBoundsAbsolute); } - realLocation = borderItemLocator.getValidLocation(rect, feedback, Collections.singleton(feedback)); + realLocation = borderItemLocator.getValidLocation(rect, feedback, getFiguresToIgnore(request), getBorderNodeFeedbacks(request)); targetFigure.translateToAbsolute(realLocation); feedback.translateToRelative(realLocation); feedback.setBounds(realLocation); - // doesn't allows drop feedback of borderedNode to Diagram - } else if (!(targetEditPart instanceof DDiagramEditPart)) { - + storeFeedback(feedback, request); + } else { activateProhibitedFeedbacks(hostEditPart.getParent(), request); final IBorderItemLocator borderItemLocator = borderItemEP.getBorderItemLocator(); @@ -235,7 +263,7 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx // Compute the list of figures to ignore during the // conflict detection. List<IFigure> figuresToIgnore = getFiguresToIgnore(request); - realLocation = ((DBorderItemLocator) borderItemLocator).getValidLocation(rect, borderItemEP.getFigure(), figuresToIgnore); + realLocation = ((DBorderItemLocator) borderItemLocator).getValidLocation(rect, borderItemEP.getFigure(), figuresToIgnore, getBorderNodeFeedbacks(request)); } else { realLocation = borderItemLocator.getValidLocation(rect.getCopy(), borderItemEP.getFigure()); } @@ -246,11 +274,37 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx feedback.translateToRelative(realLocation); feedback.setBounds(realLocation); + storeFeedback(feedback, request); } } } } + /** + * The feedback is stored only if the request corresponds to several + * elements and that the current element is not the last. + * + * @param feedback + * The figure to store. + * @param request + * The request to store in. + */ + @SuppressWarnings("unchecked") + private void storeFeedback(IFigure feedback, ChangeBoundsRequest request) { + if (request.getEditParts().size() > 1 && !getHost().equals(request.getEditParts().get(request.getEditParts().size() - 1))) { + // Store the feedback new location in request to use it for + // other feedback conflict detection + List<IFigure> borderNodeFeedbacks = getBorderNodeFeedbacks(request); + int currentIndex = borderNodeFeedbacks.indexOf(feedback); + if (currentIndex != -1) { + borderNodeFeedbacks.set(currentIndex, feedback); + } else { + borderNodeFeedbacks.add(feedback); + } + request.getExtendedData().put(BORDER_NODE_FEEDBACKS_KEY, borderNodeFeedbacks); + } + } + private void restoreCollapsedNode(IBorderItemEditPart borderItemEP) { IBorderItemLocator borderItemLocator = borderItemEP.getBorderItemLocator(); if (borderItemLocator instanceof DBorderItemLocator) { @@ -337,7 +391,7 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx if (!request.getEditParts().contains(child) && child instanceof AbstractDiagramBorderNodeEditPart) { AbstractDiagramBorderNodeEditPart borderNodeEditPart = (AbstractDiagramBorderNodeEditPart) child; if (isCollapsed(borderNodeEditPart)) { - configureFeedback(borderNodeEditPart); + configureFeedback(borderNodeEditPart, getBorderNodeFeedbacks(request)); } } } @@ -372,8 +426,12 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx * * @param borderNodeEditPart * the edit part hosting the collapsed node figure. + * @param otherFeedbackFigures + * In case of simultaneous moves, this list corresponds to the + * already known border nodes after move (generally the feedback + * figure) */ - private void configureFeedback(AbstractBorderItemEditPart borderNodeEditPart) { + private void configureFeedback(AbstractBorderItemEditPart borderNodeEditPart, List<IFigure> otherFeedbackFigures) { IFigure figure = borderNodeEditPart.getFigure(); EditPart parentEditPart = borderNodeEditPart.getParent(); @@ -392,7 +450,7 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx Rectangle newBounds = PortLayoutHelper.getUncollapseCandidateLocation(initialDim, bounds, parentBounds); final IBorderItemLocator borderItemLocator = borderNodeEditPart.getBorderItemLocator(); // get real location from DBorderItemLocator - Rectangle realNewBounds = getRealExpandedBounds(figure, newBounds, borderItemLocator); + Rectangle realNewBounds = getRealExpandedBounds(figure, newBounds, borderItemLocator, otherFeedbackFigures); PrecisionRectangle precisionRectangle = new PrecisionRectangle(realNewBounds); // // Use a ghost rectangle for feedback @@ -432,9 +490,13 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx * the new bounds candidates. * @param borderItemLocator * the figure edit part border item locator. + * @param otherFeedbackFigures + * In case of simultaneous moves, this list corresponds to the + * already known border nodes after move (generally the feedback + * figure) * @return the real location from the border item locator. */ - private Rectangle getRealExpandedBounds(IFigure figure, Rectangle candidateNewBounds, final IBorderItemLocator borderItemLocator) { + private Rectangle getRealExpandedBounds(IFigure figure, Rectangle candidateNewBounds, final IBorderItemLocator borderItemLocator, List<IFigure> otherFeedbackFigures) { Rectangle realNewBounds = candidateNewBounds; if (borderItemLocator instanceof DBorderItemLocator) { Rectangle oldConstraint = ((DBorderItemLocator) borderItemLocator).getCurrentConstraint(); @@ -443,7 +505,7 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx Dimension oldOffset = ((DBorderItemLocator) borderItemLocator).getBorderItemOffset(); ((DBorderItemLocator) borderItemLocator).setBorderItemOffset(IBorderItemOffsets.DEFAULT_OFFSET); - realNewBounds = ((DBorderItemLocator) borderItemLocator).getValidLocation(candidateNewBounds, figure, Collections.singleton(figure)); + realNewBounds = ((DBorderItemLocator) borderItemLocator).getValidLocation(candidateNewBounds, figure, Collections.singleton(figure), otherFeedbackFigures); ((DBorderItemLocator) borderItemLocator).setBorderItemOffset(oldOffset); borderItemLocator.setConstraint(oldConstraint); @@ -464,7 +526,7 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx /** * Tell if according to the <code>request</code>'s location we must provide * a feedback for a drop of borderedNode to another parent or a feedback for - * a simple move of borderedNode without changing visually the parent/ + * a simple move of borderedNode without changing visually the parent. * * @param request * the {@link ChangeBoundsRequest} providing the location of the @@ -484,13 +546,10 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx IFigure targetFigure = targetAbstractGraphicalEditPart.getFigure(); - // verify not case of a label and not on the diagram to the - // ghost - // appears only on the nodes and not on the diagram during a - // drop + // verify not case of a label and not on the diagram to the ghost + // appears only on the nodes and not on the diagram during a drop if (targetFigure != diagramFigure && !(hostEditPart instanceof DNodeNameEditPart)) { - // Necessary for sequence diagrams, for the feedback does - // not + // Necessary for sequence diagrams, for the feedback does not // shift isFeedbackForBorderedNodeDropping = targetAbstractGraphicalEditPart != hostEditPart && targetAbstractGraphicalEditPart != hostEditPart.getParent(); } @@ -531,7 +590,7 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx rect.setBounds(newBounds); } - realLocation = ((DBorderItemLocator) borderItemLocator).getValidLocation(rect, borderItemEP.getFigure(), figuresToIgnore); + realLocation = ((DBorderItemLocator) borderItemLocator).getValidLocation(rect, borderItemEP.getFigure(), figuresToIgnore, getBorderNodeFeedbacks(request)); if (collapsedRectangle != null) { restoreCollapsedNode(borderItemEP); IFigure parentFigure = ((DBorderItemLocator) borderItemLocator).getParentFigure(); @@ -571,6 +630,7 @@ public class SpecificBorderItemSelectionEditPolicy extends ResizableEditPolicyEx figuresToIgnore.add(((org.eclipse.gef.GraphicalEditPart) part).getFigure()); } } + figuresToIgnore.add(getDragSourceFeedbackFigure()); return figuresToIgnore; } diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/figure/locator/DBorderItemLocator.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/figure/locator/DBorderItemLocator.java index 2b09964e9e..3c7c5cfd51 100644 --- a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/figure/locator/DBorderItemLocator.java +++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/figure/locator/DBorderItemLocator.java @@ -13,6 +13,7 @@ package org.eclipse.sirius.diagram.ui.tools.api.figure.locator; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.ListIterator; @@ -27,6 +28,9 @@ import org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator; import org.eclipse.sirius.ext.base.Option; import org.eclipse.sirius.ext.base.Options; +import com.google.common.base.Function; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; /** @@ -195,7 +199,7 @@ public class DBorderItemLocator extends BorderItemLocator { // if bordered node is moved. figuresToIgnoreDuringNextRelocate.clear(); } - final Point ptNewLocation = locateOnBorder(rectSuggested.getLocation(), getCurrentSideOfParent(), 0, borderItem, figuresToIgnoreDuringNextRelocate); + final Point ptNewLocation = locateOnBorder(rectSuggested.getLocation(), getCurrentSideOfParent(), 0, borderItem, figuresToIgnoreDuringNextRelocate, new ArrayList<IFigure>()); borderItem.setLocation(ptNewLocation); figuresToIgnoreDuringNextRelocate.clear(); borderItem.setSize(size); @@ -207,7 +211,7 @@ public class DBorderItemLocator extends BorderItemLocator { protected Point locateOnBorder(Point suggestedLocation, int suggestedSide, int circuitCount, IFigure borderItem) { List<IFigure> figuresToIgnore = Lists.newArrayList(); figuresToIgnore.add(borderItem); - return locateOnBorder(suggestedLocation, suggestedSide, circuitCount, borderItem, figuresToIgnore); + return locateOnBorder(suggestedLocation, suggestedSide, circuitCount, borderItem, figuresToIgnore, new ArrayList<IFigure>()); } /** @@ -227,20 +231,24 @@ public class DBorderItemLocator extends BorderItemLocator { * the border item. * @param portsFiguresToIgnore * the ports figures to ignore + * @param additionalFiguresForConflictDetection + * Figures that are not brothers of the current figure but that + * must be used for conflict detection * @return point */ - protected Point locateOnBorder(final Point suggestedLocation, final int suggestedSide, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore) { + protected Point locateOnBorder(final Point suggestedLocation, final int suggestedSide, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore, + List<IFigure> additionalFiguresForConflictDetection) { Point recommendedLocation = locateOnParent(suggestedLocation, suggestedSide, borderItem); - if (circuitCount < NB_SIDES && conflicts(recommendedLocation, borderItem, portsFiguresToIgnore).some()) { + if (circuitCount < NB_SIDES && conflicts(recommendedLocation, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection).some()) { if (suggestedSide == PositionConstants.WEST) { - recommendedLocation = locateOnWestBorder(recommendedLocation, circuitCount, borderItem, portsFiguresToIgnore); + recommendedLocation = locateOnWestBorder(recommendedLocation, circuitCount, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); } else if (suggestedSide == PositionConstants.SOUTH) { - recommendedLocation = locateOnSouthBorder(recommendedLocation, circuitCount, borderItem, portsFiguresToIgnore); + recommendedLocation = locateOnSouthBorder(recommendedLocation, circuitCount, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); } else if (suggestedSide == PositionConstants.EAST) { - recommendedLocation = locateOnEastBorder(recommendedLocation, circuitCount, borderItem, portsFiguresToIgnore); + recommendedLocation = locateOnEastBorder(recommendedLocation, circuitCount, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); } else { // NORTH - recommendedLocation = locateOnNorthBorder(recommendedLocation, circuitCount, borderItem, portsFiguresToIgnore); + recommendedLocation = locateOnNorthBorder(recommendedLocation, circuitCount, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); } } return recommendedLocation; @@ -263,9 +271,13 @@ public class DBorderItemLocator extends BorderItemLocator { * the figure representing the border item. * @param portsFiguresToIgnore * the ports figures to ignore + * @param additionalFiguresForConflictDetection + * Figures that are not brothers of the current figure but that + * must be used for conflict detection * @return the location where the border item can be put */ - protected Point locateOnSouthBorder(final Point recommendedLocation, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore) { + protected Point locateOnSouthBorder(final Point recommendedLocation, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore, + List<IFigure> additionalFiguresForConflictDetection) { final Dimension borderItemSize = getSize(borderItem); Point resultLocation = null; final Point rightTestPoint = new Point(recommendedLocation); @@ -281,7 +293,7 @@ public class DBorderItemLocator extends BorderItemLocator { if (isStillFreeSpaceToTheRight) { // Move to the right on the south side rightTestPoint.x += rightVerticalGap; - Option<Rectangle> optionalConflictingRectangle = conflicts(rightTestPoint, borderItem, portsFiguresToIgnore); + Option<Rectangle> optionalConflictingRectangle = conflicts(rightTestPoint, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); if (optionalConflictingRectangle.some()) { rightVerticalGap = (optionalConflictingRectangle.get().x + optionalConflictingRectangle.get().width + 1) - rightTestPoint.x; if (rightTestPoint.x + rightVerticalGap + borderItemSize.width > getParentBorder().getBottomRight().x) { @@ -301,7 +313,7 @@ public class DBorderItemLocator extends BorderItemLocator { if (isStillFreeSpaceToTheLeft && resultLocation == null) { // Move to the left on the south side leftTestPoint.x -= leftVerticalGap; - Option<Rectangle> optionalConflictingRectangle = conflicts(leftTestPoint, borderItem, portsFiguresToIgnore); + Option<Rectangle> optionalConflictingRectangle = conflicts(leftTestPoint, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); if (optionalConflictingRectangle.some()) { leftVerticalGap = leftTestPoint.x - (optionalConflictingRectangle.get().x - borderItemSize.width - 1); if (leftTestPoint.x - leftVerticalGap < getParentBorder().getTopLeft().x) { @@ -314,7 +326,7 @@ public class DBorderItemLocator extends BorderItemLocator { } if (resultLocation == null) { // south is full, try east. - resultLocation = locateOnBorder(recommendedLocationForEast, PositionConstants.EAST, circuitCount + 1, borderItem, portsFiguresToIgnore); + resultLocation = locateOnBorder(recommendedLocationForEast, PositionConstants.EAST, circuitCount + 1, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); } return resultLocation; } @@ -336,9 +348,13 @@ public class DBorderItemLocator extends BorderItemLocator { * the figure representing the border item. * @param portsFiguresToIgnore * the ports figures to ignore + * @param additionalFiguresForConflictDetection + * Figures that are not brothers of the current figure but that + * must be used for conflict detection * @return the location where the border item can be put */ - protected Point locateOnNorthBorder(final Point recommendedLocation, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore) { + protected Point locateOnNorthBorder(final Point recommendedLocation, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore, + List<IFigure> additionalFiguresForConflictDetection) { final Dimension borderItemSize = getSize(borderItem); Point resultLocation = null; final Point rightTestPoint = new Point(recommendedLocation); @@ -354,7 +370,7 @@ public class DBorderItemLocator extends BorderItemLocator { if (isStillFreeSpaceToTheRight) { // Move to the right on the north side rightTestPoint.x += rightVerticalGap; - Option<Rectangle> optionalConflictingRectangle = conflicts(rightTestPoint, borderItem, portsFiguresToIgnore); + Option<Rectangle> optionalConflictingRectangle = conflicts(rightTestPoint, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); if (optionalConflictingRectangle.some()) { rightVerticalGap = (optionalConflictingRectangle.get().x + optionalConflictingRectangle.get().width + 1) - rightTestPoint.x; if (rightTestPoint.x + rightVerticalGap + borderItemSize.width > getParentBorder().getBottomRight().x) { @@ -367,7 +383,7 @@ public class DBorderItemLocator extends BorderItemLocator { if (isStillFreeSpaceToTheLeft && resultLocation == null) { // Move to the left on the north side leftTestPoint.x -= leftVerticalGap; - Option<Rectangle> optionalConflictingRectangle = conflicts(leftTestPoint, borderItem, portsFiguresToIgnore); + Option<Rectangle> optionalConflictingRectangle = conflicts(leftTestPoint, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); if (optionalConflictingRectangle.some()) { leftVerticalGap = leftTestPoint.x - (optionalConflictingRectangle.get().x - borderItemSize.width - 1); if (leftTestPoint.x - leftVerticalGap < getParentBorder().getTopLeft().x) { @@ -387,7 +403,7 @@ public class DBorderItemLocator extends BorderItemLocator { } if (resultLocation == null) { // North is full, try west. - resultLocation = locateOnBorder(recommendedLocationForWest, PositionConstants.WEST, circuitCount + 1, borderItem, portsFiguresToIgnore); + resultLocation = locateOnBorder(recommendedLocationForWest, PositionConstants.WEST, circuitCount + 1, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); } return resultLocation; } @@ -408,9 +424,13 @@ public class DBorderItemLocator extends BorderItemLocator { * the figure representing the border item. * @param portsFiguresToIgnore * the ports figures to ignore + * @param additionalFiguresForConflictDetection + * Figures that are not brothers of the current figure but that + * must be used for conflict detection * @return the location where the border item can be put */ - protected Point locateOnWestBorder(final Point recommendedLocation, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore) { + protected Point locateOnWestBorder(final Point recommendedLocation, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore, + List<IFigure> additionalFiguresForConflictDetection) { final Dimension borderItemSize = getSize(borderItem); Point resultLocation = null; final Point belowTestPoint = new Point(recommendedLocation); @@ -426,7 +446,7 @@ public class DBorderItemLocator extends BorderItemLocator { if (isStillFreeSpaceBelow) { // Move down on the west side belowTestPoint.y += belowVerticalGap; - Option<Rectangle> optionalConflictingRectangle = conflicts(belowTestPoint, borderItem, portsFiguresToIgnore); + Option<Rectangle> optionalConflictingRectangle = conflicts(belowTestPoint, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); if (optionalConflictingRectangle.some()) { belowVerticalGap = optionalConflictingRectangle.get().y + optionalConflictingRectangle.get().height - belowTestPoint.y + 1; if (belowTestPoint.y + belowVerticalGap + borderItemSize.height > getParentBorder().getBottomLeft().y) { @@ -446,7 +466,7 @@ public class DBorderItemLocator extends BorderItemLocator { if (isStillFreeSpaceAbove && resultLocation == null) { // Move up on the west side aboveTestPoint.y -= aboveVerticalGap; - Option<Rectangle> optionalConflictingRectangle = conflicts(aboveTestPoint, borderItem, portsFiguresToIgnore); + Option<Rectangle> optionalConflictingRectangle = conflicts(aboveTestPoint, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); if (optionalConflictingRectangle.some()) { aboveVerticalGap = aboveTestPoint.y - (optionalConflictingRectangle.get().y - borderItemSize.height - 1); if (aboveTestPoint.y - aboveVerticalGap < getParentBorder().getTopRight().y) { @@ -459,7 +479,7 @@ public class DBorderItemLocator extends BorderItemLocator { } if (resultLocation == null) { // west is full, try south. - resultLocation = locateOnBorder(recommendedLocationForSouth, PositionConstants.SOUTH, circuitCount + 1, borderItem, portsFiguresToIgnore); + resultLocation = locateOnBorder(recommendedLocationForSouth, PositionConstants.SOUTH, circuitCount + 1, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); } return resultLocation; } @@ -480,9 +500,13 @@ public class DBorderItemLocator extends BorderItemLocator { * the figure representing the border item. * @param portsFiguresToIgnore * the ports figures to ignore + * @param additionalFiguresForConflictDetection + * Figures that are not brothers of the current figure but that + * must be used for conflict detection * @return the location where the border item can be put */ - protected Point locateOnEastBorder(final Point recommendedLocation, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore) { + protected Point locateOnEastBorder(final Point recommendedLocation, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore, + List<IFigure> additionalFiguresForConflictDetection) { final Dimension borderItemSize = getSize(borderItem); Point resultLocation = null; final Point belowTestPoint = new Point(recommendedLocation); @@ -498,7 +522,7 @@ public class DBorderItemLocator extends BorderItemLocator { if (isStillFreeSpaceBelow) { // Move down on the east side belowTestPoint.y += belowVerticalGap; - Option<Rectangle> optionalConflictingRectangle = conflicts(belowTestPoint, borderItem, portsFiguresToIgnore); + Option<Rectangle> optionalConflictingRectangle = conflicts(belowTestPoint, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); if (optionalConflictingRectangle.some()) { belowVerticalGap = optionalConflictingRectangle.get().y + optionalConflictingRectangle.get().height - belowTestPoint.y + 1; if (belowTestPoint.y + belowVerticalGap + borderItemSize.height > getParentBorder().getBottomLeft().y) { @@ -511,7 +535,7 @@ public class DBorderItemLocator extends BorderItemLocator { if (isStillFreeSpaceAbove && resultLocation == null) { // Move up on the east side aboveTestPoint.y -= aboveVerticalGap; - Option<Rectangle> optionalConflictingRectangle = conflicts(aboveTestPoint, borderItem, portsFiguresToIgnore); + Option<Rectangle> optionalConflictingRectangle = conflicts(aboveTestPoint, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); if (optionalConflictingRectangle.some()) { aboveVerticalGap = aboveTestPoint.y - (optionalConflictingRectangle.get().y - borderItemSize.height - 1); if (aboveTestPoint.y - aboveVerticalGap < getParentBorder().getTopRight().y) { @@ -531,7 +555,7 @@ public class DBorderItemLocator extends BorderItemLocator { } if (resultLocation == null) { // East is full, try north. - resultLocation = locateOnBorder(recommendedLocationForNorth, PositionConstants.NORTH, circuitCount + 1, borderItem, portsFiguresToIgnore); + resultLocation = locateOnBorder(recommendedLocationForNorth, PositionConstants.NORTH, circuitCount + 1, borderItem, portsFiguresToIgnore, additionalFiguresForConflictDetection); } return resultLocation; } @@ -621,22 +645,85 @@ public class DBorderItemLocator extends BorderItemLocator { * the border node for which we detect conflicts. * @param portsFiguresToIgnore * the ports figures to ignore + * @param additionalFiguresForConflictDetection + * Figures that are not brothers of the current figure but that + * must be used for conflict detection * @return the optional Rectangle of the border item that is in conflict * with the given bordered node (a none option) */ - protected Option<Rectangle> conflicts(final Point recommendedLocation, final IFigure targetBorderItem, final Collection<IFigure> portsFiguresToIgnore) { + protected Option<Rectangle> conflicts(final Point recommendedLocation, final IFigure targetBorderItem, final Collection<IFigure> portsFiguresToIgnore, + List<IFigure> additionalFiguresForConflictDetection) { final Rectangle recommendedRect = new Rectangle(recommendedLocation, getSize(targetBorderItem)); - final List borderItems = targetBorderItem.getParent().getChildren(); - final ListIterator iterator = borderItems.listIterator(); + + // 1- Detect conflicts with brother figures + Option<Rectangle> conflictedRectangle = conflicts(recommendedRect, getBrotherFigures(targetBorderItem), portsFiguresToIgnore); + // 2- Detect conflicts with feedback figures (if there is no brother + // conflicts). + if (!conflictedRectangle.some() && additionalFiguresForConflictDetection != null && additionalFiguresForConflictDetection.size() > 0) { + // Translate to same coordinates system as current border node + // (targetBorderItem) + Iterable<IFigure> feedbackFigures = Iterables.transform(additionalFiguresForConflictDetection, new Function<IFigure, IFigure>() { + @Override + public IFigure apply(IFigure input) { + Rectangle newBounds = new Rectangle(input.getBounds()); + input.translateToAbsolute(newBounds); + targetBorderItem.translateToRelative(newBounds); + input.setBounds(newBounds); + return input; + } + }); + conflictedRectangle = conflicts(recommendedRect, Lists.newArrayList(feedbackFigures), portsFiguresToIgnore); + // Reset to the feedback layer coordinates system + for (IFigure figure : additionalFiguresForConflictDetection) { + Rectangle newBounds = new Rectangle(figure.getBounds()); + targetBorderItem.translateToAbsolute(newBounds); + figure.translateToRelative(newBounds); + figure.setBounds(newBounds); + } + } + return conflictedRectangle; + } + + /** + * Get the figures of the brother's border nodes of + * <code>targetBorderItem</code>. + * + * @param targetBorderItem + * Contextual border item. + * @return The list of figure of the brother border nodes. + */ + protected List<IFigure> getBrotherFigures(final IFigure targetBorderItem) { + @SuppressWarnings("unchecked") + Iterable<IFigure> brotherFigures = Iterables.filter(targetBorderItem.getParent().getChildren(), + Predicates.and(Predicates.instanceOf(IFigure.class), Predicates.not(Predicates.equalTo(targetBorderItem)))); + return Lists.newArrayList(brotherFigures); + } + + /** + * Determine if the the given rectangle conflicts with the position of + * <code>figuresToCheck</code>. + * + * @param recommendedRect + * The desired bounds + * @param figuresToCheck + * Other figures to check if they conflict the + * <code>recommendedRect</code> + * @param portsFiguresToIgnore + * the ports figures to ignore, even if they are in + * <code>figuresToCheck</code> + * @return the optional Rectangle of the border item that is in conflict + * with the given bordered node (none option if no conflict) + */ + protected Option<Rectangle> conflicts(final Rectangle recommendedRect, List<IFigure> figuresToCheck, final Collection<IFigure> portsFiguresToIgnore) { + final ListIterator<IFigure> iterator = figuresToCheck.listIterator(); while (iterator.hasNext()) { - final IFigure borderItem = (IFigure) iterator.next(); + final IFigure borderItem = iterator.next(); if (!portsFiguresToIgnore.contains(borderItem)) { boolean takeIntoAccount = true; // We consider the brothers that : // * have a parent without layoutManager and are directly in a - // Layer (this case - // corresponds to feedback of collapsed bordered nodes that are - // expanded during drop) + // Layer (this case corresponds to feedback of collapsed + // bordered nodes that are expanded during drop) // * have a parent with a layoutManager and that contains a // constraint of type DBorderItemLocator that is located. if (borderItem.getParent().getLayoutManager() == null) { @@ -649,7 +736,7 @@ public class DBorderItemLocator extends BorderItemLocator { } if (borderItem.isVisible() && takeIntoAccount) { final Rectangle rect = new Rectangle(borderItem.getBounds()); - if (!(portsFiguresToIgnore.contains(borderItem)) && borderItem != targetBorderItem && rect.intersects(recommendedRect)) { + if (!(portsFiguresToIgnore.contains(borderItem)) && rect.intersects(recommendedRect)) { return Options.newSome(rect); } } @@ -777,12 +864,15 @@ public class DBorderItemLocator extends BorderItemLocator { * @param figuresToIgnore * list of figures to ignore during conflict detection. This list * must contain at least the <code>borderItem</code>. + * @param additionalFiguresForConflictDetection + * Figures that are not brothers of the current figure but that + * must be used for conflict detection * @return a rectangle containing the valid location */ - public Rectangle getValidLocation(Rectangle proposedLocation, IFigure borderItem, Collection<IFigure> figuresToIgnore) { + public Rectangle getValidLocation(Rectangle proposedLocation, IFigure borderItem, Collection<IFigure> figuresToIgnore, List<IFigure> additionalFiguresForConflictDetection) { final Rectangle realLocation = new Rectangle(proposedLocation); final int side = DBorderItemLocator.findClosestSideOfParent(proposedLocation, getParentBorder()); - final Point newTopLeft = locateOnBorder(realLocation.getTopLeft(), side, 0, borderItem, figuresToIgnore); + final Point newTopLeft = locateOnBorder(realLocation.getTopLeft(), side, 0, borderItem, figuresToIgnore, additionalFiguresForConflictDetection); realLocation.setLocation(newTopLeft); return realLocation; } @@ -791,8 +881,8 @@ public class DBorderItemLocator extends BorderItemLocator { * This method must be used only when commands are build to move a bordered * node (for example in * {@link org.eclipse.sirius.diagram.ui.graphical.edit.policies.SpecificBorderItemSelectionEditPolicy} - * ) after calling {@link #getValidLocation(Rectangle, IFigure, Collection)} - * . + * ) after calling + * {@link #getValidLocation(Rectangle, IFigure, Collection, List))} . * * @param figuresToIgnore * The list of figures to ignore. diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/figure/locator/FeedbackDBorderItemLocator.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/figure/locator/FeedbackDBorderItemLocator.java index 16abcbc444..2cdce25085 100644 --- a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/figure/locator/FeedbackDBorderItemLocator.java +++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/figure/locator/FeedbackDBorderItemLocator.java @@ -15,13 +15,16 @@ import java.util.List; import java.util.ListIterator; import org.eclipse.draw2d.IFigure; -import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.gmf.runtime.diagram.ui.figures.BorderedNodeFigure; import org.eclipse.sirius.diagram.ui.tools.api.figure.locator.DBorderItemLocator; import org.eclipse.sirius.ext.base.Option; import org.eclipse.sirius.ext.base.Options; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + /** * A specific bordered item locator for feedback when moving a border node. * @@ -40,20 +43,39 @@ public class FeedbackDBorderItemLocator extends DBorderItemLocator { } @Override - protected Option<Rectangle> conflicts(Point recommendedLocation, IFigure targetBorderItem, Collection<IFigure> portsFiguresToIgnore) { - final Rectangle recommendedRect = new Rectangle(recommendedLocation, getSize(targetBorderItem)); + protected List<IFigure> getBrotherFigures(IFigure targetBorderItem) { IFigure parentFigure = getParentFigure(); if (parentFigure instanceof BorderedNodeFigure) { parentFigure = ((BorderedNodeFigure) parentFigure).getBorderItemContainer(); } - final List borderItems = parentFigure.getChildren(); - final ListIterator iterator = borderItems.listIterator(); + @SuppressWarnings("unchecked") + Iterable<IFigure> brotherFigures = Iterables.filter(parentFigure.getChildren(), Predicates.and(Predicates.instanceOf(IFigure.class), Predicates.not(Predicates.equalTo(targetBorderItem)))); + return Lists.newArrayList(brotherFigures); + } + + /** + * Determine if the the given rectangle conflicts with the position of + * <code>figuresToCheck</code>. + * + * @param recommendedRect + * The desired bounds + * @param figuresToCheck + * Other figures to check if they conflict the + * <code>recommendedRect</code> + * @param portsFiguresToIgnore + * the ports figures to ignore, even if they are in + * <code>figuresToCheck</code> + * @return the optional Rectangle of the border item that is in conflict + * with the given bordered node (none option if no conflict) + */ + protected Option<Rectangle> conflicts(final Rectangle recommendedRect, List<IFigure> figuresToCheck, final Collection<IFigure> portsFiguresToIgnore) { + final ListIterator<IFigure> iterator = figuresToCheck.listIterator(); while (iterator.hasNext()) { - final IFigure borderItem = (IFigure) iterator.next(); + final IFigure borderItem = iterator.next(); if (!portsFiguresToIgnore.contains(borderItem)) { if (borderItem.isVisible()) { final Rectangle rect = new Rectangle(borderItem.getBounds()); - if (!(portsFiguresToIgnore.contains(borderItem)) && borderItem != targetBorderItem && rect.intersects(recommendedRect)) { + if (!(portsFiguresToIgnore.contains(borderItem)) && rect.intersects(recommendedRect)) { return Options.newSome(rect); } } @@ -61,5 +83,4 @@ public class FeedbackDBorderItemLocator extends DBorderItemLocator { } return Options.newNone(); } - } diff --git a/plugins/org.eclipse.sirius.doc/doc/Release Notes.html b/plugins/org.eclipse.sirius.doc/doc/Release Notes.html index c6658e26cc..7ffa10f630 100644 --- a/plugins/org.eclipse.sirius.doc/doc/Release Notes.html +++ b/plugins/org.eclipse.sirius.doc/doc/Release Notes.html @@ -72,6 +72,10 @@ <li>The method <code>org.eclipse.sirius.diagram.ui.business.internal.query.DNodeContainerQuery.getDefaultDimension()</code> has been added to compute the default size of a DNodeContainer. </li> + <li>The parameter + <code>additionalFiguresForConflictDetection</code> has been added to several methods of + <code>org.eclipse.sirius.diagram.ui.tools.api.figure.locator.DBorderItemLocator</code>. This parameter is used in case of simultaneous border nodes moves. This list corresponds to the already known border nodes feedbacks. They are used to detect conflicts with other moved nodes. + </li> </ul> <h4 id="Changesinorg.eclipse.sirius.ext.gmf.runtime">Changes in <code>org.eclipse.sirius.ext.gmf.runtime</code> @@ -86,7 +90,7 @@ <code>Point</code>. </li> <li> - <code>applyInverseZoomOnPoint(IGraphicalEditPart, Point)</code>: Apply the inverse of the current zoom(of + <code>applyInverseZoomOnPoint(IGraphicalEditPart, Point)</code>: Apply the inverse of the current zoom (of <code>IGraphicalEditPart</code>'s diagram) on the <code>Point</code>. </li> diff --git a/plugins/org.eclipse.sirius.doc/doc/Release Notes.textile b/plugins/org.eclipse.sirius.doc/doc/Release Notes.textile index 895213980c..dd5f01d299 100644 --- a/plugins/org.eclipse.sirius.doc/doc/Release Notes.textile +++ b/plugins/org.eclipse.sirius.doc/doc/Release Notes.textile @@ -25,12 +25,13 @@ h4. Changes in @org.eclipse.sirius.common@ h4. Changes in @org.eclipse.sirius.diagram.ui@ * The method @org.eclipse.sirius.diagram.ui.business.internal.query.DNodeContainerQuery.getDefaultDimension()@ has been added to compute the default size of a DNodeContainer. +* The parameter @additionalFiguresForConflictDetection@ has been added to several methods of @org.eclipse.sirius.diagram.ui.tools.api.figure.locator.DBorderItemLocator@. This parameter is used in case of simultaneous border nodes moves. This list corresponds to the already known border nodes feedbacks. They are used to detect conflicts with other moved nodes. h4. Changes in @org.eclipse.sirius.ext.gmf.runtime@ * Several utilities have been added in @org.eclipse.sirius.ext.gmf.runtime.editparts.GraphicalHelper@: ** @applyZoomOnPoint(IGraphicalEditPart, Point)@: Apply the current zoom (of @IGraphicalEditPart@'s diagram) on the @Point@. -** @applyInverseZoomOnPoint(IGraphicalEditPart, Point)@: Apply the inverse of the current zoom(of @IGraphicalEditPart@'s diagram) on the @Point@. +** @applyInverseZoomOnPoint(IGraphicalEditPart, Point)@: Apply the inverse of the current zoom (of @IGraphicalEditPart@'s diagram) on the @Point@. ** @appliedZoomOnRelativePoint(IGraphicalEditPart, Point)@ is now deprecated. Use @applyZoomOnPoint(IGraphicalEditPart, Point)@ instead. ** @getAnchorPoint(IGraphicalEditPart parent, Anchor anchor)@: Get the @Point@ (absolute draw2d coordinates) corresponding to this @Anchor@. ** @getAnchorPoint(IGraphicalEditPart parent, IdentityAnchor anchor)@: Get the @Point@ (absolute draw2d coordinates) corresponding to this @IdentityAnchor@. |
