< prev index next >

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

Print this page


   1 /*
   2  * Copyright (c) 2012, 2014, Oracle and/or its affiliates. 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.  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 java.io.UnsupportedEncodingException;
  29 
  30 import java.util.Collections;
  31 import java.util.ArrayList;
  32 import java.util.EnumSet;
  33 import java.util.Arrays;
  34 import java.util.List;
  35 import java.util.Set;
  36 
  37 import com.sun.javafx.embed.EmbeddedSceneDSInterface;
  38 import com.sun.javafx.embed.HostDragStartListener;
  39 import javafx.scene.input.TransferMode;
  40 
  41 import com.sun.javafx.embed.EmbeddedSceneInterface;
  42 import com.sun.javafx.embed.EmbeddedSceneDTInterface;
  43 import com.sun.javafx.tk.Toolkit;
  44 
  45 import javax.swing.JComponent;
  46 import javax.swing.SwingUtilities;


  55 import java.awt.dnd.DragSource;
  56 import java.awt.dnd.DragSourceAdapter;
  57 import java.awt.dnd.DragSourceListener;
  58 import java.awt.dnd.DragSourceDropEvent;
  59 import java.awt.dnd.DropTarget;
  60 import java.awt.dnd.DropTargetAdapter;
  61 import java.awt.dnd.DropTargetDragEvent;
  62 import java.awt.dnd.DropTargetDropEvent;
  63 import java.awt.dnd.DropTargetEvent;
  64 import java.awt.dnd.DropTargetListener;
  65 import java.awt.dnd.InvalidDnDOperationException;
  66 
  67 import java.awt.event.InputEvent;
  68 import java.awt.event.MouseAdapter;
  69 import java.awt.event.MouseEvent;
  70 
  71 /**
  72  * An utility class to connect DnD mechanism of Swing and FX.
  73  * It allows FX content to use the AWT machinery for performing DnD.
  74  */
  75 final class SwingDnD {
  76 
  77     private final Transferable dndTransferable = new DnDTransferable();
  78 
  79     private final DragSource dragSource;
  80     private final DragSourceListener dragSourceListener;
  81 
  82     // swingDragSource and fxDropTarget are used when DnD is initiated from
  83     // Swing or external process, i.e. this SwingDnD is used as a drop target
  84     private SwingDragSource swingDragSource;
  85     private EmbeddedSceneDTInterface fxDropTarget;
  86 
  87     // fxDragSource is used when DnD is initiated from FX, i.e. this
  88     // SwingDnD acts as a drag source
  89     private EmbeddedSceneDSInterface fxDragSource;
  90 
  91     private MouseEvent me;
  92 
  93     SwingDnD(final JComponent comp, final EmbeddedSceneInterface embeddedScene) {
  94 
  95         comp.addMouseListener(new MouseAdapter() {
  96             @Override
  97             public void mouseClicked(MouseEvent me) {
  98                 storeMouseEvent(me);
  99             }
 100             @Override
 101             public void mouseDragged(MouseEvent me) {
 102                 storeMouseEvent(me);
 103             }
 104             @Override
 105             public void mousePressed(MouseEvent me) {
 106                 storeMouseEvent(me);
 107             }
 108             @Override
 109             public void mouseReleased(MouseEvent me) {
 110                 storeMouseEvent(me);
 111             }
 112         });
 113 


 203                         applyDropResult(lastTransferMode, e);
 204                     } catch (InvalidDnDOperationException ignore) {
 205                         // This means the JDK doesn't contain a fix for 8029979 yet.
 206                         // DnD still works, but a drag source won't know about
 207                         // the actual drop result reported by the FX app from
 208                         // its drop() handler. It will use the dropResult from
 209                         // the last call to dragOver() instead.
 210                     }
 211                 } finally {
 212                     e.dropComplete(lastTransferMode != null);
 213                     endDnD();
 214                     lastTransferMode = null;
 215                 }
 216             }
 217         };
 218         comp.setDropTarget(new DropTarget(comp,
 219                 DnDConstants.ACTION_COPY | DnDConstants.ACTION_MOVE | DnDConstants.ACTION_LINK, dtl));
 220 
 221     }
 222 
 223     void addNotify() {
 224         dragSource.addDragSourceListener(dragSourceListener);
 225     }
 226 
 227     void removeNotify() {
 228         // RT-22049: Multi-JFrame/JFXPanel app leaks JFXPanels
 229         // Don't forget to unregister drag source listener!
 230         dragSource.removeDragSourceListener(dragSourceListener);
 231     }
 232 
 233     HostDragStartListener getDragStartListener() {
 234         return (dragSource, dragAction) -> {
 235             assert Toolkit.getToolkit().isFxUserThread();
 236             assert dragSource != null;
 237 
 238             // The method is called from FX Scene just before entering
 239             // nested event loop servicing DnD events.
 240             // It should initialize DnD in AWT EDT.
 241             SwingUtilities.invokeLater(() -> {
 242                 assert fxDragSource == null;
 243                 assert swingDragSource == null;
 244                 assert fxDropTarget == null;
 245 
 246                 fxDragSource = dragSource;
 247                 startDrag(me, dndTransferable, dragSource.
 248                         getSupportedActions(), dragAction);
 249             });
 250         };
 251     }
 252 
 253     private void startDrag(final MouseEvent e, final Transferable t,


 294     private void applyDragResult(final TransferMode dragResult,
 295                                  final DropTargetDragEvent e)
 296     {
 297         if (dragResult == null) {
 298             e.rejectDrag();
 299         } else {
 300             e.acceptDrag(transferModeToDropAction(dragResult));
 301         }
 302     }
 303 
 304     private void applyDropResult(final TransferMode dropResult,
 305                                  final DropTargetDropEvent e)
 306     {
 307         if (dropResult == null) {
 308             e.rejectDrop();
 309         } else {
 310             e.acceptDrop(transferModeToDropAction(dropResult));
 311         }
 312     }
 313 
 314     static TransferMode dropActionToTransferMode(final int dropAction) {
 315         switch (dropAction) {
 316             case DnDConstants.ACTION_COPY:
 317                 return TransferMode.COPY;
 318             case DnDConstants.ACTION_MOVE:
 319                 return TransferMode.MOVE;
 320             case DnDConstants.ACTION_LINK:
 321                 return TransferMode.LINK;
 322             case DnDConstants.ACTION_NONE:
 323                 return null;
 324             default:
 325                 throw new IllegalArgumentException();
 326         }
 327     }
 328 
 329     static int transferModeToDropAction(final TransferMode tm) {
 330         switch (tm) {
 331             case COPY:
 332                 return DnDConstants.ACTION_COPY;
 333             case MOVE:
 334                 return DnDConstants.ACTION_MOVE;
 335             case LINK:
 336                 return DnDConstants.ACTION_LINK;
 337             default:
 338                 throw new IllegalArgumentException();
 339         }
 340     }
 341 
 342     static Set<TransferMode> dropActionsToTransferModes(
 343             final int dropActions)
 344     {
 345         final Set<TransferMode> tms = EnumSet.noneOf(TransferMode.class);
 346         if ((dropActions & DnDConstants.ACTION_COPY) != 0) {
 347             tms.add(TransferMode.COPY);
 348         }
 349         if ((dropActions & DnDConstants.ACTION_MOVE) != 0) {
 350             tms.add(TransferMode.MOVE);
 351         }
 352         if ((dropActions & DnDConstants.ACTION_LINK) != 0) {
 353             tms.add(TransferMode.LINK);
 354         }
 355         return Collections.unmodifiableSet(tms);
 356     }
 357 
 358     static int transferModesToDropActions(final Set<TransferMode> tms) {
 359         int dropActions = DnDConstants.ACTION_NONE;
 360         for (TransferMode tm : tms) {
 361             dropActions |= transferModeToDropAction(tm);
 362         }
 363         return dropActions;
 364     }
 365 
 366     // Transferable wrapper over FX dragboard. All the calls are
 367     // forwarded to FX and executed on the FX event thread.
 368     private final class DnDTransferable implements Transferable {
 369 
 370         @Override
 371         public Object getTransferData(final DataFlavor flavor)
 372                 throws UnsupportedEncodingException
 373         {
 374             assert fxDragSource != null;
 375             assert SwingUtilities.isEventDispatchThread();
 376 
 377             String mimeType = DataFlavorUtils.getFxMimeType(flavor);
 378             return DataFlavorUtils.adjustFxData(


   1 /*
   2  * Copyright (c) 2012, 2018, Oracle and/or its affiliates. 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.  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 java.io.UnsupportedEncodingException;
  29 
  30 import java.util.Collections;
  31 import java.util.ArrayList;
  32 import java.util.EnumSet;
  33 import java.util.Arrays;
  34 import java.util.List;
  35 import java.util.Set;
  36 
  37 import com.sun.javafx.embed.EmbeddedSceneDSInterface;
  38 import com.sun.javafx.embed.HostDragStartListener;
  39 import javafx.scene.input.TransferMode;
  40 
  41 import com.sun.javafx.embed.EmbeddedSceneInterface;
  42 import com.sun.javafx.embed.EmbeddedSceneDTInterface;
  43 import com.sun.javafx.tk.Toolkit;
  44 
  45 import javax.swing.JComponent;
  46 import javax.swing.SwingUtilities;


  55 import java.awt.dnd.DragSource;
  56 import java.awt.dnd.DragSourceAdapter;
  57 import java.awt.dnd.DragSourceListener;
  58 import java.awt.dnd.DragSourceDropEvent;
  59 import java.awt.dnd.DropTarget;
  60 import java.awt.dnd.DropTargetAdapter;
  61 import java.awt.dnd.DropTargetDragEvent;
  62 import java.awt.dnd.DropTargetDropEvent;
  63 import java.awt.dnd.DropTargetEvent;
  64 import java.awt.dnd.DropTargetListener;
  65 import java.awt.dnd.InvalidDnDOperationException;
  66 
  67 import java.awt.event.InputEvent;
  68 import java.awt.event.MouseAdapter;
  69 import java.awt.event.MouseEvent;
  70 
  71 /**
  72  * An utility class to connect DnD mechanism of Swing and FX.
  73  * It allows FX content to use the AWT machinery for performing DnD.
  74  */
  75 final public class SwingDnD {
  76 
  77     private final Transferable dndTransferable = new DnDTransferable();
  78 
  79     private final DragSource dragSource;
  80     private final DragSourceListener dragSourceListener;
  81 
  82     // swingDragSource and fxDropTarget are used when DnD is initiated from
  83     // Swing or external process, i.e. this SwingDnD is used as a drop target
  84     private SwingDragSource swingDragSource;
  85     private EmbeddedSceneDTInterface fxDropTarget;
  86 
  87     // fxDragSource is used when DnD is initiated from FX, i.e. this
  88     // SwingDnD acts as a drag source
  89     private EmbeddedSceneDSInterface fxDragSource;
  90 
  91     private MouseEvent me;
  92 
  93     public SwingDnD(final JComponent comp, final EmbeddedSceneInterface embeddedScene) {
  94 
  95         comp.addMouseListener(new MouseAdapter() {
  96             @Override
  97             public void mouseClicked(MouseEvent me) {
  98                 storeMouseEvent(me);
  99             }
 100             @Override
 101             public void mouseDragged(MouseEvent me) {
 102                 storeMouseEvent(me);
 103             }
 104             @Override
 105             public void mousePressed(MouseEvent me) {
 106                 storeMouseEvent(me);
 107             }
 108             @Override
 109             public void mouseReleased(MouseEvent me) {
 110                 storeMouseEvent(me);
 111             }
 112         });
 113 


 203                         applyDropResult(lastTransferMode, e);
 204                     } catch (InvalidDnDOperationException ignore) {
 205                         // This means the JDK doesn't contain a fix for 8029979 yet.
 206                         // DnD still works, but a drag source won't know about
 207                         // the actual drop result reported by the FX app from
 208                         // its drop() handler. It will use the dropResult from
 209                         // the last call to dragOver() instead.
 210                     }
 211                 } finally {
 212                     e.dropComplete(lastTransferMode != null);
 213                     endDnD();
 214                     lastTransferMode = null;
 215                 }
 216             }
 217         };
 218         comp.setDropTarget(new DropTarget(comp,
 219                 DnDConstants.ACTION_COPY | DnDConstants.ACTION_MOVE | DnDConstants.ACTION_LINK, dtl));
 220 
 221     }
 222 
 223     public void addNotify() {
 224         dragSource.addDragSourceListener(dragSourceListener);
 225     }
 226 
 227     public void removeNotify() {
 228         // RT-22049: Multi-JFrame/JFXPanel app leaks JFXPanels
 229         // Don't forget to unregister drag source listener!
 230         dragSource.removeDragSourceListener(dragSourceListener);
 231     }
 232 
 233     public HostDragStartListener getDragStartListener() {
 234         return (dragSource, dragAction) -> {
 235             assert Toolkit.getToolkit().isFxUserThread();
 236             assert dragSource != null;
 237 
 238             // The method is called from FX Scene just before entering
 239             // nested event loop servicing DnD events.
 240             // It should initialize DnD in AWT EDT.
 241             SwingUtilities.invokeLater(() -> {
 242                 assert fxDragSource == null;
 243                 assert swingDragSource == null;
 244                 assert fxDropTarget == null;
 245 
 246                 fxDragSource = dragSource;
 247                 startDrag(me, dndTransferable, dragSource.
 248                         getSupportedActions(), dragAction);
 249             });
 250         };
 251     }
 252 
 253     private void startDrag(final MouseEvent e, final Transferable t,


 294     private void applyDragResult(final TransferMode dragResult,
 295                                  final DropTargetDragEvent e)
 296     {
 297         if (dragResult == null) {
 298             e.rejectDrag();
 299         } else {
 300             e.acceptDrag(transferModeToDropAction(dragResult));
 301         }
 302     }
 303 
 304     private void applyDropResult(final TransferMode dropResult,
 305                                  final DropTargetDropEvent e)
 306     {
 307         if (dropResult == null) {
 308             e.rejectDrop();
 309         } else {
 310             e.acceptDrop(transferModeToDropAction(dropResult));
 311         }
 312     }
 313 
 314     public static TransferMode dropActionToTransferMode(final int dropAction) {
 315         switch (dropAction) {
 316             case DnDConstants.ACTION_COPY:
 317                 return TransferMode.COPY;
 318             case DnDConstants.ACTION_MOVE:
 319                 return TransferMode.MOVE;
 320             case DnDConstants.ACTION_LINK:
 321                 return TransferMode.LINK;
 322             case DnDConstants.ACTION_NONE:
 323                 return null;
 324             default:
 325                 throw new IllegalArgumentException();
 326         }
 327     }
 328 
 329     public static int transferModeToDropAction(final TransferMode tm) {
 330         switch (tm) {
 331             case COPY:
 332                 return DnDConstants.ACTION_COPY;
 333             case MOVE:
 334                 return DnDConstants.ACTION_MOVE;
 335             case LINK:
 336                 return DnDConstants.ACTION_LINK;
 337             default:
 338                 throw new IllegalArgumentException();
 339         }
 340     }
 341 
 342     public static Set<TransferMode> dropActionsToTransferModes(
 343             final int dropActions)
 344     {
 345         final Set<TransferMode> tms = EnumSet.noneOf(TransferMode.class);
 346         if ((dropActions & DnDConstants.ACTION_COPY) != 0) {
 347             tms.add(TransferMode.COPY);
 348         }
 349         if ((dropActions & DnDConstants.ACTION_MOVE) != 0) {
 350             tms.add(TransferMode.MOVE);
 351         }
 352         if ((dropActions & DnDConstants.ACTION_LINK) != 0) {
 353             tms.add(TransferMode.LINK);
 354         }
 355         return Collections.unmodifiableSet(tms);
 356     }
 357 
 358     public static int transferModesToDropActions(final Set<TransferMode> tms) {
 359         int dropActions = DnDConstants.ACTION_NONE;
 360         for (TransferMode tm : tms) {
 361             dropActions |= transferModeToDropAction(tm);
 362         }
 363         return dropActions;
 364     }
 365 
 366     // Transferable wrapper over FX dragboard. All the calls are
 367     // forwarded to FX and executed on the FX event thread.
 368     private final class DnDTransferable implements Transferable {
 369 
 370         @Override
 371         public Object getTransferData(final DataFlavor flavor)
 372                 throws UnsupportedEncodingException
 373         {
 374             assert fxDragSource != null;
 375             assert SwingUtilities.isEventDispatchThread();
 376 
 377             String mimeType = DataFlavorUtils.getFxMimeType(flavor);
 378             return DataFlavorUtils.adjustFxData(


< prev index next >