diff --git a/src/org/jetuml/gui/DiagramCanvasController.java b/src/org/jetuml/gui/DiagramCanvasController.java index 2531f32c8..4fd1768d9 100644 --- a/src/org/jetuml/gui/DiagramCanvasController.java +++ b/src/org/jetuml/gui/DiagramCanvasController.java @@ -454,7 +454,7 @@ else if( aDragMode == DragMode.DRAG_LASSO ) private void alignMoveToGrid() { Iterator selectedNodes = aSelectionModel.getSelectedNodes().iterator(); - Rectangle entireBounds = aSelectionModel.getEntireSelectionBounds(); + Rectangle entireBounds = RenderingFacade.getBoundsIncludingParents(aSelectionModel); if( selectedNodes.hasNext() ) { @@ -549,7 +549,7 @@ else if(aDragMode == DragMode.DRAG_RUBBERBAND) // finds the point to reveal based on the entire selection private Point computePointToReveal(Point pMousePoint) { - Rectangle bounds = aSelectionModel.getEntireSelectionBounds(); + Rectangle bounds = RenderingFacade.getBoundsIncludingParents(aSelectionModel); int x = bounds.getMaxX(); int y = bounds.getMaxY(); @@ -577,7 +577,7 @@ private void moveSelection(Point pMousePoint) aSelectionModel.getSelectedNodes().forEach(selected -> selected.translate(dx, dy)); // If this translation results in exceeding the canvas bounds, roll back. - Rectangle bounds = aSelectionModel.getEntireSelectionBounds(); + Rectangle bounds =RenderingFacade.getBoundsIncludingParents(aSelectionModel); int dxCorrection = Math.max(-bounds.getX(), 0) + Math.min((int)aCanvas.getWidth() - bounds.getMaxX(), 0); int dyCorrection = Math.max(-bounds.getY(), 0) diff --git a/src/org/jetuml/gui/SelectionModel.java b/src/org/jetuml/gui/SelectionModel.java index 73e37f697..9c388ec16 100644 --- a/src/org/jetuml/gui/SelectionModel.java +++ b/src/org/jetuml/gui/SelectionModel.java @@ -20,6 +20,8 @@ *******************************************************************************/ package org.jetuml.gui; +import static java.util.stream.Collectors.toList; + import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -32,7 +34,6 @@ import org.jetuml.diagram.Node; import org.jetuml.geom.Line; import org.jetuml.geom.Rectangle; -import org.jetuml.viewers.DiagramViewer; import org.jetuml.viewers.edges.EdgeViewerRegistry; import org.jetuml.viewers.nodes.NodeViewerRegistry; @@ -77,59 +78,16 @@ public void selectAll(DiagramData pDiagramData) pDiagramData.edges().forEach(this::internalAddToSelection); aObserver.selectionModelChanged(); } - - /* - * Returns a rectangle that represents the bounding box of the last selected element. - */ - private Rectangle getLastSelectedBounds() - { - Optional lastSelected = getLastSelected(); - assert lastSelected.isPresent(); - return DiagramViewer.getBounds(lastSelected.get()); - } /** - * @return A rectangle that represents the bounding box of the - * entire selection including the bounds of their parent nodes. - */ - public Rectangle getEntireSelectionBounds() - { - Rectangle bounds = getLastSelectedBounds(); - for(DiagramElement selected : aSelected ) - { - bounds = addBounds(bounds, selected); - } - return bounds; - } - - // Recursively enlarge the current rectangle to include the selected DiagramElements - private Rectangle addBounds(Rectangle pBounds, DiagramElement pSelected) - { - if( pSelected instanceof Node && ((Node) pSelected).hasParent()) - { - return addBounds(pBounds, ((Node) pSelected).getParent()); - } - else - { - return pBounds.add(DiagramViewer.getBounds(pSelected)); - } - } - - /** - * @return An iterable of all selected nodes. This - * corresponds to the entire selection, except the edge. + * @return A list of all the selected nodes. */ public List getSelectedNodes() { - List result = new ArrayList<>(); - for( DiagramElement element : aSelected ) - { - if( element instanceof Node ) - { - result.add((Node) element); - } - } - return result; + return aSelected.stream() + .filter(e -> Node.class.isAssignableFrom(e.getClass())) + .map(Node.class::cast) + .collect(toList()); } /** diff --git a/src/org/jetuml/viewers/RenderingFacade.java b/src/org/jetuml/viewers/RenderingFacade.java index c4237dfb0..11d7c9c52 100644 --- a/src/org/jetuml/viewers/RenderingFacade.java +++ b/src/org/jetuml/viewers/RenderingFacade.java @@ -59,6 +59,12 @@ public static Canvas createIcon(DiagramElement pElement) } } + /** + * @param pElements The elements whose bounds we are interested in. + * @return The rectangle that bounds all elements in pElements, excluding their parent node. + * @pre pElements != null + * @pre pElements has at least one element. + */ public static Rectangle getBounds(Iterable pElements) { assert pElements != null; @@ -70,5 +76,40 @@ public static Rectangle getBounds(Iterable pElements) bounds = bounds.add(DiagramViewer.getBounds(elements.next())); } return bounds; - } + } + + /** + * @param pElements The elements whose bounds we are interested in. + * @return A rectangle that represents the bounding box of the + * entire selection including the bounds of their parent nodes. + * @pre pElements != null + * @pre pElements has at least one element. + */ + public static Rectangle getBoundsIncludingParents(Iterable pElements) + { + assert pElements != null; + assert pElements.iterator().hasNext(); + Iterator elements = pElements.iterator(); + DiagramElement next = elements.next(); + Rectangle bounds = DiagramViewer.getBounds(next); + bounds = addBounds(bounds, next); + while( elements.hasNext() ) + { + bounds = addBounds(bounds, elements.next()); + } + return bounds; + } + + // Recursively enlarge the current rectangle to include the selected DiagramElements + private static Rectangle addBounds(Rectangle pBounds, DiagramElement pElement) + { + if( pElement instanceof Node && ((Node) pElement).hasParent()) + { + return addBounds(pBounds, ((Node) pElement).getParent()); + } + else + { + return pBounds.add(DiagramViewer.getBounds(pElement)); + } + } } diff --git a/test/org/jetuml/gui/TestSelectionModel.java b/test/org/jetuml/gui/TestSelectionModel.java index 25fffc101..055a9db63 100644 --- a/test/org/jetuml/gui/TestSelectionModel.java +++ b/test/org/jetuml/gui/TestSelectionModel.java @@ -100,7 +100,7 @@ private void assertContent(DiagramElement... pElements) private void assertEntireSelectionBounds(int pX, int pY, int pWidth, int pHeight) { - assertEquals(new Rectangle(pX, pY, pWidth, pHeight), aModel.getEntireSelectionBounds()); + assertEquals(new Rectangle(pX, pY, pWidth, pHeight), RenderingFacade.getBoundsIncludingParents(aModel)); } private void assertSelectionBounds(int pX, int pY, int pWidth, int pHeight)