blob: a99907b03dfc5a7dba214fa76a8902ca96b9854c [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.awt.dnd;
27
28import java.awt.AWTEvent;
29import java.awt.Component;
30import java.awt.Cursor;
31import java.awt.EventQueue;
32import java.awt.Image;
33import java.awt.Point;
34
35import java.awt.datatransfer.Transferable;
36
37import java.awt.dnd.DnDConstants;
38import java.awt.dnd.DragSourceContext;
39import java.awt.dnd.DragSourceEvent;
40import java.awt.dnd.DragSourceDropEvent;
41import java.awt.dnd.DragSourceDragEvent;
42import java.awt.dnd.DragGestureEvent;
43import java.awt.dnd.InvalidDnDOperationException;
44
45import java.awt.dnd.peer.DragSourceContextPeer;
46
47import java.awt.event.InputEvent;
48import java.awt.event.MouseEvent;
49
50import java.util.Map;
51import java.util.SortedMap;
52
53import sun.awt.SunToolkit;
54import sun.awt.datatransfer.DataTransferer;
55
56/**
57 * <p>
58 * TBC
59 * </p>
60 *
61 * @since JDK1.3.1
62 *
63 */
64
65public abstract class SunDragSourceContextPeer implements DragSourceContextPeer {
66
67 private DragGestureEvent trigger;
68 private Component component;
69 private Cursor cursor;
70 private long nativeCtxt;
71 private DragSourceContext dragSourceContext;
72 private int sourceActions;
73
74 private static boolean dragDropInProgress = false;
75 private static boolean discardingMouseEvents = false;
76
77 /*
78 * dispatch constants
79 */
80
81 protected final static int DISPATCH_ENTER = 1;
82 protected final static int DISPATCH_MOTION = 2;
83 protected final static int DISPATCH_CHANGED = 3;
84 protected final static int DISPATCH_EXIT = 4;
85 protected final static int DISPATCH_FINISH = 5;
86 protected final static int DISPATCH_MOUSE_MOVED = 6;
87
88 /**
89 * construct a new SunDragSourceContextPeer
90 */
91
92 public SunDragSourceContextPeer(DragGestureEvent dge) {
93 trigger = dge;
94 if (trigger != null) {
95 component = trigger.getComponent();
96 } else {
97 component = null;
98 }
99 }
100
101 /**
102 * Synchro messages in AWT
103 */
104 public void startSecondaryEventLoop(){}
105 public void quitSecondaryEventLoop(){}
106
107 /**
108 * initiate a DnD operation ...
109 */
110
111 public void startDrag(DragSourceContext dsc, Cursor c, Image di, Point p)
112 throws InvalidDnDOperationException {
113
114 /* Fix for 4354044: don't initiate a drag if event sequence provided by
115 * DragGestureRecognizer is empty */
116 if (getTrigger().getTriggerEvent() == null) {
117 throw new InvalidDnDOperationException("DragGestureEvent has a null trigger");
118 }
119
120 dragSourceContext = dsc;
121 cursor = c;
122 sourceActions = getDragSourceContext().getSourceActions();
123
124 Transferable transferable = getDragSourceContext().getTransferable();
125 SortedMap formatMap = DataTransferer.getInstance().getFormatsForTransferable
126 (transferable, DataTransferer.adaptFlavorMap
127 (getTrigger().getDragSource().getFlavorMap()));
128 long[] formats = DataTransferer.getInstance().
129 keysToLongArray(formatMap);
130 startDrag(transferable, formats, formatMap);
131
132 /*
133 * Fix for 4613903.
134 * Filter out all mouse events that are currently on the event queue.
135 */
136 discardingMouseEvents = true;
137 EventQueue.invokeLater(new Runnable() {
138 public void run() {
139 discardingMouseEvents = false;
140 }
141 });
142 }
143
144 protected abstract void startDrag(Transferable trans,
145 long[] formats, Map formatMap);
146
147 /**
148 * set cursor
149 */
150
151 public void setCursor(Cursor c) throws InvalidDnDOperationException {
152 synchronized (this) {
153 if (cursor == null || !cursor.equals(c)) {
154 cursor = c;
155 // NOTE: native context can be null at this point.
156 // setNativeCursor() should handle it properly.
157 setNativeCursor(getNativeContext(), c,
158 c != null ? c.getType() : 0);
159 }
160 }
161 }
162
163 /**
164 * return cursor
165 */
166
167 public Cursor getCursor() {
168 return cursor;
169 }
170
171 /**
172 * downcall into native code
173 */
174
175
176 protected abstract void setNativeCursor(long nativeCtxt, Cursor c,
177 int cType);
178
179 protected synchronized void setTrigger(DragGestureEvent dge) {
180 trigger = dge;
181 if (trigger != null) {
182 component = trigger.getComponent();
183 } else {
184 component = null;
185 }
186 }
187
188 protected DragGestureEvent getTrigger() {
189 return trigger;
190 }
191
192 protected Component getComponent() {
193 return component;
194 }
195
196 protected synchronized void setNativeContext(long ctxt) {
197 nativeCtxt = ctxt;
198 }
199
200 protected synchronized long getNativeContext() {
201 return nativeCtxt;
202 }
203
204 protected DragSourceContext getDragSourceContext() {
205 return dragSourceContext;
206 }
207
208 /**
209 * Notify the peer that the transferables' DataFlavors have changed.
210 *
211 * No longer useful as the transferables are determined at the time
212 * of the drag.
213 */
214
215 public void transferablesFlavorsChanged() {
216 }
217
218
219
220
221
222 protected final void postDragSourceDragEvent(final int targetAction,
223 final int modifiers,
224 final int x, final int y,
225 final int dispatchType) {
226
227 final int dropAction =
228 SunDragSourceContextPeer.convertModifiersToDropAction(modifiers,
229 sourceActions);
230
231 DragSourceDragEvent event =
232 new DragSourceDragEvent(getDragSourceContext(),
233 dropAction,
234 targetAction & sourceActions,
235 modifiers, x, y);
236 EventDispatcher dispatcher = new EventDispatcher(dispatchType, event);
237
238 SunToolkit.invokeLaterOnAppContext(
239 SunToolkit.targetToAppContext(getComponent()), dispatcher);
240
241 startSecondaryEventLoop();
242 }
243
244 /**
245 * upcall from native code
246 */
247
248 private void dragEnter(final int targetActions,
249 final int modifiers,
250 final int x, final int y) {
251 postDragSourceDragEvent(targetActions, modifiers, x, y, DISPATCH_ENTER);
252 }
253
254 /**
255 * upcall from native code
256 */
257
258 private void dragMotion(final int targetActions,
259 final int modifiers,
260 final int x, final int y) {
261 postDragSourceDragEvent(targetActions, modifiers, x, y, DISPATCH_MOTION);
262 }
263
264 /**
265 * upcall from native code
266 */
267
268 private void operationChanged(final int targetActions,
269 final int modifiers,
270 final int x, final int y) {
271 postDragSourceDragEvent(targetActions, modifiers, x, y, DISPATCH_CHANGED);
272 }
273
274 /**
275 * upcall from native code
276 */
277
278 protected final void dragExit(final int x, final int y) {
279 DragSourceEvent event =
280 new DragSourceEvent(getDragSourceContext(), x, y);
281 EventDispatcher dispatcher =
282 new EventDispatcher(DISPATCH_EXIT, event);
283
284 SunToolkit.invokeLaterOnAppContext(
285 SunToolkit.targetToAppContext(getComponent()), dispatcher);
286
287 startSecondaryEventLoop();
288 }
289
290 /**
291 * upcall from native code
292 */
293
294 private void dragMouseMoved(final int targetActions,
295 final int modifiers,
296 final int x, final int y) {
297 postDragSourceDragEvent(targetActions, modifiers, x, y,
298 DISPATCH_MOUSE_MOVED);
299 }
300
301 /**
302 * upcall from native code via implemented class (do)
303 */
304
305 protected final void dragDropFinished(final boolean success,
306 final int operations,
307 final int x, final int y) {
308 DragSourceEvent event =
309 new DragSourceDropEvent(getDragSourceContext(),
310 operations & sourceActions,
311 success, x, y);
312 EventDispatcher dispatcher =
313 new EventDispatcher(DISPATCH_FINISH, event);
314
315 SunToolkit.invokeLaterOnAppContext(
316 SunToolkit.targetToAppContext(getComponent()), dispatcher);
317
318 startSecondaryEventLoop();
319 setNativeContext(0);
320 }
321
322 public static void setDragDropInProgress(boolean b)
323 throws InvalidDnDOperationException {
324 if (dragDropInProgress == b) {
325 throw new InvalidDnDOperationException(getExceptionMessage(b));
326 }
327
328 synchronized (SunDragSourceContextPeer.class) {
329 if (dragDropInProgress == b) {
330 throw new InvalidDnDOperationException(getExceptionMessage(b));
331 }
332 dragDropInProgress = b;
333 }
334 }
335
336 /**
337 * Filters out all mouse events that were on the java event queue when
338 * startDrag was called.
339 */
340 public static boolean checkEvent(AWTEvent event) {
341 if (discardingMouseEvents && event instanceof MouseEvent) {
342 MouseEvent mouseEvent = (MouseEvent)event;
343 if (!(mouseEvent instanceof SunDropTargetEvent)) {
344 return false;
345 }
346 }
347 return true;
348 }
349
350 public static void checkDragDropInProgress()
351 throws InvalidDnDOperationException {
352 if (dragDropInProgress) {
353 throw new InvalidDnDOperationException(getExceptionMessage(true));
354 }
355 }
356
357 private static String getExceptionMessage(boolean b) {
358 return b ? "Drag and drop in progress" : "No drag in progress";
359 }
360
361 public static int convertModifiersToDropAction(final int modifiers,
362 final int supportedActions) {
363 int dropAction = DnDConstants.ACTION_NONE;
364
365 /*
366 * Fix for 4285634.
367 * Calculate the drop action to match Motif DnD behavior.
368 * If the user selects an operation (by pressing a modifier key),
369 * return the selected operation or ACTION_NONE if the selected
370 * operation is not supported by the drag source.
371 * If the user doesn't select an operation search the set of operations
372 * supported by the drag source for ACTION_MOVE, then for
373 * ACTION_COPY, then for ACTION_LINK and return the first operation
374 * found.
375 */
376 switch (modifiers & (InputEvent.SHIFT_DOWN_MASK |
377 InputEvent.CTRL_DOWN_MASK)) {
378 case InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK:
379 dropAction = DnDConstants.ACTION_LINK; break;
380 case InputEvent.CTRL_DOWN_MASK:
381 dropAction = DnDConstants.ACTION_COPY; break;
382 case InputEvent.SHIFT_DOWN_MASK:
383 dropAction = DnDConstants.ACTION_MOVE; break;
384 default:
385 if ((supportedActions & DnDConstants.ACTION_MOVE) != 0) {
386 dropAction = DnDConstants.ACTION_MOVE;
387 } else if ((supportedActions & DnDConstants.ACTION_COPY) != 0) {
388 dropAction = DnDConstants.ACTION_COPY;
389 } else if ((supportedActions & DnDConstants.ACTION_LINK) != 0) {
390 dropAction = DnDConstants.ACTION_LINK;
391 }
392 }
393
394 return dropAction & supportedActions;
395 }
396
397 private void cleanup() {
398 trigger = null;
399 component = null;
400 cursor = null;
401 dragSourceContext = null;
402 SunDropTargetContextPeer.setCurrentJVMLocalSourceTransferable(null);
403 SunDragSourceContextPeer.setDragDropInProgress(false);
404 }
405
406 private class EventDispatcher implements Runnable {
407
408 private final int dispatchType;
409
410 private final DragSourceEvent event;
411
412 EventDispatcher(int dispatchType, DragSourceEvent event) {
413 switch (dispatchType) {
414 case DISPATCH_ENTER:
415 case DISPATCH_MOTION:
416 case DISPATCH_CHANGED:
417 case DISPATCH_MOUSE_MOVED:
418 if (!(event instanceof DragSourceDragEvent)) {
419 throw new IllegalArgumentException("Event: " + event);
420 }
421 break;
422 case DISPATCH_EXIT:
423 break;
424 case DISPATCH_FINISH:
425 if (!(event instanceof DragSourceDropEvent)) {
426 throw new IllegalArgumentException("Event: " + event);
427 }
428 break;
429 default:
430 throw new IllegalArgumentException("Dispatch type: " +
431 dispatchType);
432 }
433
434 this.dispatchType = dispatchType;
435 this.event = event;
436 }
437
438 public void run() {
439 DragSourceContext dragSourceContext =
440 SunDragSourceContextPeer.this.getDragSourceContext();
441 try {
442 switch (dispatchType) {
443 case DISPATCH_ENTER:
444 dragSourceContext.dragEnter((DragSourceDragEvent)event);
445 break;
446 case DISPATCH_MOTION:
447 dragSourceContext.dragOver((DragSourceDragEvent)event);
448 break;
449 case DISPATCH_CHANGED:
450 dragSourceContext.dropActionChanged((DragSourceDragEvent)event);
451 break;
452 case DISPATCH_EXIT:
453 dragSourceContext.dragExit(event);
454 break;
455 case DISPATCH_MOUSE_MOVED:
456 dragSourceContext.dragMouseMoved((DragSourceDragEvent)event);
457 break;
458 case DISPATCH_FINISH:
459 try {
460 dragSourceContext.dragDropEnd((DragSourceDropEvent)event);
461 } finally {
462 SunDragSourceContextPeer.this.cleanup();
463 }
464 break;
465 default:
466 throw new IllegalStateException("Dispatch type: " +
467 dispatchType);
468 }
469 } finally {
470 SunDragSourceContextPeer.this.quitSecondaryEventLoop();
471 }
472 }
473 }
474}