001: /*******************************************************************************
002: * Copyright (c) 2004, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.presentations;
011:
012: import org.eclipse.jface.util.Geometry;
013: import org.eclipse.swt.SWT;
014: import org.eclipse.swt.graphics.Point;
015: import org.eclipse.swt.widgets.Control;
016: import org.eclipse.swt.widgets.Event;
017: import org.eclipse.swt.widgets.Listener;
018: import org.eclipse.ui.internal.dnd.DragUtil;
019:
020: /**
021: * Contains various utility methods for Presentation authors
022: *
023: * @since 3.0
024: */
025: public class PresentationUtil {
026: private static Point anchor;
027:
028: private final static int HYSTERESIS = 16;
029:
030: private static int initialMouseButton = 0;
031:
032: private final static String LISTENER_ID = PresentationUtil.class
033: .getName()
034: + ".dragListener"; //$NON-NLS-1$
035:
036: private static Event dragEvent;
037:
038: private static Listener currentListener = null;
039:
040: private static Control dragSource;
041:
042: private static Listener dragListener = new Listener() {
043: public void handleEvent(Event event) {
044: dragEvent = event;
045: if (dragSource != event.widget) {
046: dragSource = null;
047: currentListener = null;
048: }
049: }
050: };
051:
052: /**
053: * Returns whether the mouse has moved enough to warrant
054: * opening a tracker.
055: */
056: private static boolean hasMovedEnough(Event event) {
057: return Geometry.distanceSquared(DragUtil.getEventLoc(event),
058: anchor) >= HYSTERESIS * HYSTERESIS;
059: }
060:
061: private static Listener moveListener = new Listener() {
062: public void handleEvent(Event event) {
063: handleMouseMove(event);
064: }
065: };
066:
067: private static Listener clickListener = new Listener() {
068: public void handleEvent(Event e) {
069: handleMouseClick(e);
070: }
071: };
072:
073: private static Listener mouseDownListener = new Listener() {
074: public void handleEvent(Event event) {
075: if (event.widget instanceof Control) {
076: // Remember the button that started the drag so we
077: // can forward it on the call to the 'externalDragListener'
078: initialMouseButton = event.button;
079:
080: dragSource = (Control) event.widget;
081: currentListener = (Listener) dragSource
082: .getData(LISTENER_ID);
083: anchor = DragUtil.getEventLoc(event);
084:
085: if (dragEvent != null
086: && (dragEvent.widget != dragSource)) {
087: dragEvent = null;
088: }
089: }
090: }
091: };
092:
093: private static void handleMouseClick(Event event) {
094: cancelDrag();
095: }
096:
097: private static void handleMouseMove(Event e) {
098: if (currentListener != null && dragEvent != null
099: && hasMovedEnough(e)) {
100: if (dragSource != null && !dragSource.isDisposed()
101: && dragSource == e.widget) {
102: Event de = dragEvent;
103:
104: // cache the current value so we can restore it later
105: int originalMouseButton = de.button;
106:
107: // Update the button field so that the drag listener
108: // can detect whether or not it's a 'right button' drag
109: de.button = initialMouseButton;
110:
111: Listener l = currentListener;
112: cancelDrag();
113: l.handleEvent(de);
114:
115: // Restore the event's state so that other listeners see
116: // the original values
117: de.button = originalMouseButton;
118: } else {
119: cancelDrag();
120: }
121: }
122: }
123:
124: private static void cancelDrag() {
125: currentListener = null;
126: dragEvent = null;
127: dragSource = null;
128:
129: initialMouseButton = 0;
130: }
131:
132: /**
133: * Adds a drag listener to the given control. The behavior is very similar
134: * to control.addListener(SWT.DragDetect, dragListener), however the listener
135: * attached by this method is less sensitive. The drag event is only fired
136: * once the user moves the cursor more than HYSTERESIS pixels.
137: * <p>
138: * This is useful for registering a listener that will trigger an editor or
139: * view drag, since an overly sensitive drag listener can cause users to accidentally
140: * drag views when trying to select a tab.</p>
141: * <p>
142: * Currently, only one such drag listener can be registered at a time. </p>
143: *
144: * @param control the control containing the drag listener
145: * @param externalDragListener the drag listener to attach
146: */
147: public static void addDragListener(Control control,
148: Listener externalDragListener) {
149: control.addListener(SWT.DragDetect, dragListener);
150: control.addListener(SWT.MouseUp, clickListener);
151: control.addListener(SWT.MouseDoubleClick, clickListener);
152: control.addListener(SWT.MouseDown, mouseDownListener);
153: control.addListener(SWT.MouseMove, moveListener);
154: control.setData(LISTENER_ID, externalDragListener);
155: }
156:
157: /**
158: * Removes a drag listener that was previously attached using addDragListener
159: *
160: * @param control the control containing the drag listener
161: * @param externalDragListener the drag listener to remove
162: */
163: public static void removeDragListener(Control control,
164: Listener externalDragListener) {
165: control.removeListener(SWT.DragDetect, dragListener);
166: control.removeListener(SWT.MouseUp, clickListener);
167: control.removeListener(SWT.MouseDoubleClick, clickListener);
168: control.removeListener(SWT.MouseDown, mouseDownListener);
169: control.removeListener(SWT.MouseMove, moveListener);
170: control.setData(LISTENER_ID, null);
171: if (externalDragListener == currentListener) {
172: cancelDrag();
173: }
174: }
175:
176: }
|