Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/eclipsecopy/DragUtil.java')
-rwxr-xr-xplugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/eclipsecopy/DragUtil.java417
1 files changed, 417 insertions, 0 deletions
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/eclipsecopy/DragUtil.java b/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/eclipsecopy/DragUtil.java
new file mode 100755
index 00000000000..68c01d478f4
--- /dev/null
+++ b/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/eclipsecopy/DragUtil.java
@@ -0,0 +1,417 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.papyrus.infra.core.sasheditor.internal.eclipsecopy;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Tracker;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.DragCursors;
+
+/**
+ * Provides the methods for attaching drag-and-drop listeners to SWT controls.
+ */
+public class DragUtil {
+ private static final String DROP_TARGET_ID = "org.eclipse.ui.internal.dnd.dropTarget"; //$NON-NLS-1$
+
+ /**
+ * The location where all drags will end. If this is non-null, then
+ * all user input is ignored in drag/drop. If null, we use user input
+ * to determine where objects should be dropped.
+ */
+ private static TestDropLocation forcedDropTarget = null;
+
+ /**
+ * List of IDragOverListener
+ */
+ private static List defaultTargets = new ArrayList();
+
+ /**
+ * Sets the drop target for the given control. It is possible to add one or more
+ * targets for a "null" control. This becomes a default target that is used if no
+ * other targets are found (for example, when dragging objects off the application
+ * window).
+ *
+ * @param control
+ * the control that should be treated as a drag target, or null
+ * to indicate the default target
+ * @param target
+ * the drag target to handle the given control
+ */
+ public static void addDragTarget(Control control, IDragOverListener target) {
+ if (control == null) {
+ defaultTargets.add(target);
+ } else {
+ List targetList = getTargetList(control);
+
+ if (targetList == null) {
+ targetList = new ArrayList(1);
+ }
+ targetList.add(target);
+ control.setData(DROP_TARGET_ID, targetList);
+ }
+ }
+
+ /**
+ * Return the list of 'IDragOverListener' elements associated with
+ * the given control. If there's a 'global' listener then always
+ * return it.
+ *
+ * @param control
+ * @return
+ */
+ private static List getTargetList(Control control) {
+ List result = (List) control.getData(DROP_TARGET_ID);
+ return result;
+ }
+
+ /**
+ * Removes a drop target from the given control.
+ *
+ * @param control
+ * @param target
+ */
+ public static void removeDragTarget(Control control,
+ IDragOverListener target) {
+ if (control == null) {
+ defaultTargets.remove(target);
+ } else {
+ List targetList = getTargetList(control);
+ if (targetList != null) {
+ targetList.remove(target);
+ if (targetList.isEmpty()) {
+ control.setData(DROP_TARGET_ID, null);
+ }
+ }
+ }
+ }
+
+ /**
+ * Shorthand method. Returns the bounding rectangle for the given control, in
+ * display coordinates. Note that all 'Shell' controls are expected to be 'top level'
+ * so DO NOT do the origin offset for them.
+ *
+ * @param draggedItem
+ * @param boundsControl
+ * @return
+ */
+ public static Rectangle getDisplayBounds(Control boundsControl) {
+ Control parent = boundsControl.getParent();
+ if (parent == null || boundsControl instanceof Shell) {
+ return boundsControl.getBounds();
+ }
+
+ return Geometry.toDisplay(parent, boundsControl.getBounds());
+ }
+
+ public static boolean performDrag(final Object draggedItem,
+ Rectangle sourceBounds, Point initialLocation, boolean allowSnapping) {
+
+ IDropTarget target = dragToTarget(draggedItem, sourceBounds,
+ initialLocation, allowSnapping);
+
+ if (target == null) {
+ return false;
+ }
+
+ target.drop();
+
+ // If the target can handle a 'finished' notification then send one
+ if (target instanceof IDropTarget2) {
+ ((IDropTarget2) target).dragFinished(true);
+ }
+
+ return true;
+ }
+
+ /**
+ * Drags the given item to the given location (in display coordinates). This
+ * method is intended for use by test suites.
+ *
+ * @param draggedItem
+ * object being dragged
+ * @param finalLocation
+ * location being dragged to
+ * @return true iff the drop was accepted
+ */
+ public static boolean dragTo(Display display, Object draggedItem,
+ Point finalLocation, Rectangle dragRectangle) {
+ Control currentControl = SwtUtil.findControl(display, finalLocation);
+
+ IDropTarget target = getDropTarget(currentControl, draggedItem,
+ finalLocation, dragRectangle);
+
+ if (target == null) {
+ return false;
+ }
+
+ target.drop();
+
+ return true;
+ }
+
+ /**
+ * Forces all drags to end at the given position (display coordinates). Intended
+ * for use by test suites. If this method is called, then all subsequent calls
+ * to performDrag will terminate immediately and behave as though the object were
+ * dragged to the given location. Calling this method with null cancels this
+ * behavior and causes performDrag to behave normally.
+ *
+ * @param forcedLocation
+ * location where objects will be dropped (or null to
+ * cause drag/drop to behave normally).
+ */
+ public static void forceDropLocation(TestDropLocation forcedLocation) {
+ forcedDropTarget = forcedLocation;
+ }
+
+ /**
+ * Drags the given item, given an initial bounding rectangle in display coordinates.
+ * Due to a quirk in the Tracker class, changing the tracking rectangle when using the
+ * keyboard will also cause the mouse cursor to move. Since "snapping" causes the tracking
+ * rectangle to change based on the position of the mouse cursor, it is impossible to do
+ * drag-and-drop with the keyboard when snapping is enabled.
+ *
+ * @param draggedItem
+ * object being dragged
+ * @param sourceBounds
+ * initial bounding rectangle for the dragged item
+ * @param initialLocation
+ * initial position of the mouse cursor
+ * @param allowSnapping
+ * true iff the rectangle should snap to the drop location. This must
+ * be false if the user might be doing drag-and-drop using the keyboard.
+ *
+ * @return
+ */
+ static IDropTarget dragToTarget(final Object draggedItem,
+ final Rectangle sourceBounds, final Point initialLocation,
+ final boolean allowSnapping) {
+ final Display display = Display.getCurrent();
+
+ // Testing...immediately 'drop' onto the test target
+ if (forcedDropTarget != null) {
+ Point location = forcedDropTarget.getLocation();
+
+ Control currentControl = SwtUtil.findControl(forcedDropTarget.getShells(), location);
+ return getDropTarget(currentControl, draggedItem, location,
+ sourceBounds);
+ }
+
+ // Create a tracker. This is just an XOR rect on the screen.
+ // As it moves we notify the drag listeners.
+ final Tracker tracker = new Tracker(display, SWT.NULL);
+ tracker.setStippled(true);
+
+ tracker.addListener(SWT.Move, event -> display.syncExec(() -> {
+ // Get the curslor location as a point
+ Point location = new Point(event.x, event.y);
+
+ // Select a drop target; use the global one by default
+ IDropTarget target = null;
+
+ Control targetControl = display.getCursorControl();
+
+ // Get the drop target for this location
+ target = getDropTarget(targetControl,
+ draggedItem, location,
+ tracker.getRectangles()[0]);
+
+ // Set up the tracker feedback based on the target
+ Rectangle snapTarget = null;
+ if (target != null) {
+ snapTarget = target.getSnapRectangle();
+
+ tracker.setCursor(target.getCursor());
+ } else {
+ tracker.setCursor(DragCursors
+ .getCursor(DragCursors.INVALID));
+ }
+
+ // If snapping then reset the tracker's rectangle based on the current drop target
+ if (allowSnapping) {
+ if (snapTarget == null) {
+ snapTarget = new Rectangle(sourceBounds.x
+ + location.x - initialLocation.x,
+ sourceBounds.y + location.y
+ - initialLocation.y,
+ sourceBounds.width, sourceBounds.height);
+ }
+
+ // Try to prevent flicker: don't change the rectangles if they're already in
+ // the right location
+ Rectangle[] currentRectangles = tracker.getRectangles();
+
+ if (!(currentRectangles.length == 1 && currentRectangles[0]
+ .equals(snapTarget))) {
+ tracker.setRectangles(new Rectangle[] { Geometry.copy(snapTarget) });
+ }
+ }
+ }));
+
+ // Setup...when the drag starts we might already be over a valid target, check this...
+ // If there is a 'global' target then skip the check
+ IDropTarget target = null;
+ Control startControl = display.getCursorControl();
+
+ if (startControl != null && allowSnapping) {
+ target = getDropTarget(startControl,
+ draggedItem, initialLocation,
+ sourceBounds);
+ }
+
+ // Set up an initial tracker rectangle
+ Rectangle startRect = sourceBounds;
+ if (target != null) {
+ Rectangle rect = target.getSnapRectangle();
+
+ if (rect != null) {
+ startRect = rect;
+ }
+
+ tracker.setCursor(target.getCursor());
+ }
+
+ if (startRect != null) {
+ tracker.setRectangles(new Rectangle[] { Geometry.copy(startRect) });
+ }
+
+ // Tracking Loop...tracking is preformed on the 'SWT.Move' listener registered
+ // against the tracker.
+
+ // HACK:
+ // Some control needs to capture the mouse during the drag or other
+ // controls will interfere with the cursor
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ if (shell != null) {
+ shell.setCapture(true);
+ }
+
+ // Run tracker until mouse up occurs or escape key pressed.
+ boolean trackingOk = tracker.open();
+
+ // HACK:
+ // Release the mouse now
+ if (shell != null) {
+ shell.setCapture(false);
+ }
+
+ // Done tracking...
+
+ // Get the current drop target
+ IDropTarget dropTarget = null;
+ Point finalLocation = display.getCursorLocation();
+ Control targetControl = display.getCursorControl();
+ dropTarget = getDropTarget(targetControl, draggedItem,
+ finalLocation, tracker.getRectangles()[0]);
+
+ // Cleanup...
+ tracker.dispose();
+
+ // if we're going to perform a 'drop' then delay the issuing of the 'finished'
+ // callback until after it's done...
+ if (trackingOk) {
+ return dropTarget;
+ } else if (dropTarget != null && dropTarget instanceof IDropTarget2) {
+ // If the target can handle a 'finished' notification then send one
+ ((IDropTarget2) dropTarget).dragFinished(false);
+ }
+
+ return null;
+ }
+
+ /**
+ * Given a list of IDragOverListeners and a description of what is being dragged, it returns
+ * a IDropTarget for the current drop.
+ *
+ * @param toSearch
+ * @param mostSpecificControl
+ * @param draggedObject
+ * @param position
+ * @param dragRectangle
+ * @return
+ */
+ private static IDropTarget getDropTarget(List toSearch,
+ Control mostSpecificControl, Object draggedObject, Point position,
+ Rectangle dragRectangle) {
+ if (toSearch == null) {
+ return null;
+ }
+
+ Iterator iter = toSearch.iterator();
+ while (iter.hasNext()) {
+ IDragOverListener next = (IDragOverListener) iter.next();
+
+ IDropTarget dropTarget = next.drag(mostSpecificControl,
+ draggedObject, position, dragRectangle);
+
+ if (dropTarget != null) {
+ return dropTarget;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the drag target for the given control or null if none.
+ *
+ * @param toSearch
+ * @param e
+ * @return
+ */
+ public static IDropTarget getDropTarget(Control toSearch,
+ Object draggedObject, Point position, Rectangle dragRectangle) {
+ // Search for a listener by walking the control's parent hierarchy
+ for (Control current = toSearch; current != null; current = current
+ .getParent()) {
+ IDropTarget dropTarget = getDropTarget(getTargetList(current),
+ toSearch, draggedObject, position, dragRectangle);
+
+ if (dropTarget != null) {
+ return dropTarget;
+ }
+
+ // Don't look to parent shells for drop targets
+ if (current instanceof Shell) {
+ break;
+ }
+ }
+
+ // No controls could handle this event -- check for default targets
+ return getDropTarget(defaultTargets, toSearch, draggedObject, position,
+ dragRectangle);
+ }
+
+ /**
+ * Returns the location of the given event, in display coordinates
+ *
+ * @return
+ */
+ public static Point getEventLoc(Event event) {
+ Control ctrl = (Control) event.widget;
+ return ctrl.toDisplay(new Point(event.x, event.y));
+ }
+
+}

Back to the top