From 7c5d432270b49757bb6f92d30112e0a3e181c065 Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Tue, 24 Jun 2025 17:36:11 +0200 Subject: [PATCH 1/2] [Draw2D] Implement toString() method for Handle and Layer classes --- .../src-draw2d/org/eclipse/wb/draw2d/Layer.java | 5 +++++ .../src-gef/org/eclipse/wb/gef/graphical/handles/Handle.java | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/org.eclipse.wb.core/src-draw2d/org/eclipse/wb/draw2d/Layer.java b/org.eclipse.wb.core/src-draw2d/org/eclipse/wb/draw2d/Layer.java index 89b5096ea..ecbd453dc 100644 --- a/org.eclipse.wb.core/src-draw2d/org/eclipse/wb/draw2d/Layer.java +++ b/org.eclipse.wb.core/src-draw2d/org/eclipse/wb/draw2d/Layer.java @@ -80,4 +80,9 @@ public String getName() { @Override public void setOpaque(boolean opaque) { } + + @Override + public String toString() { + return "[%s] %s".formatted(getClass().getSimpleName(), getName()); + } } \ No newline at end of file diff --git a/org.eclipse.wb.core/src-gef/org/eclipse/wb/gef/graphical/handles/Handle.java b/org.eclipse.wb.core/src-gef/org/eclipse/wb/gef/graphical/handles/Handle.java index f9ae691df..318a11afd 100644 --- a/org.eclipse.wb.core/src-gef/org/eclipse/wb/gef/graphical/handles/Handle.java +++ b/org.eclipse.wb.core/src-gef/org/eclipse/wb/gef/graphical/handles/Handle.java @@ -164,4 +164,9 @@ public Point getAccessibleLocation() { translateToAbsolute(p); return p; } + + @Override + public String toString() { + return "[%s] %s".formatted(getClass().getSimpleName(), getBounds()); + } } \ No newline at end of file From 7fcb3ed27c70adc6654af2503cb1f9c2c24ac853 Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Tue, 24 Jun 2025 17:39:35 +0200 Subject: [PATCH 2/2] [GEF] Calculate target handle using findFigureAt() This replaces the TargetFigureFindVisitor used in the findTargetHandle() method with call to findFigureAt(), which is provided by Draw2D. A custom filter is used to restrict the search to only accept Handles and to only look in the specified layer. --- .../gef/graphical/GraphicalViewer.java | 18 ++-- .../eclipse/wb/tests/gef/GraphicalRobot.java | 87 +++++++++++++++++-- 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/org.eclipse.wb.core/src-gef/org/eclipse/wb/internal/gef/graphical/GraphicalViewer.java b/org.eclipse.wb.core/src-gef/org/eclipse/wb/internal/gef/graphical/GraphicalViewer.java index 25d99dd28..dba95f79d 100644 --- a/org.eclipse.wb.core/src-gef/org/eclipse/wb/internal/gef/graphical/GraphicalViewer.java +++ b/org.eclipse.wb.core/src-gef/org/eclipse/wb/internal/gef/graphical/GraphicalViewer.java @@ -18,12 +18,12 @@ import org.eclipse.wb.internal.draw2d.FigureCanvas; import org.eclipse.wb.internal.draw2d.IRootFigure; import org.eclipse.wb.internal.draw2d.RootFigure; -import org.eclipse.wb.internal.draw2d.TargetFigureFindVisitor; import org.eclipse.wb.internal.gef.core.AbstractEditPartViewer; import org.eclipse.wb.internal.gef.core.EditDomain; import org.eclipse.wb.internal.gef.core.TargetEditPartFindVisitor; import org.eclipse.draw2d.IFigure; +import org.eclipse.draw2d.TreeSearch; import org.eclipse.draw2d.geometry.Point; import org.eclipse.gef.Handle; import org.eclipse.swt.SWT; @@ -221,9 +221,17 @@ public Handle findHandleAt(Point p) { * given location (x, y). */ private Handle findTargetHandle(String layer, Point p) { - TargetFigureFindVisitor visitor = new TargetFigureFindVisitor(m_canvas, p.x, p.y); - ((Layer) m_rootEditPart.getLayer(layer)).accept(visitor, false); - Figure targetFigure = visitor.getTargetFigure(); - return targetFigure instanceof Handle ? (Handle) targetFigure : null; + return (Handle) m_canvas.getLightweightSystem().getRootFigure().findFigureAt(p.x, p.y, + new TreeSearch() { + @Override + public boolean accept(IFigure figure) { + return figure instanceof Handle; + } + + @Override + public boolean prune(IFigure figure) { + return figure instanceof Layer layerFigure && !layer.equals(layerFigure.getName()); + } + }); } } \ No newline at end of file diff --git a/org.eclipse.wb.tests/src/org/eclipse/wb/tests/gef/GraphicalRobot.java b/org.eclipse.wb.tests/src/org/eclipse/wb/tests/gef/GraphicalRobot.java index c2242bbb8..ed426a3bf 100644 --- a/org.eclipse.wb.tests/src/org/eclipse/wb/tests/gef/GraphicalRobot.java +++ b/org.eclipse.wb.tests/src/org/eclipse/wb/tests/gef/GraphicalRobot.java @@ -24,10 +24,14 @@ import org.eclipse.wb.gef.graphical.tools.ResizeTracker; import org.eclipse.wb.gef.graphical.tools.SelectionTool; import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils; +import org.eclipse.wb.internal.draw2d.FigureCanvas; +import org.eclipse.wb.internal.gef.core.EditDomain; import org.eclipse.wb.internal.gef.graphical.GraphicalViewer; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.PositionConstants; +import org.eclipse.draw2d.RangeModel; +import org.eclipse.draw2d.Viewport; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PointList; @@ -50,6 +54,7 @@ import org.assertj.core.api.Assertions; import org.assertj.core.description.Description; +import java.io.Closeable; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -65,6 +70,9 @@ public final class GraphicalRobot { // viewer private final GraphicalViewer m_viewer; private final EventSender m_sender; + private final FigureCanvas m_canvas; + private final RangeModel m_horizontalRange; + private final RangeModel m_verticalRange; // source private boolean sourceSideMode = false; private int sourceWidth; @@ -91,6 +99,12 @@ public final class GraphicalRobot { public GraphicalRobot(GraphicalViewer viewer) { m_viewer = viewer; m_sender = new EventSender(viewer.getControl()); + m_canvas = m_viewer.getControl(); + Viewport viewport = m_canvas.getViewport(); + m_horizontalRange = viewport.getHorizontalRangeModel(); + m_verticalRange = viewport.getVerticalRangeModel(); + EditDomain editDomain = m_viewer.getEditDomain(); + editDomain.setActiveTool(new AbsoluteSelectionTool()); } //////////////////////////////////////////////////////////////////////////// @@ -188,7 +202,13 @@ public GraphicalRobot beginMove(Object object) { // find MoveHandle mouseX = bounds.x; mouseY = bounds.y; - while (!(m_viewer.findHandleAt(new Point(mouseX, mouseY)) instanceof MoveHandle)) { + Rectangle rootBounds = m_canvas.getRootFigure().getBounds(); + while (rootBounds.contains(mouseX, mouseY)) { + try (AutoScroller scroller = new AutoScroller(mouseX, mouseY)) { + if (m_viewer.findHandleAt(scroller.location) instanceof MoveHandle) { + break; + } + } mouseX++; } mouseInSourceX = mouseX - bounds.x; @@ -296,18 +316,69 @@ private Point findSideHandle(Predicate predicate, int deltaY) { x += bounds.x; y += bounds.y; - while (x < bounds.right() && y < bounds.bottom()) { - Point p = new Point(x, y); - Handle handle = (Handle) m_viewer.findHandleAt(p); - if (predicate.test(handle)) { - return handle.getBounds().getCenter(); + Rectangle rootBounds = m_canvas.getRootFigure().getBounds(); + while (x < bounds.right() && y < bounds.bottom() && rootBounds.contains(x, y)) { + try (AutoScroller scroller = new AutoScroller(x, y)) { + Handle handle = (Handle) m_viewer.findHandleAt(scroller.location); + if (predicate.test(handle)) { + return handle.getBounds().getCenter(); + } + x += deltaX; + y += deltaY; } - x += deltaX; - y += deltaY; } return null; } + /** + * Subclass of the selection tool that also supports figures outside the visible + * area. If necessary, the absolute coordinates that are passed to this tool are + * converted to relative coordinates and the viewer scrolled by the offset. This + * is necessary to have the {@link GraphicalViewer#findHandleAt(Point)} behave + * correctly. + */ + private class AbsoluteSelectionTool extends SelectionTool { + @Override + protected boolean handleButtonDown(int button) { + Point absoluteLocation = getLocation(); + try (AutoScroller scroller = new AutoScroller(absoluteLocation.x, absoluteLocation.y)) { + getCurrentInput().setMouseLocation(scroller.location.x, scroller.location.y); + return super.handleButtonDown(button); + } finally { + getCurrentInput().setMouseLocation(absoluteLocation.x, absoluteLocation.y); + } + } + } + + /** + * This class scrolls the viewer so that the absolute coordinates that are + * passed as constructor arguments are within the visible area. This is required + * because GEF does not support selecting edit parts/figures that are currently + * invisible. The relative coordinates can then be accessed via + * {@link #scrolledX} and {@link #scrolledY}. + */ + private class AutoScroller implements Closeable { + private final int offX; + private final int offY; + private final Point location; + + public AutoScroller(int x, int y) { + offX = Math.max(x - m_horizontalRange.getExtent() + 8, 0); + offY = Math.max(y - m_verticalRange.getExtent() + 8, 0); + m_horizontalRange.setValue(offX); + m_verticalRange.setValue(offY); + int scrolledX = x - m_horizontalRange.getValue(); + int scrolledY = y - m_verticalRange.getValue(); + location = new Point(scrolledX, scrolledY); + } + + @Override + public void close() { + m_horizontalRange.setValue(0); + m_verticalRange.setValue(0); + } + } + //////////////////////////////////////////////////////////////////////////// // // Side to set position