< prev index next >

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

Print this page




  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 


 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() {


 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         }


 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 


 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(); }


 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;




  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 jdk.swing.interop.LightweightFrameWrapper;
  61 import jdk.swing.interop.SwingInterOpUtils;
  62 import jdk.swing.interop.DragSourceContextWrapper;
  63 import jdk.swing.interop.DropTargetContextWrapper;
  64 
  65 /**
  66  * A utility class to connect DnD mechanism of Swing and FX.
  67  * It allows Swing content to use the FX machinery for performing DnD.
  68  */
  69 final class FXDnD {
  70     private final SwingNode node;
  71     private static boolean fxAppThreadIsDispatchThread;
  72     private SwingNode getNode() { return node; }
  73 
  74     static {
  75         AccessController.doPrivileged(new PrivilegedAction<Object>() {
  76             public Object run() {
  77                 fxAppThreadIsDispatchThread =
  78                         "true".equals(System.getProperty("javafx.embed.singleThread"));
  79                 return null;
  80             }
  81         });
  82     }
  83 
  84     FXDnD(SwingNode node) {
  85         this.node = node;
  86     }
  87 
  88     /**
  89      * Utility class that operates on Maps with Components as keys.
  90      * Useful when processing mouse events to choose an object from the map
  91      * based on the component located at the given coordinates.
  92      */
  93     private class ComponentMapper<T> {
  94         private int x, y;
  95         private T object = null;
  96 
  97         private ComponentMapper(Map<Component, T> map, int xArg, int yArg) {
  98             this.x = xArg;
  99             this.y = yArg;
 100 
 101             final LightweightFrameWrapper lwFrame = node.getLightweightFrame();
 102             Component c = lwFrame.findComponentAt(lwFrame, x, y, false);

 103             if (c == null) return;
 104 
 105             synchronized (c.getTreeLock()) {
 106                 do {
 107                     object = map.get(c);
 108                 } while (object == null && (c = c.getParent()) != null);
 109 
 110                 if (object != null) {
 111                     // The object is either a DropTarget or a DragSource, so:
 112                     //assert c == object.getComponent();
 113 
 114                     // Translate x, y from lwFrame to component coordinates
 115                     while ((lwFrame.isCompEqual(c,lwFrame)) && c != null) {
 116                         x -= c.getX();
 117                         y -= c.getY();
 118                         c = c.getParent();
 119                     }
 120                 }
 121             }
 122         }
 123     }
 124     public <T> ComponentMapper<T> mapComponent(Map<Component, T> map, int x, int y) {
 125         return new ComponentMapper<T>(map, x, y);
 126     }
 127 
 128 
 129 
 130 
 131 
 132     ///////////////////////////////////////////////////////////////////////////
 133     //     DRAG SOURCE IMPLEMENTATION
 134     ///////////////////////////////////////////////////////////////////////////
 135 


 178         protected void unregisterListeners() {
 179             SwingFXUtils.runOnFxThread(() -> {
 180                 if (isDragSourceListenerInstalled) {
 181                     node.removeEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressHandler);
 182                     node.removeEventHandler(MouseEvent.DRAG_DETECTED, onDragStartHandler);
 183                     node.removeEventHandler(DragEvent.DRAG_DONE, onDragDoneHandler);
 184 
 185                     isDragSourceListenerInstalled = false;
 186                 }
 187             });
 188         }
 189 
 190         private void fireEvent(int x, int y, long evTime, int modifiers) {
 191             // In theory we should register all the events that trigger the gesture (like PRESS, DRAG, DRAG, BINGO!)
 192             // But we can live with this hack for now.
 193             appendEvent(new java.awt.event.MouseEvent(getComponent(), java.awt.event.MouseEvent.MOUSE_PRESSED,
 194                         evTime, modifiers, x, y, 0, false));
 195 
 196             // Also, the modifiers here should've actually come from the last known mouse event (last MOVE or DRAG).
 197             // But we're OK with using the initial PRESS modifiers for now
 198             int initialAction = DragSourceContextWrapper.convertModifiersToDropAction(
 199                     modifiers, getSourceActions());
 200 
 201             fireDragGestureRecognized(initialAction, new java.awt.Point(x, y));
 202         }
 203     }
 204 
 205     // Invoked on EDT
 206     private void fireEvent(int x, int y, long evTime, int modifiers) {
 207         ComponentMapper<FXDragGestureRecognizer> mapper = mapComponent(recognizers, x, y);
 208 
 209         final FXDragGestureRecognizer r = mapper.object;
 210         if (r != null) {
 211             r.fireEvent(mapper.x, mapper.y, evTime, modifiers);
 212         } else {
 213             // No recognizer, no DnD, no startDrag, so release the FX loop now
 214             SwingFXUtils.leaveFXNestedLoop(FXDnD.this);
 215         }
 216     }
 217 
 218     private MouseEvent getInitialGestureEvent() {


 262         }
 263     };
 264 
 265     private final EventHandler<DragEvent> onDragDoneHandler = (event) -> {
 266         event.consume();
 267 
 268         // Release FXDragSourceContextPeer.startDrag()
 269         if (!fxAppThreadIsDispatchThread) {
 270             loop.exit();
 271         }
 272 
 273         if (activeDSContextPeer != null) {
 274             final TransferMode mode = event.getTransferMode();
 275             activeDSContextPeer.dragDone(
 276                     mode == null ? 0 : SwingDnD.transferModeToDropAction(mode),
 277                     (int)event.getX(), (int)event.getY());
 278         }
 279     };
 280 
 281 
 282     private final class FXDragSourceContextPeer extends DragSourceContextWrapper {
 283         private volatile int sourceActions = 0;
 284 
 285         private final CachingTransferable transferable = new CachingTransferable();
 286 
 287         @Override public void startSecondaryEventLoop(){
 288             Toolkit.getToolkit().enterNestedEventLoop(this);
 289         }
 290         @Override public void quitSecondaryEventLoop(){
 291             assert !Platform.isFxApplicationThread();
 292             Platform.runLater(() -> Toolkit.getToolkit().exitNestedEventLoop(FXDragSourceContextPeer.this, null));
 293         }
 294 
 295         @Override protected void setNativeCursor(long nativeCtxt, Cursor c, int cType) {
 296             //TODO
 297         }
 298 
 299 
 300         private void dragDone(int operation, int x, int y) {
 301             dragDropFinished(operation != 0, operation, x, y);
 302         }


 318             // StringReader as data, etc.) So instead we perform our internal
 319             // translation.
 320             // Note that fetchData == true. FX doesn't support delayed data
 321             // callbacks yet anyway, so we have to fetch all the data from AWT upfront.
 322             transferable.updateData(trans, true);
 323 
 324             sourceActions = getDragSourceContext().getSourceActions();
 325 
 326             // Release the FX nested loop to allow onDragDetected to start the actual DnD operation,
 327             // and then start an AWT nested loop to wait until DnD finishes.
 328             if (!fxAppThreadIsDispatchThread) {
 329                 loop = java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue().createSecondaryLoop();
 330                 SwingFXUtils.leaveFXNestedLoop(FXDnD.this);
 331                 if (!loop.enter()) {
 332                     // An error occured, but there's little we can do here...
 333                 }
 334             }
 335         }
 336     };
 337 
 338     //@Override
 339     public <T extends DragGestureRecognizer> T createDragGestureRecognizer(
 340             Class<T> abstractRecognizerClass,
 341             DragSource ds, Component c, int srcActions,
 342             DragGestureListener dgl)
 343     {
 344         return (T) new FXDragGestureRecognizer(ds, c, srcActions, dgl);
 345     }
 346 
 347     //@Override
 348     public DragSourceContextWrapper 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 


 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 extends DropTargetContextWrapper {
 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(); }


 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                         DropTargetContextWrapper.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                         DropTargetContextWrapper.setDropTargetContextPeer(ctx, 
 483                                          new FXDropTargetContextPeer());
 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;


< prev index next >