< prev index next >

modules/javafx.swing/src/main/java/com/sun/javafx/embed/swing/FXDnD.java

Print this page




   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.embed.swing;
  27 
  28 import com.sun.javafx.tk.Toolkit;
  29 import java.awt.Component;
  30 import java.awt.Cursor;
  31 import java.awt.Point;
  32 import java.awt.SecondaryLoop;
  33 import java.awt.datatransfer.DataFlavor;
  34 import java.awt.datatransfer.Transferable;
  35 import java.awt.dnd.DnDConstants;
  36 import java.awt.dnd.DragGestureEvent;
  37 import java.awt.dnd.DragGestureListener;
  38 import java.awt.dnd.DragGestureRecognizer;
  39 import java.awt.dnd.DragSource;
  40 import java.awt.dnd.DropTarget;
  41 import java.awt.dnd.DropTargetContext;
  42 import java.awt.dnd.DropTargetDragEvent;
  43 import java.awt.dnd.DropTargetDropEvent;
  44 import java.awt.dnd.DropTargetListener;
  45 import java.awt.dnd.InvalidDnDOperationException;
  46 import java.awt.dnd.MouseDragGestureRecognizer;
  47 import java.awt.dnd.peer.DragSourceContextPeer;
  48 import java.awt.dnd.peer.DropTargetContextPeer;
  49 import java.security.AccessController;
  50 import java.security.PrivilegedAction;
  51 import java.util.HashMap;
  52 import java.util.Map;
  53 import javafx.application.Platform;
  54 import javafx.event.EventHandler;
  55 import javafx.event.EventType;
  56 import javafx.scene.input.DataFormat;
  57 import javafx.scene.input.DragEvent;
  58 import javafx.scene.input.Dragboard;
  59 import javafx.scene.input.MouseEvent;
  60 import javafx.scene.input.TransferMode;
  61 import sun.awt.AWTAccessor;
  62 import sun.awt.dnd.SunDragSourceContextPeer;
  63 import sun.swing.JLightweightFrame;
  64 

  65 
  66 /**
  67  * A utility class to connect DnD mechanism of Swing and FX.
  68  * It allows Swing content to use the FX machinery for performing DnD.
  69  */
  70 final class FXDnD {
  71     private final SwingNode node;
  72     private static boolean fxAppThreadIsDispatchThread;
  73     private SwingNode getNode() { return node; }

  74 
  75     static {
  76         AccessController.doPrivileged(new PrivilegedAction<Object>() {
  77             public Object run() {
  78                 fxAppThreadIsDispatchThread =
  79                         "true".equals(System.getProperty("javafx.embed.singleThread"));
  80                 return null;
  81             }
  82         });
  83     }
  84 
  85     FXDnD(SwingNode node) {
  86         this.node = node;
  87     }
  88 
  89     /**
  90      * Utility class that operates on Maps with Components as keys.
  91      * Useful when processing mouse events to choose an object from the map
  92      * based on the component located at the given coordinates.
  93      */
  94     private class ComponentMapper<T> {
  95         private int x, y;
  96         private T object = null;
  97 
  98         private ComponentMapper(Map<Component, T> map, int xArg, int yArg) {
  99             this.x = xArg;
 100             this.y = yArg;
 101 
 102             final JLightweightFrame lwFrame = node.getLightweightFrame();
 103             Component c = AWTAccessor.getContainerAccessor().findComponentAt(
 104                     lwFrame, x, y, false);
 105             if (c == null) return;
 106 
 107             synchronized (c.getTreeLock()) {
 108                 do {
 109                     object = map.get(c);
 110                 } while (object == null && (c = c.getParent()) != null);
 111 
 112                 if (object != null) {
 113                     // The object is either a DropTarget or a DragSource, so:
 114                     //assert c == object.getComponent();
 115 
 116                     // Translate x, y from lwFrame to component coordinates
 117                     while (c != lwFrame && c != null) {
 118                         x -= c.getX();
 119                         y -= c.getY();
 120                         c = c.getParent();
 121                     }
 122                 }
 123             }
 124         }
 125     }
 126     public <T> ComponentMapper<T> mapComponent(Map<Component, T> map, int x, int y) {
 127         return new ComponentMapper<T>(map, x, y);
 128     }
 129 
 130 
 131 
 132 
 133 
 134     ///////////////////////////////////////////////////////////////////////////
 135     //     DRAG SOURCE IMPLEMENTATION
 136     ///////////////////////////////////////////////////////////////////////////
 137 
 138 
 139     private boolean isDragSourceListenerInstalled = false;
 140 
 141     // To keep track of where the DnD gesture actually started
 142     private MouseEvent pressEvent = null;
 143     private long pressTime = 0;
 144 
 145     private volatile SecondaryLoop loop;
 146 
 147     private final Map<Component, FXDragGestureRecognizer> recognizers = new HashMap<>();
 148 
 149     // Note that we don't really use the MouseDragGestureRecognizer facilities,
 150     // however some code in JDK may expect a descendant of this class rather
 151     // than a generic DragGestureRecognizer. So we inherit from it.
 152     private class FXDragGestureRecognizer extends MouseDragGestureRecognizer {
 153         FXDragGestureRecognizer(DragSource ds, Component c, int srcActions,
 154             DragGestureListener dgl)
 155         {
 156             super(ds, c, srcActions, dgl);
 157 
 158             if (c != null) recognizers.put(c, this);
 159         }
 160 
 161         @Override public void setComponent(Component c) {
 162             final Component old = getComponent();
 163             if (old != null) recognizers.remove(old);
 164             super.setComponent(c);
 165             if (c != null) recognizers.put(c, this);
 166         }
 167 
 168         protected void registerListeners() {
 169             SwingFXUtils.runOnFxThread(() -> {
 170                 if (!isDragSourceListenerInstalled) {
 171                     node.addEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressHandler);
 172                     node.addEventHandler(MouseEvent.DRAG_DETECTED, onDragStartHandler);
 173                     node.addEventHandler(DragEvent.DRAG_DONE, onDragDoneHandler);
 174 
 175                     isDragSourceListenerInstalled = true;
 176                 }
 177             });
 178         }
 179 
 180         protected void unregisterListeners() {
 181             SwingFXUtils.runOnFxThread(() -> {
 182                 if (isDragSourceListenerInstalled) {
 183                     node.removeEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressHandler);
 184                     node.removeEventHandler(MouseEvent.DRAG_DETECTED, onDragStartHandler);
 185                     node.removeEventHandler(DragEvent.DRAG_DONE, onDragDoneHandler);
 186 
 187                     isDragSourceListenerInstalled = false;
 188                 }
 189             });
 190         }
 191 
 192         private void fireEvent(int x, int y, long evTime, int modifiers) {
 193             // In theory we should register all the events that trigger the gesture (like PRESS, DRAG, DRAG, BINGO!)
 194             // But we can live with this hack for now.
 195             appendEvent(new java.awt.event.MouseEvent(getComponent(), java.awt.event.MouseEvent.MOUSE_PRESSED,
 196                         evTime, modifiers, x, y, 0, false));
 197 
 198             // Also, the modifiers here should've actually come from the last known mouse event (last MOVE or DRAG).
 199             // But we're OK with using the initial PRESS modifiers for now
 200             int initialAction = SunDragSourceContextPeer.convertModifiersToDropAction(
 201                     modifiers, getSourceActions());
 202 
 203             fireDragGestureRecognized(initialAction, new java.awt.Point(x, y));
 204         }
 205     }
 206 
 207     // Invoked on EDT
 208     private void fireEvent(int x, int y, long evTime, int modifiers) {
 209         ComponentMapper<FXDragGestureRecognizer> mapper = mapComponent(recognizers, x, y);
 210 
 211         final FXDragGestureRecognizer r = mapper.object;
 212         if (r != null) {
 213             r.fireEvent(mapper.x, mapper.y, evTime, modifiers);
 214         } else {
 215             // No recognizer, no DnD, no startDrag, so release the FX loop now
 216             SwingFXUtils.leaveFXNestedLoop(FXDnD.this);
 217         }
 218     }
 219 
 220     private MouseEvent getInitialGestureEvent() {
 221         return pressEvent;
 222     }
 223 
 224     private final EventHandler<MouseEvent> onMousePressHandler = (event) -> {
 225         // It would be nice to maintain a list of all the events that initiate
 226         // a DnD gesture (see a comment in FXDragGestureRecognizer.fireEvent().
 227         // For now, we simply use the initial PRESS event for this purpose.
 228         pressEvent = event;
 229         pressTime = System.currentTimeMillis();
 230     };
 231 
 232 
 233     private volatile FXDragSourceContextPeer activeDSContextPeer;
 234 
 235     private final EventHandler<MouseEvent> onDragStartHandler = (event) -> {
 236         // Call to AWT and determine the active DragSourceContextPeer
 237         activeDSContextPeer = null;
 238         final MouseEvent firstEv = getInitialGestureEvent();
 239         SwingFXUtils.runOnEDTAndWait(FXDnD.this, () -> fireEvent(
 240                     (int)firstEv.getX(), (int)firstEv.getY(), pressTime,
 241                     SwingEvents.fxMouseModsToMouseMods(firstEv)));
 242         if (activeDSContextPeer == null) return;
 243 
 244         // Since we're going to start DnD, consume the event.
 245         event.consume();
 246 
 247         Dragboard db = getNode().startDragAndDrop(SwingDnD.dropActionsToTransferModes(
 248                     activeDSContextPeer.sourceActions).toArray(new TransferMode[1]));
 249 
 250         // At this point the activeDSContextPeer.transferable contains all the data from AWT
 251         Map<DataFormat, Object> fxData = new HashMap<>();
 252         for (String mt : activeDSContextPeer.transferable.getMimeTypes()) {
 253             DataFormat f = DataFormat.lookupMimeType(mt);
 254             //TODO: what to do if f == null?
 255             if (f != null) fxData.put(f, activeDSContextPeer.transferable.getData(mt));
 256         }
 257 
 258         final boolean hasContent = db.setContent(fxData);
 259         if (!hasContent) {
 260             // No data, no DnD, no onDragDoneHandler, so release the AWT loop now
 261             if (!fxAppThreadIsDispatchThread) {
 262                 loop.exit();
 263             }
 264         }
 265     };
 266 
 267     private final EventHandler<DragEvent> onDragDoneHandler = (event) -> {
 268         event.consume();
 269 
 270         // Release FXDragSourceContextPeer.startDrag()
 271         if (!fxAppThreadIsDispatchThread) {
 272             loop.exit();
 273         }
 274 
 275         if (activeDSContextPeer != null) {
 276             final TransferMode mode = event.getTransferMode();
 277             activeDSContextPeer.dragDone(
 278                     mode == null ? 0 : SwingDnD.transferModeToDropAction(mode),
 279                     (int)event.getX(), (int)event.getY());
 280         }
 281     };
 282 
 283 
 284     private final class FXDragSourceContextPeer extends SunDragSourceContextPeer {
 285         private volatile int sourceActions = 0;
 286 
 287         private final CachingTransferable transferable = new CachingTransferable();
 288 
 289         @Override public void startSecondaryEventLoop(){
 290             Toolkit.getToolkit().enterNestedEventLoop(this);
 291         }
 292         @Override public void quitSecondaryEventLoop(){
 293             assert !Platform.isFxApplicationThread();
 294             Platform.runLater(() -> Toolkit.getToolkit().exitNestedEventLoop(FXDragSourceContextPeer.this, null));
 295         }
 296 
 297         @Override protected void setNativeCursor(long nativeCtxt, Cursor c, int cType) {
 298             //TODO
 299         }
 300 
 301 
 302         private void dragDone(int operation, int x, int y) {
 303             dragDropFinished(operation != 0, operation, x, y);
 304         }
 305 
 306         FXDragSourceContextPeer(DragGestureEvent dge) {
 307             super(dge);

 308         }
 309 
 310 
 311         // It's Map<Long, DataFlavor> actually, but javac complains if the type isn't erased...
 312         @Override protected void startDrag(Transferable trans, long[] formats, Map formatMap)
 313         {
 314             activeDSContextPeer = this;
 315 
 316             // NOTE: we ignore the formats[] and the formatMap altogether.
 317             // AWT provides those to allow for more flexible representations of
 318             // e.g. text data (in various formats, encodings, etc.) However, FX
 319             // code isn't ready to handle those (e.g. it can't digest a
 320             // StringReader as data, etc.) So instead we perform our internal
 321             // translation.
 322             // Note that fetchData == true. FX doesn't support delayed data
 323             // callbacks yet anyway, so we have to fetch all the data from AWT upfront.
 324             transferable.updateData(trans, true);
 325 
 326             sourceActions = getDragSourceContext().getSourceActions();
 327 
 328             // Release the FX nested loop to allow onDragDetected to start the actual DnD operation,
 329             // and then start an AWT nested loop to wait until DnD finishes.
 330             if (!fxAppThreadIsDispatchThread) {
 331                 loop = java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue().createSecondaryLoop();
 332                 SwingFXUtils.leaveFXNestedLoop(FXDnD.this);
 333                 if (!loop.enter()) {
 334                     // An error occured, but there's little we can do here...
 335                 }
 336             }
 337         }
 338     };
 339 
 340     public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
 341             Class<T> abstractRecognizerClass,
 342             DragSource ds, Component c, int srcActions,
 343             DragGestureListener dgl)
 344     {
 345         return (T) new FXDragGestureRecognizer(ds, c, srcActions, dgl);
 346     }
 347 
 348     public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException
 349     {
 350         return new FXDragSourceContextPeer(dge);
 351     }
 352 
 353 
 354 
 355 
 356 
 357     ///////////////////////////////////////////////////////////////////////////
 358     //     DROP TARGET IMPLEMENTATION
 359     ///////////////////////////////////////////////////////////////////////////
 360 
 361 
 362     private boolean isDropTargetListenerInstalled = false;
 363     private volatile FXDropTargetContextPeer activeDTContextPeer = null;
 364     private final Map<Component, DropTarget> dropTargets = new HashMap<>();
 365 
 366     private final EventHandler<DragEvent> onDragEnteredHandler = (event) -> {
 367         if (activeDTContextPeer == null) activeDTContextPeer = new FXDropTargetContextPeer();
 368 
 369         int action = activeDTContextPeer.postDropTargetEvent(event);
 370 
 371         // If AWT doesn't accept anything, let parent nodes handle the event
 372         if (action != 0) event.consume();
 373     };
 374 
 375     private final EventHandler<DragEvent> onDragExitedHandler = (event) -> {
 376         if (activeDTContextPeer == null) activeDTContextPeer = new FXDropTargetContextPeer();
 377 
 378         activeDTContextPeer.postDropTargetEvent(event);
 379 
 380         activeDTContextPeer = null;
 381     };
 382 
 383     private final EventHandler<DragEvent> onDragOverHandler = (event) -> {
 384         if (activeDTContextPeer == null) activeDTContextPeer = new FXDropTargetContextPeer();
 385 
 386         int action = activeDTContextPeer.postDropTargetEvent(event);
 387 
 388         // If AWT doesn't accept anything, let parent nodes handle the event
 389         if (action != 0) {
 390             // NOTE: in FX the acceptTransferModes() may ONLY be called from DRAG_OVER.
 391             // If the AWT app always reports NONE and suddenly decides to accept the
 392             // data in its DRAG_DROPPED handler, this just won't work. There's no way
 393             // to workaround this other than by modifing the AWT application code.
 394             event.acceptTransferModes(SwingDnD.dropActionsToTransferModes(action).toArray(new TransferMode[1]));
 395             event.consume();
 396         }
 397     };
 398 
 399     private final EventHandler<DragEvent> onDragDroppedHandler = (event) -> {
 400         if (activeDTContextPeer == null) activeDTContextPeer = new FXDropTargetContextPeer();
 401 
 402         int action = activeDTContextPeer.postDropTargetEvent(event);
 403 
 404         if (action != 0) {
 405             // NOTE: the dropAction is ignored since we use the action last
 406             // reported from the DRAG_OVER handler.
 407             //
 408             // We might want to:
 409             //
 410             //    assert activeDTContextPeer.dropAction == onDragDroppedHandler.currentAction;
 411             //
 412             // and maybe print a diagnostic message if they differ.
 413             event.setDropCompleted(activeDTContextPeer.success);
 414 
 415             event.consume();
 416         }
 417 
 418         activeDTContextPeer = null;
 419     };
 420 
 421     private final class FXDropTargetContextPeer implements DropTargetContextPeer {
 422 
 423         private int targetActions = DnDConstants.ACTION_NONE;
 424         private int currentAction = DnDConstants.ACTION_NONE;
 425         private DropTarget dt = null;
 426         private DropTargetContext ctx = null;
 427 
 428         private final CachingTransferable transferable = new CachingTransferable();
 429 
 430         // Drop result
 431         private boolean success = false;
 432         private int dropAction = 0;
 433 
 434         @Override public synchronized void setTargetActions(int actions) { targetActions = actions; }
 435         @Override public synchronized int getTargetActions() { return targetActions; }
 436 
 437         @Override public synchronized DropTarget getDropTarget() { return dt; }
 438 
 439         @Override public synchronized boolean isTransferableJVMLocal() { return false; }
 440 
 441         @Override public synchronized DataFlavor[] getTransferDataFlavors() { return transferable.getTransferDataFlavors(); }
 442         @Override public synchronized Transferable getTransferable() { return transferable; }
 443 
 444         @Override public synchronized void acceptDrag(int dragAction) { currentAction = dragAction; }
 445         @Override public synchronized void rejectDrag() { currentAction = DnDConstants.ACTION_NONE; }
 446 
 447         @Override public synchronized void acceptDrop(int dropAction) { this.dropAction = dropAction; }
 448         @Override public synchronized void rejectDrop() { dropAction = DnDConstants.ACTION_NONE; }
 449 
 450         @Override public synchronized void dropComplete(boolean success) { this.success = success; }
 451 
 452 
 453         private int postDropTargetEvent(DragEvent event)
 454         {
 455             ComponentMapper<DropTarget> mapper = mapComponent(dropTargets, (int)event.getX(), (int)event.getY());
 456 
 457             final EventType<?> fxEvType = event.getEventType();
 458 
 459             Dragboard db = event.getDragboard();
 460             transferable.updateData(db, DragEvent.DRAG_DROPPED.equals(fxEvType));
 461 
 462             final int sourceActions = SwingDnD.transferModesToDropActions(db.getTransferModes());
 463             final int userAction = event.getTransferMode() == null ? DnDConstants.ACTION_NONE
 464                 : SwingDnD.transferModeToDropAction(event.getTransferMode());
 465 
 466             // A target for the AWT DnD event
 467             DropTarget target = mapper.object != null ? mapper.object : dt;
 468 
 469             SwingFXUtils.runOnEDTAndWait(FXDnD.this, () -> {
 470                 if (target != dt) {
 471                     if (ctx != null) {
 472                         AWTAccessor.getDropTargetContextAccessor().reset(ctx);
 473                     }
 474                     ctx = null;
 475 
 476                     currentAction = dropAction = DnDConstants.ACTION_NONE;
 477                 }
 478 
 479                 if (target != null) {
 480                     if (ctx == null) {
 481                         ctx = target.getDropTargetContext();
 482                         AWTAccessor.getDropTargetContextAccessor()
 483                                 .setDropTargetContextPeer(ctx, FXDropTargetContextPeer.this);
 484                     }
 485 
 486                     DropTargetListener dtl = (DropTargetListener)target;
 487 
 488                     if (DragEvent.DRAG_DROPPED.equals(fxEvType)) {
 489                         DropTargetDropEvent awtEvent = new DropTargetDropEvent(
 490                             ctx, new Point(mapper.x, mapper.y), userAction, sourceActions);
 491 
 492                         dtl.drop(awtEvent);
 493                     } else {
 494                         DropTargetDragEvent awtEvent = new DropTargetDragEvent(
 495                             ctx, new Point(mapper.x, mapper.y), userAction, sourceActions);
 496 
 497                         if (DragEvent.DRAG_OVER.equals(fxEvType)) dtl.dragOver(awtEvent);
 498                         else if (DragEvent.DRAG_ENTERED.equals(fxEvType)) dtl.dragEnter(awtEvent);
 499                         else if (DragEvent.DRAG_EXITED.equals(fxEvType)) dtl.dragExit(awtEvent);
 500                     }
 501                 }
 502 
 503                 dt = mapper.object;
 504                 if (dt == null) {
 505                     // FIXME: once we switch to JDK 9 as the boot JDK
 506                     // we need to re-implement the following using
 507                     // available API.
 508                     /*
 509                     if (ctx != null) ctx.removeNotify();
 510                     */
 511                     ctx = null;
 512 
 513                     currentAction = dropAction = DnDConstants.ACTION_NONE;
 514                 }
 515                 if (DragEvent.DRAG_DROPPED.equals(fxEvType) || DragEvent.DRAG_EXITED.equals(fxEvType)) {
 516                     // This must be done to ensure that the data isn't being
 517                     // cached in AWT. Otherwise subsequent DnD operations will
 518                     // see the old data only.
 519                     // FIXME: once we switch to JDK 9 as the boot JDK
 520                     // we need to re-implement the following using
 521                     // available API.
 522                     /*
 523                     if (ctx != null) ctx.removeNotify();
 524                     */
 525                     ctx = null;
 526                 }
 527 
 528                 SwingFXUtils.leaveFXNestedLoop(FXDnD.this);
 529             });
 530 
 531             if (DragEvent.DRAG_DROPPED.equals(fxEvType)) return dropAction;
 532 
 533             return currentAction;
 534         }
 535     }
 536 
 537     public void addDropTarget(DropTarget dt) {
 538         dropTargets.put(dt.getComponent(), dt);
 539         Platform.runLater(() -> {
 540             if (!isDropTargetListenerInstalled) {
 541                 node.addEventHandler(DragEvent.DRAG_ENTERED, onDragEnteredHandler);
 542                 node.addEventHandler(DragEvent.DRAG_EXITED, onDragExitedHandler);
 543                 node.addEventHandler(DragEvent.DRAG_OVER, onDragOverHandler);
 544                 node.addEventHandler(DragEvent.DRAG_DROPPED, onDragDroppedHandler);
 545 
 546                 isDropTargetListenerInstalled = true;
 547             }
 548         });
 549     }
 550 
 551     public void removeDropTarget(DropTarget dt) {
 552         dropTargets.remove(dt.getComponent());
 553         Platform.runLater(() -> {
 554             if (isDropTargetListenerInstalled && dropTargets.isEmpty()) {
 555                 node.removeEventHandler(DragEvent.DRAG_ENTERED, onDragEnteredHandler);
 556                 node.removeEventHandler(DragEvent.DRAG_EXITED, onDragExitedHandler);
 557                 node.removeEventHandler(DragEvent.DRAG_OVER, onDragOverHandler);
 558                 node.removeEventHandler(DragEvent.DRAG_DROPPED, onDragDroppedHandler);
 559 
 560                 isDropTargetListenerInstalled = false;
 561             }
 562         });
 563     }
 564 }


   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.javafx.embed.swing;
  27 
  28 import com.sun.javafx.tk.Toolkit;
  29 import java.awt.Component;
  30 import java.awt.Cursor;
  31 import java.awt.Point;
  32 import java.awt.SecondaryLoop;
  33 import java.awt.datatransfer.DataFlavor;
  34 import java.awt.datatransfer.Transferable;
  35 import java.awt.dnd.DnDConstants;
  36 import java.awt.dnd.DragGestureEvent;
  37 import java.awt.dnd.DragGestureListener;
  38 import java.awt.dnd.DragGestureRecognizer;
  39 import java.awt.dnd.DragSource;
  40 import java.awt.dnd.DropTarget;
  41 import java.awt.dnd.DropTargetContext;
  42 import java.awt.dnd.DropTargetDragEvent;
  43 import java.awt.dnd.DropTargetDropEvent;
  44 import java.awt.dnd.DropTargetListener;
  45 import java.awt.dnd.InvalidDnDOperationException;
  46 import java.awt.dnd.MouseDragGestureRecognizer;


  47 import java.security.AccessController;
  48 import java.security.PrivilegedAction;
  49 import java.util.HashMap;
  50 import java.util.Map;
  51 import javafx.application.Platform;
  52 import javafx.event.EventHandler;
  53 import javafx.event.EventType;
  54 import javafx.scene.input.DataFormat;
  55 import javafx.scene.input.DragEvent;
  56 import javafx.scene.input.Dragboard;
  57 import javafx.scene.input.MouseEvent;
  58 import javafx.scene.input.TransferMode;



  59 
  60 import javafx.embed.swing.SwingNode;
  61 
  62 /**
  63  * A utility class to connect DnD mechanism of Swing and FX.
  64  * It allows Swing content to use the FX machinery for performing DnD.
  65  */
  66 final public class FXDnD {
  67     private static SwingNode node;
  68     public static boolean fxAppThreadIsDispatchThread;
  69     private SwingNode getNode() { return node; }
  70     private static FXDnDInterop fxdndiop;
  71 
  72     static {
  73         AccessController.doPrivileged(new PrivilegedAction<Object>() {
  74             public Object run() {
  75                 fxAppThreadIsDispatchThread =
  76                         "true".equals(System.getProperty("javafx.embed.singleThread"));
  77                 return null;
  78             }
  79         });














  80 
  81         InteropFactory instance = null;
  82         try {
  83             instance = InteropFactory.getInstance();
  84         } catch (Exception e) {
  85             throw new ExceptionInInitializerError(e);



















  86         }
  87         fxdndiop = instance.createFXDnDImpl();


































































  88     }
  89 
  90     public FXDnD(SwingNode node) {
  91         this.node = node;
  92         fxdndiop.setNode(node);













































































































  93     }
  94 
  95     public Object createDragSourceContext(DragGestureEvent dge) 
  96                     throws InvalidDnDOperationException {
  97         return fxdndiop.createDragSourceContext(dge);
  98     }
  99 






























 100     public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
 101             Class<T> abstractRecognizerClass,
 102             DragSource ds, Component c, int srcActions,
 103             DragGestureListener dgl)
 104     {
 105         return fxdndiop.createDragGestureRecognizer(ds, c, srcActions, dgl);





























































































































































































 106     }
 107 
 108     public void addDropTarget(DropTarget dt) {
 109         fxdndiop.addDropTarget(dt, node);










 110     }
 111 
 112     public void removeDropTarget(DropTarget dt) {
 113         fxdndiop.removeDropTarget(dt, node);










 114     }
 115 }
< prev index next >