2424import org .eclipse .wb .gef .graphical .tools .ResizeTracker ;
2525import org .eclipse .wb .gef .graphical .tools .SelectionTool ;
2626import org .eclipse .wb .internal .core .utils .reflect .ReflectionUtils ;
27+ import org .eclipse .wb .internal .draw2d .FigureCanvas ;
28+ import org .eclipse .wb .internal .gef .core .EditDomain ;
2729import org .eclipse .wb .internal .gef .graphical .GraphicalViewer ;
2830
2931import org .eclipse .draw2d .IFigure ;
3032import org .eclipse .draw2d .PositionConstants ;
33+ import org .eclipse .draw2d .RangeModel ;
34+ import org .eclipse .draw2d .Viewport ;
3135import org .eclipse .draw2d .geometry .Dimension ;
3236import org .eclipse .draw2d .geometry .Point ;
3337import org .eclipse .draw2d .geometry .PointList ;
5054import org .assertj .core .api .Assertions ;
5155import org .assertj .core .description .Description ;
5256
57+ import java .io .Closeable ;
5358import java .util .HashSet ;
5459import java .util .Iterator ;
5560import java .util .List ;
@@ -65,6 +70,9 @@ public final class GraphicalRobot {
6570 // viewer
6671 private final GraphicalViewer m_viewer ;
6772 private final EventSender m_sender ;
73+ private final FigureCanvas m_canvas ;
74+ private final RangeModel m_horizontalRange ;
75+ private final RangeModel m_verticalRange ;
6876 // source
6977 private boolean sourceSideMode = false ;
7078 private int sourceWidth ;
@@ -91,6 +99,12 @@ public final class GraphicalRobot {
9199 public GraphicalRobot (GraphicalViewer viewer ) {
92100 m_viewer = viewer ;
93101 m_sender = new EventSender (viewer .getControl ());
102+ m_canvas = m_viewer .getControl ();
103+ Viewport viewport = m_canvas .getViewport ();
104+ m_horizontalRange = viewport .getHorizontalRangeModel ();
105+ m_verticalRange = viewport .getVerticalRangeModel ();
106+ EditDomain editDomain = m_viewer .getEditDomain ();
107+ editDomain .setActiveTool (new AbsoluteSelectionTool ());
94108 }
95109
96110 ////////////////////////////////////////////////////////////////////////////
@@ -188,7 +202,13 @@ public GraphicalRobot beginMove(Object object) {
188202 // find MoveHandle
189203 mouseX = bounds .x ;
190204 mouseY = bounds .y ;
191- while (!(m_viewer .findHandleAt (new Point (mouseX , mouseY )) instanceof MoveHandle )) {
205+ Rectangle rootBounds = m_canvas .getRootFigure ().getBounds ();
206+ while (rootBounds .contains (mouseX , mouseY )) {
207+ try (AutoScroller scroller = new AutoScroller (mouseX , mouseY )) {
208+ if (m_viewer .findHandleAt (scroller .location ) instanceof MoveHandle ) {
209+ break ;
210+ }
211+ }
192212 mouseX ++;
193213 }
194214 mouseInSourceX = mouseX - bounds .x ;
@@ -296,18 +316,69 @@ private Point findSideHandle(Predicate<Handle> predicate,
296316 int deltaY ) {
297317 x += bounds .x ;
298318 y += bounds .y ;
299- while (x < bounds .right () && y < bounds .bottom ()) {
300- Point p = new Point (x , y );
301- Handle handle = (Handle ) m_viewer .findHandleAt (p );
302- if (predicate .test (handle )) {
303- return handle .getBounds ().getCenter ();
319+ Rectangle rootBounds = m_canvas .getRootFigure ().getBounds ();
320+ while (x < bounds .right () && y < bounds .bottom () && rootBounds .contains (x , y )) {
321+ try (AutoScroller scroller = new AutoScroller (x , y )) {
322+ Handle handle = (Handle ) m_viewer .findHandleAt (scroller .location );
323+ if (predicate .test (handle )) {
324+ return handle .getBounds ().getCenter ();
325+ }
326+ x += deltaX ;
327+ y += deltaY ;
304328 }
305- x += deltaX ;
306- y += deltaY ;
307329 }
308330 return null ;
309331 }
310332
333+ /**
334+ * Subclass of the selection tool that also supports figures outside the visible
335+ * area. If necessary, the absolute coordinates that are passed to this tool are
336+ * converted to relative coordinates and the viewer scrolled by the offset. This
337+ * is necessary to have the {@link GraphicalViewer#findHandleAt(Point)} behave
338+ * correctly.
339+ */
340+ private class AbsoluteSelectionTool extends SelectionTool {
341+ @ Override
342+ protected boolean handleButtonDown (int button ) {
343+ Point absoluteLocation = getLocation ();
344+ try (AutoScroller scroller = new AutoScroller (absoluteLocation .x , absoluteLocation .y )) {
345+ getCurrentInput ().setMouseLocation (scroller .location .x , scroller .location .y );
346+ return super .handleButtonDown (button );
347+ } finally {
348+ getCurrentInput ().setMouseLocation (absoluteLocation .x , absoluteLocation .y );
349+ }
350+ }
351+ }
352+
353+ /**
354+ * This class scrolls the viewer so that the absolute coordinates that are
355+ * passed as constructor arguments are within the visible area. This is required
356+ * because GEF does not support selecting edit parts/figures that are currently
357+ * invisible. The relative coordinates can then be accessed via
358+ * {@link #scrolledX} and {@link #scrolledY}.
359+ */
360+ private class AutoScroller implements Closeable {
361+ private final int offX ;
362+ private final int offY ;
363+ private final Point location ;
364+
365+ public AutoScroller (int x , int y ) {
366+ offX = Math .max (x - m_horizontalRange .getExtent () + 8 , 0 );
367+ offY = Math .max (y - m_verticalRange .getExtent () + 8 , 0 );
368+ m_horizontalRange .setValue (offX );
369+ m_verticalRange .setValue (offY );
370+ int scrolledX = x - m_horizontalRange .getValue ();
371+ int scrolledY = y - m_verticalRange .getValue ();
372+ location = new Point (scrolledX , scrolledY );
373+ }
374+
375+ @ Override
376+ public void close () {
377+ m_horizontalRange .setValue (0 );
378+ m_verticalRange .setValue (0 );
379+ }
380+ }
381+
311382 ////////////////////////////////////////////////////////////////////////////
312383 //
313384 // Side to set position
0 commit comments