1 /*
   2  * Copyright (c) 2000, 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 test.javafx.scene.input;
  27 
  28 import static org.junit.Assert.assertNull;
  29 import static org.junit.Assert.fail;
  30 
  31 import java.security.AccessControlContext;
  32 import java.util.ArrayList;
  33 import java.util.Arrays;
  34 import java.util.HashSet;
  35 import java.util.List;
  36 import java.util.Set;
  37 
  38 import com.sun.javafx.tk.TKScene;
  39 import javafx.event.EventHandler;
  40 import javafx.scene.Group;
  41 import javafx.scene.Node;
  42 import javafx.scene.Scene;
  43 import javafx.scene.shape.Rectangle;
  44 import javafx.stage.Stage;
  45 import javafx.util.Pair;
  46 
  47 import org.junit.After;
  48 import org.junit.Assert;
  49 import org.junit.Before;
  50 import org.junit.Test;
  51 
  52 import test.com.sun.javafx.pgstub.StubToolkit;
  53 import com.sun.javafx.tk.TKClipboard;
  54 import com.sun.javafx.tk.TKDragGestureListener;
  55 import com.sun.javafx.tk.TKDragSourceListener;
  56 import com.sun.javafx.tk.TKDropTargetListener;
  57 import com.sun.javafx.tk.Toolkit;
  58 import test.com.sun.javafx.test.MouseEventGenerator;
  59 import javafx.event.Event;
  60 import javafx.geometry.Point3D;
  61 import javafx.scene.SubScene;
  62 import javafx.scene.image.Image;
  63 import javafx.scene.input.ClipboardContent;
  64 import javafx.scene.input.ClipboardContent;
  65 import javafx.scene.input.DataFormat;
  66 import javafx.scene.input.DataFormat;
  67 import javafx.scene.input.DragEvent;
  68 import javafx.scene.input.DragEvent;
  69 import javafx.scene.input.Dragboard;
  70 import javafx.scene.input.Dragboard;
  71 import javafx.scene.input.DragboardShim;
  72 import javafx.scene.input.MouseEvent;
  73 import javafx.scene.input.MouseEvent;
  74 import javafx.scene.input.PickResult;
  75 import javafx.scene.input.PickResult;
  76 import javafx.scene.input.TransferMode;
  77 import javafx.scene.input.TransferMode;
  78 import static org.junit.Assert.assertEquals;
  79 import static org.junit.Assert.assertFalse;
  80 import static org.junit.Assert.assertNotNull;
  81 import static org.junit.Assert.assertSame;
  82 import static org.junit.Assert.assertTrue;
  83 
  84 public class DragAndDropTest {
  85     
  86     private DndToolkit toolkit = new DndToolkit();
  87     private int counter;
  88     private boolean detected;
  89     private Node dragSource;
  90     
  91     @Before
  92     public void setUp() {
  93         counter = 0;
  94         detected = false;
  95         toolkit = new DndToolkit();
  96         ((StubToolkit) Toolkit.getToolkit()).setDndDelegate(toolkit);
  97     }
  98     
  99     @After
 100     public void tearDown() {
 101         ((StubToolkit) Toolkit.getToolkit()).setDndDelegate(null);
 102         toolkit = null;
 103     }
 104     
 105     /************************************************************************/
 106     /*                      DRAG EVENT CONSTRUCTOR                          */
 107     /************************************************************************/
 108 
 109     @Test public void testShortConstructor() {
 110         Rectangle node = new Rectangle(10, 10);
 111         node.setTranslateX(3);
 112         node.setTranslateY(2);
 113         node.setTranslateZ(50);
 114         Dragboard db = DragboardShim.getDragboard(new ClipboardImpl());
 115         Rectangle gsrc = new Rectangle(10, 10);
 116         Rectangle gtrg = new Rectangle(10, 10);
 117 
 118         PickResult pickRes = new PickResult(node, new Point3D(15, 25, 100), 33);
 119         DragEvent e = new DragEvent(DragEvent.DRAG_ENTERED, db, 10, 20, 30, 40,
 120             TransferMode.LINK, gsrc, gtrg, pickRes);
 121 
 122         assertSame(DragEvent.DRAG_ENTERED, e.getEventType());
 123         assertEquals(18, e.getX(), 10e-20);
 124         assertEquals(27, e.getY(), 10e-20);
 125         assertEquals(150, e.getZ(), 10e-20);
 126         assertEquals(10, e.getSceneX(), 10e-20);
 127         assertEquals(20, e.getSceneY(), 10e-20);
 128         assertEquals(30, e.getScreenX(), 10e-20);
 129         assertEquals(40, e.getScreenY(), 10e-20);
 130         assertSame(db, e.getDragboard());
 131         assertSame(gsrc, e.getGestureSource());
 132         assertSame(gtrg, e.getGestureTarget());
 133         assertSame(TransferMode.LINK, e.getTransferMode());
 134         assertSame(pickRes, e.getPickResult());
 135         assertSame(Event.NULL_SOURCE_TARGET, e.getSource());
 136         assertSame(Event.NULL_SOURCE_TARGET, e.getTarget());
 137         assertFalse(e.isAccepted());
 138         assertNull(e.getAcceptedTransferMode());
 139         assertFalse(e.isConsumed());
 140     }
 141 
 142     @Test public void testShortConstructorWithoutPickResult() {
 143         Dragboard db = DragboardShim.getDragboard(new ClipboardImpl());
 144         Rectangle gsrc = new Rectangle(10, 10);
 145         Rectangle gtrg = new Rectangle(10, 10);
 146         DragEvent e = new DragEvent(DragEvent.DRAG_ENTERED, db, 10, 20, 30, 40,
 147             TransferMode.LINK, gsrc, gtrg, null);
 148 
 149         assertEquals(10, e.getX(), 10e-20);
 150         assertEquals(20, e.getY(), 10e-20);
 151         assertEquals(0, e.getZ(), 10e-20);
 152         assertEquals(10, e.getSceneX(), 10e-20);
 153         assertEquals(20, e.getSceneY(), 10e-20);
 154         assertEquals(30, e.getScreenX(), 10e-20);
 155         assertEquals(40, e.getScreenY(), 10e-20);
 156         assertNotNull(e.getPickResult());
 157         assertNotNull(e.getPickResult().getIntersectedPoint());
 158         assertEquals(10, e.getPickResult().getIntersectedPoint().getX(), 10e-20);
 159         assertEquals(20, e.getPickResult().getIntersectedPoint().getY(), 10e-20);
 160         assertEquals(0, e.getPickResult().getIntersectedPoint().getZ(), 10e-20);
 161         assertSame(Event.NULL_SOURCE_TARGET, e.getSource());
 162         assertSame(Event.NULL_SOURCE_TARGET, e.getTarget());
 163     }
 164 
 165     @Test public void testLongConstructor() {
 166         Rectangle node = new Rectangle(10, 10);
 167         node.setTranslateX(3);
 168         node.setTranslateY(2);
 169         node.setTranslateZ(50);
 170         Rectangle n1 = new Rectangle(10, 10);
 171         Rectangle n2 = new Rectangle(10, 10);
 172         Dragboard db = DragboardShim.getDragboard(new ClipboardImpl());
 173         Rectangle gsrc = new Rectangle(10, 10);
 174         Rectangle gtrg = new Rectangle(10, 10);
 175 
 176         PickResult pickRes = new PickResult(node, new Point3D(15, 25, 100), 33);
 177         DragEvent e = new DragEvent(n1, n2, DragEvent.DRAG_ENTERED, db,
 178                 10, 20, 30, 40, TransferMode.LINK, gsrc, gtrg, pickRes);
 179         assertSame(n1, e.getSource());
 180         assertSame(n2, e.getTarget());
 181         assertSame(DragEvent.DRAG_ENTERED, e.getEventType());
 182         assertEquals(18, e.getX(), 10e-20);
 183         assertEquals(27, e.getY(), 10e-20);
 184         assertEquals(150, e.getZ(), 10e-20);
 185         assertEquals(10, e.getSceneX(), 10e-20);
 186         assertEquals(20, e.getSceneY(), 10e-20);
 187         assertEquals(30, e.getScreenX(), 10e-20);
 188         assertEquals(40, e.getScreenY(), 10e-20);
 189         assertSame(TransferMode.LINK, e.getTransferMode());
 190         assertSame(db, e.getDragboard());
 191         assertSame(gsrc, e.getGestureSource());
 192         assertSame(gtrg, e.getGestureTarget());
 193         assertSame(pickRes, e.getPickResult());
 194         assertFalse(e.isConsumed());
 195         assertFalse(e.isAccepted());
 196         assertNull(e.getAcceptedTransferMode());
 197     }
 198 
 199     @Test public void testLongConstructorWithoutPickResult() {
 200         Rectangle n1 = new Rectangle(10, 10);
 201         Rectangle n2 = new Rectangle(10, 10);
 202         Dragboard db = DragboardShim.getDragboard(new ClipboardImpl());
 203         Rectangle gsrc = new Rectangle(10, 10);
 204         Rectangle gtrg = new Rectangle(10, 10);
 205         DragEvent e = new DragEvent(n1, n2, DragEvent.DRAG_ENTERED, db,
 206                 10, 20, 30, 40, TransferMode.LINK, gsrc, gtrg, null);
 207 
 208         assertEquals(10, e.getX(), 10e-20);
 209         assertEquals(20, e.getY(), 10e-20);
 210         assertEquals(0, e.getZ(), 10e-20);
 211         assertEquals(10, e.getSceneX(), 10e-20);
 212         assertEquals(20, e.getSceneY(), 10e-20);
 213         assertEquals(30, e.getScreenX(), 10e-20);
 214         assertEquals(40, e.getScreenY(), 10e-20);
 215         assertNotNull(e.getPickResult());
 216         assertNotNull(e.getPickResult().getIntersectedPoint());
 217         assertEquals(10, e.getPickResult().getIntersectedPoint().getX(), 10e-20);
 218         assertEquals(20, e.getPickResult().getIntersectedPoint().getY(), 10e-20);
 219         assertEquals(0, e.getPickResult().getIntersectedPoint().getZ(), 10e-20);
 220     }
 221 
 222     @Test public void shortConstructorMakesDropAccepted() {
 223         DragEvent e = new DragEvent(DragEvent.DRAG_DROPPED,
 224                 DragboardShim.getDragboard(
 225                         new ClipboardImpl()), 10, 20, 30, 40,
 226                 TransferMode.LINK, new Rectangle(), new Rectangle(), null);
 227         assertSame(DragEvent.DRAG_DROPPED, e.getEventType());
 228         assertTrue(e.isAccepted());
 229         assertSame(TransferMode.LINK, e.getAcceptedTransferMode());
 230     }
 231 
 232     @Test
 233     public void shortConstructorMakesDoneAccepted() {
 234         DragEvent e = new DragEvent(DragEvent.DRAG_DONE,
 235                 DragboardShim.getDragboard(
 236                         new ClipboardImpl()), 10, 20, 30, 40,
 237                 TransferMode.LINK, new Rectangle(), new Rectangle(), null);
 238         assertSame(DragEvent.DRAG_DONE, e.getEventType());
 239         assertTrue(e.isAccepted());
 240         assertSame(TransferMode.LINK, e.getAcceptedTransferMode());
 241     }
 242 
 243     @Test public void longConstructorMakesDropAccepted() {
 244         DragEvent e = new DragEvent(new Rectangle(), new Rectangle(),
 245                 DragEvent.DRAG_DROPPED,
 246                 DragboardShim.getDragboard(
 247                 new ClipboardImpl()), 10, 20, 30, 40,
 248                 TransferMode.LINK, new Rectangle(), new Rectangle(), null);
 249         assertSame(DragEvent.DRAG_DROPPED, e.getEventType());
 250         assertTrue(e.isAccepted());
 251         assertSame(TransferMode.LINK, e.getAcceptedTransferMode());
 252     }
 253 
 254     @Test public void longConstructorMakesDoneAccepted() {
 255         DragEvent e = new DragEvent(new Rectangle(), new Rectangle(),
 256                 DragEvent.DRAG_DONE,
 257                 DragboardShim.getDragboard(
 258                         new ClipboardImpl()), 10, 20, 30, 40,
 259                 TransferMode.LINK, new Rectangle(), new Rectangle(), null);
 260         assertSame(DragEvent.DRAG_DONE, e.getEventType());
 261         assertTrue(e.isAccepted());
 262         assertSame(TransferMode.LINK, e.getAcceptedTransferMode());
 263     }
 264 
 265     /************************************************************************/
 266     /*                         DRAG INITIATION                              */
 267     /************************************************************************/
 268     
 269     
 270     @Test
 271     public void dragDetectionShouldUseHysteresis() {
 272         Node n = oneNode();
 273         MouseEventGenerator gen = new MouseEventGenerator();
 274         
 275         EventHandler<MouseEvent> thirdEventFailsHysteresis =
 276                 event -> {
 277                     counter++;
 278                     assertTrue((counter != 3 && !event.isDragDetect()) ||
 279                             (counter == 3 && event.isDragDetect()));
 280                 };
 281 
 282         n.addEventHandler(MouseEvent.MOUSE_PRESSED, thirdEventFailsHysteresis);
 283         n.addEventHandler(MouseEvent.MOUSE_DRAGGED, thirdEventFailsHysteresis);
 284         n.addEventHandler(MouseEvent.MOUSE_RELEASED, thirdEventFailsHysteresis);
 285         
 286         n.getScene().impl_processMouseEvent(
 287                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 288         n.getScene().impl_processMouseEvent(
 289                 gen.generateMouseEvent(MouseEvent.MOUSE_DRAGGED, 52, 48));
 290         n.getScene().impl_processMouseEvent(
 291                 gen.generateMouseEvent(MouseEvent.MOUSE_DRAGGED, 70, 70));
 292         n.getScene().impl_processMouseEvent(
 293                 gen.generateMouseEvent(MouseEvent.MOUSE_DRAGGED, 50, 50));
 294         n.getScene().impl_processMouseEvent(
 295                 gen.generateMouseEvent(MouseEvent.MOUSE_RELEASED, 50, 50));
 296         
 297         assertEquals(5, counter);
 298     }
 299     
 300     @Test
 301     public void dragShouldNotBeDetectedBasedOnMoveOrRelase() {
 302         Node n = oneNode();
 303         MouseEventGenerator gen = new MouseEventGenerator();
 304 
 305         n.setOnDragDetected(detector);
 306         n.setOnMousePressed(dontDetect);
 307         n.setOnMouseMoved(doDetect);
 308         n.setOnMouseReleased(doDetect);
 309         
 310         /* dontDetect prevents detection */
 311         n.getScene().impl_processMouseEvent(
 312                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 313         assertFalse(detected);
 314 
 315         n.getScene().impl_processMouseEvent(
 316                 gen.generateMouseEvent(MouseEvent.MOUSE_RELEASED, 50, 50));
 317         assertFalse(detected);
 318 
 319         n.getScene().impl_processMouseEvent(
 320                 gen.generateMouseEvent(MouseEvent.MOUSE_MOVED, 60, 60));
 321         assertFalse(detected);
 322     }
 323 
 324     @Test
 325     public void dragShouldBeDetectedBasedOnMouseEvent() {
 326         Node n = oneNode();
 327         MouseEventGenerator gen = new MouseEventGenerator();
 328 
 329         n.setOnDragDetected(detector);
 330         n.setOnMousePressed(dontDetect);
 331         n.setOnMouseDragged(dontDetect);
 332         n.setOnMouseReleased(doDetect);
 333         
 334         /* dontDetect prevents detection */
 335         n.getScene().impl_processMouseEvent(
 336                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 337         assertFalse(detected);
 338         n.getScene().impl_processMouseEvent(
 339                 gen.generateMouseEvent(MouseEvent.MOUSE_DRAGGED, 52, 48));
 340         assertFalse(detected);
 341         n.getScene().impl_processMouseEvent(
 342                 gen.generateMouseEvent(MouseEvent.MOUSE_DRAGGED, 70, 70));
 343         assertFalse(detected);
 344 
 345         /* doDetect fires detection */
 346         n.setOnMouseDragged(doDetect);
 347         
 348         n.getScene().impl_processMouseEvent(
 349                 gen.generateMouseEvent(MouseEvent.MOUSE_DRAGGED, 50, 50));
 350         assertTrue(detected);
 351         detected = false;
 352 
 353         /* but fires it only once */
 354         n.getScene().impl_processMouseEvent(
 355                 gen.generateMouseEvent(MouseEvent.MOUSE_DRAGGED, 70, 70));
 356         assertFalse(detected);
 357         
 358         n.getScene().impl_processMouseEvent(
 359                 gen.generateMouseEvent(MouseEvent.MOUSE_RELEASED, 50, 50));
 360         assertFalse(detected);
 361     }
 362     
 363     @Test
 364     public void dragDetectionShouldBeOverridable() {
 365         Node n = oneNode();
 366         MouseEventGenerator gen = new MouseEventGenerator();
 367 
 368         n.setOnDragDetected(detector);
 369         n.setOnMousePressed(doDetect);
 370         n.setOnMouseDragged(dontDetect);
 371         n.getParent().setOnMousePressed(dontDetect);
 372         n.getParent().setOnMouseDragged(doDetect);
 373         
 374         /* dontDetect prevents detection */
 375         n.getScene().impl_processMouseEvent(
 376                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 377         assertFalse(detected);
 378         
 379         n.getScene().impl_processMouseEvent(
 380                 gen.generateMouseEvent(MouseEvent.MOUSE_DRAGGED, 50, 50));
 381         assertTrue(detected);
 382         detected = false;
 383 
 384         n.getScene().impl_processMouseEvent(
 385                 gen.generateMouseEvent(MouseEvent.MOUSE_RELEASED, 50, 50));
 386         assertFalse(detected);
 387     }
 388     
 389     @Test
 390     public void startDragShouldNotBeCalledIfNothingPutOnDragboard() {
 391         final Node n = oneNode();
 392         final MouseEventGenerator gen = new MouseEventGenerator();
 393         
 394         n.setOnMousePressed(doDetect);
 395         n.setOnDragDetected(event -> {
 396             n.startDragAndDrop(TransferMode.COPY);
 397         });
 398 
 399         n.getScene().impl_processMouseEvent(
 400                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 401         n.getScene().impl_processMouseEvent(
 402                 gen.generateMouseEvent(MouseEvent.MOUSE_DRAGGED, 50, 50));
 403         n.getScene().impl_processMouseEvent(
 404                 gen.generateMouseEvent(MouseEvent.MOUSE_RELEASED, 50, 50));
 405         
 406         assertFalse(toolkit.dragging);
 407     }
 408     
 409     @Test
 410     public void startDragShouldBeCalledIfStringPutOnDragboard() {
 411         final Node n = oneNode();
 412         final MouseEventGenerator gen = new MouseEventGenerator();
 413         
 414         dragSource = n;
 415         n.setOnMousePressed(doDetect);
 416         n.setOnDragDetected(stringSource(TransferMode.ANY));
 417 
 418         n.getScene().impl_processMouseEvent(
 419                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 420         assertTrue(toolkit.dragging);
 421     }
 422     
 423     /************************************************************************/
 424     /*                           SOURCE/TARGET                              */
 425     /************************************************************************/
 426 
 427     @Test
 428     public void nodeThatCallsStartDndShouldBecomeGestureSource() {
 429         final Node n = oneNode();
 430         final MouseEventGenerator gen = new MouseEventGenerator();
 431         
 432         dragSource = n.getParent();
 433         n.setOnMousePressed(doDetect);
 434         n.setOnDragDetected(stringSource(TransferMode.ANY));
 435         n.setOnDragOver(event -> {
 436             assertSame(dragSource, event.getGestureSource());
 437             counter++;
 438         });
 439 
 440         n.getScene().impl_processMouseEvent(
 441                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 442         toolkit.dragTo(52, 52, TransferMode.COPY);
 443         
 444         assertEquals(1, counter);
 445     }
 446 
 447     @Test
 448     public void parentThatCallsStartDndShouldBecomeGestureSource() {
 449         final Node n = oneNode();
 450         final MouseEventGenerator gen = new MouseEventGenerator();
 451         
 452         dragSource = n.getParent();
 453         n.setOnMousePressed(doDetect);
 454         n.getParent().setOnDragDetected(stringSource(TransferMode.ANY));
 455         n.setOnDragOver(event -> {
 456             assertSame(dragSource, event.getGestureSource());
 457             counter++;
 458         });
 459 
 460         n.getScene().impl_processMouseEvent(
 461                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 462         toolkit.dragTo(52, 52, TransferMode.COPY);
 463         
 464         assertEquals(1, counter);
 465     }
 466 
 467     @Test
 468     public void nodeThatAcceptsDragShouldBecomeGestureTarget() {
 469         final Node n = oneNode();
 470         final MouseEventGenerator gen = new MouseEventGenerator();
 471         
 472         dragSource = n;
 473         n.setOnMousePressed(doDetect);
 474         n.setOnDragDetected(stringSource(TransferMode.ANY));
 475         n.setOnDragOver(event -> {
 476             event.acceptTransferModes(TransferMode.ANY);
 477             if (counter == 0) {
 478                 assertNull(event.getGestureTarget());
 479             } else {
 480                 assertSame(n, event.getGestureTarget());
 481             }
 482             counter++;
 483         });
 484         n.setOnDragDropped(event -> {
 485             assertSame(n, event.getGestureTarget());
 486             counter++;
 487         });
 488 
 489         n.getScene().impl_processMouseEvent(
 490                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 491         toolkit.dragTo(51, 51, TransferMode.COPY);
 492         toolkit.dragTo(52, 52, TransferMode.COPY);
 493         toolkit.drop(52, 52, TransferMode.COPY);
 494         
 495         assertEquals(3, counter);
 496     }
 497     
 498     @Test
 499     public void parentThatAcceptsDragShouldBecomeGestureTarget() {
 500         final Node n = oneNode();
 501         final MouseEventGenerator gen = new MouseEventGenerator();
 502         
 503         dragSource = n;
 504         n.setOnMousePressed(doDetect);
 505         n.setOnDragDetected(stringSource(TransferMode.ANY));
 506         n.setOnDragOver(event -> {
 507             event.acceptTransferModes(TransferMode.ANY);
 508             if (counter == 0) {
 509                 assertNull(event.getGestureTarget());
 510             } else {
 511                 assertSame(n.getParent(), event.getGestureTarget());
 512             }
 513             counter++;
 514         });
 515         n.getParent().setOnDragOver(acceptAny);
 516         n.setOnDragDropped(event -> {
 517             assertSame(n.getParent(), event.getGestureTarget());
 518             counter++;
 519         });
 520 
 521         n.getScene().impl_processMouseEvent(
 522                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 523         toolkit.dragTo(51, 51, TransferMode.COPY);
 524         toolkit.dragTo(52, 52, TransferMode.COPY);
 525         toolkit.drop(52, 52, TransferMode.COPY);
 526         
 527         assertEquals(3, counter);
 528     }
 529 
 530     @Test
 531     public void sceneCanBecomeGestureSource() {
 532         final Node n = oneNode();
 533         final MouseEventGenerator gen = new MouseEventGenerator();
 534         
 535         n.setOnMousePressed(doDetect);
 536         n.getScene().setOnDragDetected(event -> {
 537             Dragboard db = n.getScene().startDragAndDrop(TransferMode.ANY);
 538             ClipboardContent cc = new ClipboardContent();
 539             cc.putString("Hello");
 540             db.setContent(cc);
 541         });
 542         n.setOnDragOver(event -> {
 543             assertSame(n.getScene(), event.getGestureSource());
 544             counter++;
 545         });
 546 
 547         n.getScene().impl_processMouseEvent(
 548                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 549         toolkit.dragTo(52, 52, TransferMode.COPY);
 550         
 551         assertEquals(1, counter);
 552     }
 553     
 554     @Test
 555     public void sceneCanBecomeGestureTarget() {
 556         final Node n = oneNode();
 557         final MouseEventGenerator gen = new MouseEventGenerator();
 558         
 559         dragSource = n;
 560         n.setOnMousePressed(doDetect);
 561         n.setOnDragDetected(stringSource(TransferMode.ANY));
 562         n.getScene().setOnDragOver(event -> {
 563             event.acceptTransferModes(TransferMode.ANY);
 564             if (counter == 0) {
 565                 assertNull(event.getGestureTarget());
 566             } else {
 567                 assertSame(n.getScene(), event.getGestureTarget());
 568             }
 569             counter++;
 570         });
 571         n.setOnDragDropped(event -> {
 572             assertSame(n.getScene(), event.getGestureTarget());
 573             counter++;
 574         });
 575 
 576         n.getScene().impl_processMouseEvent(
 577                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 578         toolkit.dragTo(51, 51, TransferMode.COPY);
 579         toolkit.dragTo(52, 52, TransferMode.COPY);
 580         toolkit.drop(52, 52, TransferMode.COPY);
 581         
 582         assertEquals(3, counter);
 583     }
 584     
 585     /************************************************************************/
 586     /*                           TRANSFER MODES                             */
 587     /************************************************************************/
 588     
 589     @Test 
 590     public void defaultTransferModeShouldBeUsedIfSupported() {
 591         final Node n = oneNode();
 592         final MouseEventGenerator gen = new MouseEventGenerator();
 593 
 594         dragSource = n;
 595         n.setOnMousePressed(doDetect);
 596         n.setOnDragDetected(stringSource(TransferMode.ANY));
 597         n.setOnDragOver(acceptAny);
 598 
 599         /* start drag */
 600         n.getScene().impl_processMouseEvent(
 601                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 602         
 603         /* drag */
 604         assertSame(TransferMode.LINK, toolkit.dragTo(52, 52, TransferMode.LINK));
 605     }
 606     
 607     @Test 
 608     public void defaultTransferModeShouldNotBeUsedIfNotSupported() {
 609         final Node n = oneNode();
 610         final MouseEventGenerator gen = new MouseEventGenerator();
 611 
 612         dragSource = n;
 613         n.setOnMousePressed(doDetect);
 614         n.setOnDragDetected(stringSource(TransferMode.COPY));
 615         n.setOnDragOver(acceptAny);
 616 
 617         /* start drag */
 618         n.getScene().impl_processMouseEvent(
 619                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 620         
 621         /* drag */
 622         assertSame(TransferMode.COPY, toolkit.dragTo(52, 52, TransferMode.LINK));
 623     }
 624     
 625     @Test 
 626     public void mostCommonTransferModeShouldBeChosen() {
 627         final Node n = oneNode();
 628         final MouseEventGenerator gen = new MouseEventGenerator();
 629 
 630         dragSource = n;
 631         n.setOnMousePressed(doDetect);
 632         n.setOnDragDetected(stringSource(TransferMode.COPY_OR_MOVE));
 633         n.setOnDragOver(acceptAny);
 634 
 635         /* start drag */
 636         n.getScene().impl_processMouseEvent(
 637                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 638         
 639         /* drag */
 640         assertSame(TransferMode.MOVE, toolkit.dragTo(52, 52, TransferMode.LINK));
 641     }
 642     
 643     @Test 
 644     public void transferModeAcceptanceShouldBeOverridable_restriction() {
 645         final Node n = oneNode();
 646         final MouseEventGenerator gen = new MouseEventGenerator();
 647 
 648         dragSource = n;
 649         n.setOnMousePressed(doDetect);
 650         n.setOnDragDetected(stringSource(TransferMode.COPY_OR_MOVE));
 651         n.setOnDragOver(acceptAny);
 652         n.getParent().setOnDragOver(acceptCopy);
 653 
 654         /* start drag */
 655         n.getScene().impl_processMouseEvent(
 656                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 657         
 658         /* drag */
 659         assertSame(TransferMode.COPY, toolkit.dragTo(52, 52, TransferMode.MOVE));
 660     }
 661     
 662     @Test 
 663     public void transferModeAcceptanceShouldBeOverridable_loosening() {
 664         final Node n = oneNode();
 665         final MouseEventGenerator gen = new MouseEventGenerator();
 666 
 667         dragSource = n;
 668         n.setOnMousePressed(doDetect);
 669         n.setOnDragDetected(stringSource(TransferMode.COPY_OR_MOVE));
 670         n.setOnDragOver(acceptCopy);
 671         n.getParent().setOnDragOver(acceptAny);
 672 
 673         /* start drag */
 674         n.getScene().impl_processMouseEvent(
 675                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 676         
 677         /* drag */
 678         assertSame(TransferMode.MOVE, toolkit.dragTo(52, 52, TransferMode.MOVE));
 679     }
 680     
 681     @Test 
 682     public void noTransferShouldHappenWhenUnsupportedModeIsAccepted() {
 683         final Node n = oneNode();
 684         final MouseEventGenerator gen = new MouseEventGenerator();
 685 
 686         dragSource = n;
 687         n.setOnMousePressed(doDetect);
 688         n.setOnDragDetected(stringSource(TransferMode.LINK));
 689         n.setOnDragOver(acceptCopyOrMove);
 690 
 691         /* start drag */
 692         n.getScene().impl_processMouseEvent(
 693                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 694         
 695         /* drag */
 696         assertNull(toolkit.dragTo(52, 52, TransferMode.MOVE));
 697     }
 698     
 699     @Test 
 700     public void noTransferShouldHappenWhenNotAccepted() {
 701         final Node n = oneNode();
 702         final MouseEventGenerator gen = new MouseEventGenerator();
 703 
 704         dragSource = n;
 705         n.setOnMousePressed(doDetect);
 706         n.setOnDragDetected(stringSource(TransferMode.ANY));
 707 
 708         /* start drag */
 709         n.getScene().impl_processMouseEvent(
 710                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 711         
 712         /* drag */
 713         assertNull(toolkit.dragTo(52, 52, TransferMode.MOVE));
 714     }
 715 
 716     @Test 
 717     public void dropShouldGetAcceptedTransferMode() {
 718         final Node n = oneNode();
 719         final MouseEventGenerator gen = new MouseEventGenerator();
 720 
 721         dragSource = n;
 722         n.setOnMousePressed(doDetect);
 723         n.setOnDragDetected(stringSource(TransferMode.ANY));
 724         n.setOnDragOver(acceptCopy);
 725         n.setOnDragDropped(event -> {
 726             counter++;
 727             assertSame(TransferMode.COPY, event.getTransferMode());
 728             assertSame(TransferMode.COPY, event.getAcceptedTransferMode());
 729         });
 730 
 731         /* start drag */
 732         n.getScene().impl_processMouseEvent(
 733                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 734         
 735         /* drag and drop*/
 736         toolkit.dragTo(52, 52, TransferMode.MOVE);
 737         toolkit.drop(52, 52, TransferMode.MOVE);
 738         
 739         assertEquals(1, counter);
 740     }
 741     
 742     @Test 
 743     public void shouldBePossibleToAcceptInDrop() {
 744         final Node n = oneNode();
 745         final MouseEventGenerator gen = new MouseEventGenerator();
 746 
 747         dragSource = n;
 748         n.setOnMousePressed(doDetect);
 749         n.setOnDragDetected(stringSource(TransferMode.ANY));
 750         n.setOnDragOver(acceptCopy);
 751         n.setOnDragDropped(event -> {
 752             assertSame(TransferMode.COPY, event.getTransferMode());
 753             assertSame(TransferMode.COPY, event.getAcceptedTransferMode());
 754             event.acceptTransferModes(TransferMode.MOVE);
 755             event.setDropCompleted(true);
 756             assertSame(TransferMode.COPY, event.getTransferMode());
 757             assertSame(TransferMode.MOVE, event.getAcceptedTransferMode());
 758         });
 759 
 760         /* start drag */
 761         n.getScene().impl_processMouseEvent(
 762                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 763         
 764         /* drag and drop*/
 765         toolkit.dragTo(52, 52, TransferMode.MOVE);
 766         assertEquals(TransferMode.MOVE, toolkit.drop(52, 52, TransferMode.LINK));
 767     }
 768     
 769     @Test
 770     public void acceptingNonSupportedTransferModeInDropShouldThrowException() {
 771         final Node n = oneNode();
 772         final MouseEventGenerator gen = new MouseEventGenerator();
 773 
 774         dragSource = n;
 775         n.setOnMousePressed(doDetect);
 776         n.setOnDragDetected(stringSource(TransferMode.COPY_OR_MOVE));
 777         n.setOnDragOver(acceptCopy);
 778         n.setOnDragDropped(event -> {
 779             try {
 780                 event.acceptTransferModes(TransferMode.LINK);
 781                 fail("Exception was not thrown");
 782             } catch (IllegalStateException e) {
 783                 /* expceted */
 784                 counter++;
 785             }
 786         });
 787 
 788         /* start drag */
 789         n.getScene().impl_processMouseEvent(
 790                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 791         
 792         /* drag and drop*/
 793         toolkit.dragTo(52, 52, TransferMode.MOVE);
 794         toolkit.drop(52, 52, TransferMode.LINK);
 795         
 796         assertEquals(1, counter);
 797     }
 798 
 799     @Test
 800     public void modifyingStaticArraysShouldNotInfluenceResult() {
 801         TransferMode.ANY[0] = TransferMode.LINK;
 802         TransferMode.ANY[1] = TransferMode.LINK;
 803         TransferMode.ANY[2] = TransferMode.LINK;
 804 
 805         TransferMode.COPY_OR_MOVE[0] = TransferMode.LINK;
 806         TransferMode.COPY_OR_MOVE[1] = TransferMode.LINK;
 807 
 808         final Node n = oneNode();
 809         final MouseEventGenerator gen = new MouseEventGenerator();
 810 
 811         dragSource = n;
 812         n.setOnMousePressed(doDetect);
 813         n.setOnDragDetected(stringSource(TransferMode.ANY));
 814         n.setOnDragOver(acceptCopyOrMove);
 815         n.setOnDragDropped(event -> {
 816             event.acceptTransferModes(TransferMode.ANY);
 817             event.setDropCompleted(true);
 818         });
 819 
 820         /* start drag */
 821         n.getScene().impl_processMouseEvent(
 822                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 823 
 824         /* drag and drop*/
 825         assertSame(TransferMode.COPY, toolkit.dragTo(52, 52, TransferMode.COPY));
 826         assertSame(TransferMode.COPY, toolkit.drop(52, 52, TransferMode.COPY));
 827 
 828         TransferMode.ANY[0] = TransferMode.COPY;
 829         TransferMode.ANY[1] = TransferMode.MOVE;
 830         TransferMode.ANY[2] = TransferMode.LINK;
 831 
 832         TransferMode.COPY_OR_MOVE[0] = TransferMode.COPY;
 833         TransferMode.COPY_OR_MOVE[1] = TransferMode.MOVE;
 834     }
 835 
 836     /************************************************************************/
 837     /*                           GESTURE FINISH                             */
 838     /************************************************************************/
 839     
 840     @Test 
 841     public void dropShouldBeAcceptedByCompletion() {
 842         final Node n = oneNode();
 843         final MouseEventGenerator gen = new MouseEventGenerator();
 844 
 845         dragSource = n;
 846         n.setOnMousePressed(doDetect);
 847         n.setOnDragDetected(stringSource(TransferMode.ANY));
 848         n.setOnDragOver(acceptCopy);
 849         n.setOnDragDropped(event -> {
 850             event.setDropCompleted(true);
 851         });
 852 
 853         /* start drag */
 854         n.getScene().impl_processMouseEvent(
 855                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 856         
 857         /* drag and drop*/
 858         toolkit.dragTo(52, 52, TransferMode.MOVE);
 859         assertSame(TransferMode.COPY, toolkit.drop(52, 52, TransferMode.MOVE));
 860     }
 861     
 862     @Test 
 863     public void dropShouldNotBeAcceptedWithUnsuccessfulCompletion() {
 864         final Node n = oneNode();
 865         final MouseEventGenerator gen = new MouseEventGenerator();
 866 
 867         dragSource = n;
 868         n.setOnMousePressed(doDetect);
 869         n.setOnDragDetected(stringSource(TransferMode.ANY));
 870         n.setOnDragOver(acceptCopy);
 871         n.setOnDragDropped(event -> {
 872             event.setDropCompleted(false);
 873         });
 874 
 875         /* start drag */
 876         n.getScene().impl_processMouseEvent(
 877                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 878         
 879         /* drag and drop*/
 880         toolkit.dragTo(52, 52, TransferMode.MOVE);
 881         assertNull(toolkit.drop(52, 52, TransferMode.MOVE));
 882     }
 883     
 884     @Test 
 885     public void dropShouldNotBeAcceptedWithoutCompletion() {
 886         final Node n = oneNode();
 887         final MouseEventGenerator gen = new MouseEventGenerator();
 888 
 889         dragSource = n;
 890         n.setOnMousePressed(doDetect);
 891         n.setOnDragDetected(stringSource(TransferMode.ANY));
 892         n.setOnDragOver(acceptCopy);
 893 
 894         /* start drag */
 895         n.getScene().impl_processMouseEvent(
 896                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 897         
 898         /* drag and drop*/
 899         toolkit.dragTo(52, 52, TransferMode.MOVE);
 900         assertNull(toolkit.drop(52, 52, TransferMode.MOVE));
 901     }
 902     
 903     @Test 
 904     public void dropCompletionShouldBeOverridable() {
 905         final Node n = oneNode();
 906         final MouseEventGenerator gen = new MouseEventGenerator();
 907 
 908         dragSource = n;
 909         n.setOnMousePressed(doDetect);
 910         n.setOnDragDetected(stringSource(TransferMode.ANY));
 911         n.setOnDragOver(acceptCopyOrMove);
 912         n.setOnDragDropped(event -> {
 913             event.setDropCompleted(false);
 914         });
 915         n.getParent().setOnDragDropped(event -> {
 916             event.setDropCompleted(true);
 917         });
 918 
 919         /* start drag */
 920         n.getScene().impl_processMouseEvent(
 921                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 922         
 923         /* drag and drop*/
 924         toolkit.dragTo(52, 52, TransferMode.MOVE);
 925         assertSame(TransferMode.MOVE, toolkit.drop(52, 52, TransferMode.MOVE));
 926     }
 927     
 928     @Test 
 929     public void dropDoneShouldBeSentToGestureSource() {
 930         final Node[] ns = twoNodes();
 931         Node src = ns[0];
 932         Node trgt = ns[1];
 933 
 934         final MouseEventGenerator gen = new MouseEventGenerator();
 935 
 936         dragSource = src;
 937         src.setOnMousePressed(doDetect);
 938         src.setOnDragDetected(stringSource(TransferMode.ANY));
 939         trgt.setOnDragOver(acceptCopyOrMove);
 940         trgt.setOnDragDropped(event -> {
 941             event.setDropCompleted(true);
 942         });
 943         src.getParent().setOnDragDone(event -> {
 944             Assert.assertEquals(TransferMode.MOVE, event.getTransferMode());
 945             Assert.assertEquals(TransferMode.MOVE, event.getAcceptedTransferMode());
 946             counter++;
 947         });
 948 
 949         /* start drag */
 950         src.getScene().impl_processMouseEvent(
 951                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 952         
 953         /* drag and drop*/
 954         toolkit.dragTo(52, 52, TransferMode.MOVE);
 955         toolkit.dragTo(252, 52, TransferMode.MOVE);
 956         toolkit.drop(252, 52, TransferMode.COPY);
 957         toolkit.done(TransferMode.MOVE);
 958         assertEquals(counter, 1);
 959     }
 960     
 961     /************************************************************************/
 962     /*                            ENTERED/EXITED                            */
 963     /************************************************************************/
 964     
 965     @Test 
 966     public void dragSourceShouldGetEnteredImmediately() {
 967         final Node n = oneNode();
 968         final MouseEventGenerator gen = new MouseEventGenerator();
 969 
 970         dragSource = n;
 971         n.setOnMousePressed(doDetect);
 972         n.setOnDragDetected(stringSource(TransferMode.ANY));
 973         n.setOnDragOver(acceptAny);
 974         n.setOnDragEntered(event -> {
 975             counter++;
 976         });
 977 
 978         /* start drag */
 979         n.getScene().impl_processMouseEvent(
 980                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
 981         assertEquals(0, counter);
 982         
 983         /* drag */
 984         toolkit.dragTo(52, 52, TransferMode.MOVE);
 985         assertEquals(1, counter);
 986     }
 987     
 988     @Test 
 989     public void dragSourcesParentShouldGetEnteredImmediately() {
 990         final Node n = oneNode();
 991         final MouseEventGenerator gen = new MouseEventGenerator();
 992 
 993         dragSource = n;
 994         n.setOnMousePressed(doDetect);
 995         n.setOnDragDetected(stringSource(TransferMode.ANY));
 996         n.setOnDragOver(acceptAny);
 997         n.getParent().setOnDragEntered(event -> {
 998             counter++;
 999         });
1000 
1001         /* start drag */
1002         n.getScene().impl_processMouseEvent(
1003                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1004         assertEquals(0, counter);
1005         
1006         /* drag */
1007         toolkit.dragTo(52, 52, TransferMode.MOVE);
1008         assertEquals(1, counter);
1009     }
1010     
1011     @Test
1012     public void dragSourcesSubScenesParentShouldGetEnteredImmediately() {
1013         final Node[] ns = oneNodeInSubScene();
1014         final Node n = ns[0];
1015         final Node subScene = ns[1];
1016 
1017         dragSource = n;
1018         n.setOnMousePressed(doDetect);
1019         n.setOnDragDetected(stringSource(TransferMode.ANY));
1020         n.setOnDragOver(acceptAny);
1021         subScene.setOnDragEntered(event -> {
1022             counter++;
1023         });
1024         subScene.getParent().setOnDragEntered(event -> {
1025             counter++;
1026         });
1027 
1028         /* start drag */
1029         n.getScene().impl_processMouseEvent(
1030                 MouseEventGenerator.generateMouseEvent(
1031                     MouseEvent.MOUSE_PRESSED, 50, 50));
1032         assertEquals(0, counter);
1033 
1034         /* drag */
1035         toolkit.dragTo(52, 52, TransferMode.MOVE);
1036         assertEquals(2, counter);
1037     }
1038 
1039     @Test 
1040     public void dragSourcesParentShouldGetEnteredTargetTwice() {
1041         final Node n = oneNode();
1042         final MouseEventGenerator gen = new MouseEventGenerator();
1043 
1044         dragSource = n;
1045         n.setOnMousePressed(doDetect);
1046         n.setOnDragDetected(stringSource(TransferMode.ANY));
1047         n.setOnDragOver(acceptAny);
1048         n.getParent().addEventHandler(DragEvent.DRAG_ENTERED_TARGET,
1049                 event -> {
1050                     counter++;
1051                 }
1052         );
1053 
1054         /* start drag */
1055         n.getScene().impl_processMouseEvent(
1056                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1057         assertEquals(0, counter);
1058         
1059         /* drag */
1060         toolkit.dragTo(52, 52, TransferMode.MOVE);
1061         assertEquals(2, counter);
1062     }
1063     
1064     @Test 
1065     public void dragSourceShouldGetExitedWhenLeft() {
1066         final Node n = oneNode();
1067         final MouseEventGenerator gen = new MouseEventGenerator();
1068 
1069         dragSource = n;
1070         n.setOnMousePressed(doDetect);
1071         n.setOnDragDetected(stringSource(TransferMode.ANY));
1072         n.setOnDragOver(acceptAny);
1073         n.setOnDragExited(event -> {
1074             counter++;
1075         });
1076 
1077         /* start drag */
1078         n.getScene().impl_processMouseEvent(
1079                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1080         assertEquals(0, counter);
1081         
1082         /* drag */
1083         toolkit.dragTo(52, 52, TransferMode.MOVE);
1084         assertEquals(0, counter);
1085 
1086         toolkit.dragTo(150, 52, TransferMode.MOVE);
1087         assertEquals(1, counter);
1088     }
1089 
1090     @Test
1091     public void dragSourcesSubScenesParentShouldGetExitedWhenLeft() {
1092         final Node[] ns = oneNodeInSubScene();
1093         final Node n = ns[0];
1094         final Node subScene = ns[1];
1095 
1096         dragSource = n;
1097         n.setOnMousePressed(doDetect);
1098         n.setOnDragDetected(stringSource(TransferMode.ANY));
1099         n.setOnDragOver(acceptAny);
1100         subScene.setOnDragExited(event -> {
1101             counter++;
1102         });
1103         subScene.getParent().setOnDragExited(event -> {
1104             counter++;
1105         });
1106 
1107         /* start drag */
1108         n.getScene().impl_processMouseEvent(
1109                 MouseEventGenerator.generateMouseEvent(
1110                     MouseEvent.MOUSE_PRESSED, 50, 50));
1111         assertEquals(0, counter);
1112 
1113         /* drag */
1114         toolkit.dragTo(52, 52, TransferMode.MOVE);
1115         assertEquals(0, counter);
1116 
1117         toolkit.dragTo(250, 52, TransferMode.MOVE);
1118         assertEquals(2, counter);
1119     }
1120 
1121     @Test 
1122     public void dragSourceShouldGetEnteredWhenReturned() {
1123         final Node n = oneNode();
1124         final MouseEventGenerator gen = new MouseEventGenerator();
1125 
1126         dragSource = n;
1127         n.setOnMousePressed(doDetect);
1128         n.setOnDragDetected(stringSource(TransferMode.ANY));
1129         n.setOnDragOver(acceptAny);
1130         n.setOnDragEntered(event -> {
1131             counter++;
1132         });
1133 
1134         /* start drag */
1135         n.getScene().impl_processMouseEvent(
1136                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1137         assertEquals(0, counter);
1138         
1139         /* drag */
1140         toolkit.dragTo(52, 52, TransferMode.MOVE);
1141         assertEquals(1, counter);
1142 
1143         toolkit.dragTo(150, 52, TransferMode.MOVE);
1144         assertEquals(1, counter);
1145 
1146         toolkit.dragTo(60, 52, TransferMode.MOVE);
1147         assertEquals(2, counter);
1148     }
1149     
1150     @Test 
1151     public void anotherNodeShouldGetEntered() {
1152         final Node[] ns = twoNodes();
1153         Node src = ns[0];
1154         Node trgt = ns[1];
1155         final MouseEventGenerator gen = new MouseEventGenerator();
1156 
1157         dragSource = src;
1158         src.setOnMousePressed(doDetect);
1159         src.setOnDragDetected(stringSource(TransferMode.ANY));
1160         src.setOnDragOver(acceptAny);
1161         trgt.setOnDragEntered(event -> {
1162             counter++;
1163         });
1164 
1165         /* start drag */
1166         src.getScene().impl_processMouseEvent(
1167                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1168         assertEquals(0, counter);
1169         
1170         /* drag */
1171         toolkit.dragTo(52, 52, TransferMode.MOVE);
1172         assertEquals(0, counter);
1173 
1174         toolkit.dragTo(250, 52, TransferMode.MOVE);
1175         assertEquals(1, counter);
1176     }
1177     
1178     @Test 
1179     public void anotherNodeShouldGetExited() {
1180         final Node[] ns = twoNodes();
1181         Node src = ns[0];
1182         Node trgt = ns[1];
1183         final MouseEventGenerator gen = new MouseEventGenerator();
1184 
1185         dragSource = src;
1186         src.setOnMousePressed(doDetect);
1187         src.setOnDragDetected(stringSource(TransferMode.ANY));
1188         src.setOnDragOver(acceptAny);
1189         trgt.setOnDragExited(event -> {
1190             counter++;
1191         });
1192 
1193         /* start drag */
1194         src.getScene().impl_processMouseEvent(
1195                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1196         assertEquals(0, counter);
1197         
1198         /* drag */
1199         toolkit.dragTo(52, 52, TransferMode.MOVE);
1200         assertEquals(0, counter);
1201 
1202         toolkit.dragTo(250, 52, TransferMode.MOVE);
1203         assertEquals(0, counter);
1204 
1205         toolkit.dragTo(150, 52, TransferMode.MOVE);
1206         assertEquals(1, counter);
1207     }
1208     
1209     @Test 
1210     public void parentShouldNotGetExitedWhenDraggingOverChildren() {
1211         final Node[] ns = twoNodes();
1212         Node src = ns[0];
1213         Node trgt = ns[1];
1214         final MouseEventGenerator gen = new MouseEventGenerator();
1215 
1216         dragSource = src;
1217         src.setOnMousePressed(doDetect);
1218         src.setOnDragDetected(stringSource(TransferMode.ANY));
1219         src.setOnDragOver(acceptAny);
1220         trgt.getParent().setOnDragExited(event -> {
1221             counter++;
1222         });
1223 
1224         /* start drag */
1225         src.getScene().impl_processMouseEvent(
1226                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1227         assertEquals(0, counter);
1228         
1229         /* drag */
1230         toolkit.dragTo(52, 52, TransferMode.MOVE);
1231         assertEquals(0, counter);
1232 
1233         toolkit.dragTo(250, 52, TransferMode.MOVE);
1234         assertEquals(0, counter);
1235 
1236         toolkit.dragTo(50, 52, TransferMode.MOVE);
1237         assertEquals(0, counter);
1238     }
1239     
1240     @Test 
1241     public void parentShouldGetExitedTargetWhenDraggingOverChildren() {
1242         final Node[] ns = twoNodes();
1243         Node src = ns[0];
1244         Node trgt = ns[1];
1245         final MouseEventGenerator gen = new MouseEventGenerator();
1246 
1247         dragSource = src;
1248         src.setOnMousePressed(doDetect);
1249         src.setOnDragDetected(stringSource(TransferMode.ANY));
1250         src.setOnDragOver(acceptAny);
1251         trgt.getParent().addEventHandler(DragEvent.DRAG_EXITED_TARGET,
1252                 event -> {
1253                     counter++;
1254                 }
1255         );
1256 
1257         /* start drag */
1258         src.getScene().impl_processMouseEvent(
1259                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1260         assertEquals(0, counter);
1261         
1262         /* drag */
1263         toolkit.dragTo(52, 52, TransferMode.MOVE);
1264         assertEquals(0, counter);
1265 
1266         toolkit.dragTo(250, 52, TransferMode.MOVE);
1267         assertEquals(1, counter);
1268 
1269         toolkit.dragTo(50, 52, TransferMode.MOVE);
1270         assertEquals(2, counter);
1271     }
1272     
1273     /************************************************************************/
1274     /*                              DRAGVIEW                                */
1275     /************************************************************************/
1276     @Test
1277     public void startDragShouldNotBeCalledIfNothingPutOnDragboardWithDragView() {
1278         final Node n = oneNode();
1279         final MouseEventGenerator gen = new MouseEventGenerator();
1280         final Image img = new Image("file:testImg_" + 100 + "x" + 100 + ".png");
1281         
1282         n.setOnMousePressed(doDetect);
1283         n.setOnDragDetected(event -> {
1284             Dragboard db = n.startDragAndDrop(TransferMode.COPY);
1285             db.setDragView(img);
1286             db.setDragViewOffsetX(20);
1287             db.setDragViewOffsetX(15);
1288         });
1289 
1290         n.getScene().impl_processMouseEvent(
1291                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1292         n.getScene().impl_processMouseEvent(
1293                 gen.generateMouseEvent(MouseEvent.MOUSE_DRAGGED, 50, 50));
1294         n.getScene().impl_processMouseEvent(
1295                 gen.generateMouseEvent(MouseEvent.MOUSE_RELEASED, 50, 50));
1296 
1297         assertFalse(toolkit.dragging);
1298     }
1299     
1300     @Test
1301     public void startDragShouldBeCalledIfStringPutOnDragboardsWithDragView() {
1302         final Node n = oneNode();
1303         final MouseEventGenerator gen = new MouseEventGenerator();
1304         final Image img = new Image("file:testImg_" + 100 + "x" + 100 + ".png");
1305         
1306         dragSource = n;
1307         n.setOnMousePressed(doDetect);
1308         n.setOnDragDetected(event -> {
1309             Dragboard db = dragSource.startDragAndDrop(TransferMode.ANY);
1310             ClipboardContent cc = new ClipboardContent();
1311             cc.putString("Hello");
1312             db.setContent(cc);
1313             db.setDragView(img);
1314             db.setDragViewOffsetX(20);
1315             db.setDragViewOffsetX(15);
1316         });
1317 
1318         n.getScene().impl_processMouseEvent(
1319                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1320 
1321         assertTrue(toolkit.dragging);
1322     }
1323 
1324     @Test
1325     public void changeDragViewInParentHandlerShouldBePossible() {
1326         final Node n = oneNode();
1327         final Node parent = n.getParent();
1328         final MouseEventGenerator gen = new MouseEventGenerator();
1329         final Image img = new Image("file:testImg_" + 100 + "x" + 100 + ".png");
1330         final Image imgParent = new Image("file:testImg_" + 200 + "x" + 200 + ".png");
1331         
1332         dragSource = n;
1333         n.setOnMousePressed(doDetect);
1334         n.setOnDragDetected(event -> {
1335             Dragboard db = dragSource.startDragAndDrop(TransferMode.ANY);
1336             ClipboardContent cc = new ClipboardContent();
1337             cc.putString("Hello");
1338             db.setContent(cc);
1339             db.setDragView(img);
1340             db.setDragViewOffsetX(20);
1341             db.setDragViewOffsetY(15);
1342         });
1343 
1344         parent.setOnDragDetected(event -> {
1345             Dragboard db = dragSource.startDragAndDrop(TransferMode.ANY);
1346             ClipboardContent cc = new ClipboardContent();
1347             cc.putString("HelloParent");
1348             db.setContent(cc);
1349 
1350             assertEquals(img, db.getDragView());
1351             assertEquals(20, db.getDragViewOffsetX(), 1e-10);
1352             assertEquals(15, db.getDragViewOffsetY(), 1e-10);
1353 
1354             db.setDragView(imgParent);
1355             db.setDragViewOffsetX(40);
1356             db.setDragViewOffsetY(55);
1357 
1358             assertEquals(imgParent, db.getDragView());
1359             assertEquals(40, db.getDragViewOffsetX(), 1e-10);
1360             assertEquals(55, db.getDragViewOffsetY(), 1e-10);
1361         });
1362 
1363         n.getScene().impl_processMouseEvent(
1364                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1365     }
1366 
1367     @Test
1368     public void settingDragViewAndCursorPositionShouldReturnSameResults() {
1369         final Node n = oneNode();
1370         final Node parent = n.getParent();
1371         final MouseEventGenerator gen = new MouseEventGenerator();
1372         final Image img = new Image("file:testImg_" + 100 + "x" + 100 + ".png");
1373         final Image imgParent = new Image("file:testImg_" + 200 + "x" + 200 + ".png");
1374         
1375         dragSource = n;
1376         n.setOnMousePressed(doDetect);
1377         n.setOnDragDetected(event -> {
1378             Dragboard db = dragSource.startDragAndDrop(TransferMode.ANY);
1379             ClipboardContent cc = new ClipboardContent();
1380             cc.putString("Hello");
1381             db.setContent(cc);
1382             db.setDragView(img, 20, 15);
1383         });
1384 
1385         parent.setOnDragDetected(event -> {
1386             Dragboard db = dragSource.startDragAndDrop(TransferMode.ANY);
1387             ClipboardContent cc = new ClipboardContent();
1388             cc.putString("HelloParent");
1389             db.setContent(cc);
1390 
1391             assertEquals(img, db.getDragView());
1392             assertEquals(20, db.getDragViewOffsetX(), 1e-10);
1393             assertEquals(15, db.getDragViewOffsetY(), 1e-10);
1394 
1395             db.setDragView(imgParent);
1396             db.setDragViewOffsetX(40);
1397             db.setDragViewOffsetY(55);
1398 
1399             assertEquals(imgParent, db.getDragView());
1400             assertEquals(40, db.getDragViewOffsetX(), 1e-10);
1401             assertEquals(55, db.getDragViewOffsetY(), 1e-10);
1402         });
1403 
1404         n.getScene().impl_processMouseEvent(
1405                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1406     }
1407 
1408     @Test
1409     public void dragViewShouldBeClearedInSubsequentDragDetectedCall() {
1410         final Node n = oneNode();
1411         final MouseEventGenerator gen = new MouseEventGenerator();
1412         final Image img = new Image("file:testImg_" + 100 + "x" + 100 + ".png");
1413         
1414         dragSource = n;
1415         n.setOnMousePressed(doDetect);
1416         n.setOnDragDetected(event -> {
1417             Dragboard db = dragSource.startDragAndDrop(TransferMode.ANY);
1418 
1419             assertNull(db.getDragView());
1420             assertEquals(0, db.getDragViewOffsetX(), 1e-10);
1421             assertEquals(0, db.getDragViewOffsetY(), 1e-10);
1422 
1423             ClipboardContent cc = new ClipboardContent();
1424             cc.putString("Hello");
1425             db.setContent(cc);
1426             db.setDragView(img);
1427             db.setDragViewOffsetX(20);
1428             db.setDragViewOffsetX(15);
1429         });
1430 
1431         n.getScene().impl_processMouseEvent(
1432                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1433         n.getScene().impl_processMouseEvent(
1434                 gen.generateMouseEvent(MouseEvent.MOUSE_DRAGGED, 40, 40));
1435         n.getScene().impl_processMouseEvent(
1436                 gen.generateMouseEvent(MouseEvent.MOUSE_RELEASED, 55, 55));
1437         n.getScene().impl_processMouseEvent(
1438                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 81, 81));
1439     }
1440     
1441     /************************************************************************/
1442     /*                             PICK RESULT                              */
1443     /************************************************************************/
1444 
1445     @Test
1446     public void shouldCompute3dCoordinates() {
1447         Node n = twoNodes()[0];
1448         n.setTranslateZ(50);
1449         dragSource = n;
1450 
1451         MouseEventGenerator gen = new MouseEventGenerator();
1452 
1453         counter = 0;
1454         n.setOnMousePressed(doDetect);
1455         n.setOnDragDetected(stringSource(TransferMode.ANY));
1456         n.setOnDragOver(event -> {
1457             counter++;
1458             Assert.assertEquals(52, event.getX(), 0.00001);
1459             Assert.assertEquals(52, event.getY(), 0.00001);
1460             Assert.assertEquals(0, event.getZ(), 0.00001);
1461         });
1462 
1463         n.getScene().setOnDragOver(event -> {
1464             counter++;
1465             Assert.assertEquals(52, event.getX(), 0.00001);
1466             Assert.assertEquals(52, event.getY(), 0.00001);
1467             Assert.assertEquals(50, event.getZ(), 0.00001);
1468         });
1469 
1470         n.getScene().impl_processMouseEvent(
1471                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1472         toolkit.dragTo(52, 52, TransferMode.COPY);
1473         toolkit.drop(252, 52, TransferMode.COPY);
1474         toolkit.done(TransferMode.COPY);
1475 
1476         assertEquals(2, counter);
1477     }
1478 
1479     @Test
1480     public void dragEventsHavePickResult() {
1481         final Node[] nodes = twoNodes();
1482         final Node n1 = nodes[0];
1483         final Node n2 = nodes[1];
1484         final MouseEventGenerator gen = new MouseEventGenerator();
1485 
1486         dragSource = n1;
1487         n1.setOnMousePressed(doDetect);
1488         n1.setOnDragDetected(stringSource(TransferMode.ANY));
1489         n1.setOnDragOver(event -> {
1490             PickResult pickRes = event.getPickResult();
1491             assertNotNull(pickRes);
1492             assertSame(n1, pickRes.getIntersectedNode());
1493             assertEquals(52, pickRes.getIntersectedPoint().getX(), 0.00001);
1494             assertEquals(52, pickRes.getIntersectedPoint().getY(), 0.00001);
1495             assertEquals(0, pickRes.getIntersectedPoint().getZ(), 0.00001);
1496             counter++;
1497         });
1498         EventHandler<DragEvent> switchNodeHandler = event -> {
1499             PickResult pickRes = event.getPickResult();
1500             assertNotNull(pickRes);
1501             assertSame(n2, pickRes.getIntersectedNode());
1502             assertEquals(252, pickRes.getIntersectedPoint().getX(), 0.00001);
1503             assertEquals(52, pickRes.getIntersectedPoint().getY(), 0.00001);
1504             assertEquals(0, pickRes.getIntersectedPoint().getZ(), 0.00001);
1505             event.acceptTransferModes(TransferMode.COPY);
1506             counter++;
1507         };
1508         n1.setOnDragExited(switchNodeHandler);
1509         n2.setOnDragEntered(switchNodeHandler);
1510         n2.setOnDragOver(switchNodeHandler);
1511         n2.setOnDragDropped(switchNodeHandler);
1512         n1.setOnDragDone(event -> {
1513             PickResult pickRes = event.getPickResult();
1514             assertNotNull(pickRes);
1515             assertNull(pickRes.getIntersectedNode());
1516             assertEquals(0, pickRes.getIntersectedPoint().getX(), 0.00001);
1517             assertEquals(0, pickRes.getIntersectedPoint().getY(), 0.00001);
1518             assertEquals(0, pickRes.getIntersectedPoint().getZ(), 0.00001);
1519             counter++;
1520         });
1521 
1522         n1.getScene().impl_processMouseEvent(
1523                 gen.generateMouseEvent(MouseEvent.MOUSE_PRESSED, 50, 50));
1524         toolkit.dragTo(52, 52, TransferMode.COPY);
1525         toolkit.dragTo(252, 52, TransferMode.COPY);
1526         toolkit.drop(252, 52, TransferMode.COPY);
1527         toolkit.done(TransferMode.COPY);
1528 
1529         assertEquals(6, counter);
1530     }
1531 
1532 
1533     /************************************************************************/
1534     /*                             HELPER CODE                              */
1535     /************************************************************************/
1536     
1537     // Event handlers
1538     
1539     private final EventHandler<MouseEvent> dontDetect =
1540             event -> event.setDragDetect(false);
1541 
1542     private final EventHandler<MouseEvent> doDetect =
1543             event -> event.setDragDetect(true);
1544     
1545     private final EventHandler<MouseEvent> detector = 
1546             new EventHandler<MouseEvent>() {
1547         @Override public void handle(MouseEvent event) {
1548             detected = true;
1549         }
1550     };
1551     
1552     private EventHandler<MouseEvent> stringSource(final TransferMode... tms) { 
1553         return event -> {
1554             Dragboard db = dragSource.startDragAndDrop(tms);
1555             ClipboardContent cc = new ClipboardContent();
1556             cc.putString("Hello");
1557             db.setContent(cc);
1558         };
1559     }
1560     
1561     private final EventHandler<DragEvent> acceptAny =
1562             event -> event.acceptTransferModes(TransferMode.ANY);
1563 
1564     private final EventHandler<DragEvent> acceptCopyOrMove =
1565             event -> event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
1566     
1567     private final EventHandler<DragEvent> acceptCopy =
1568             event -> event.acceptTransferModes(TransferMode.COPY);
1569     
1570     // Scenes
1571 
1572     private static Node oneNode() {
1573         Group root = new Group();
1574         getScene(root);
1575         
1576         Rectangle r = new Rectangle(100, 100);
1577         root.getChildren().add(r);
1578         return r;
1579     }
1580     
1581     private static Node[] twoNodes() {
1582         Group root = new Group();
1583         getScene(root);
1584         
1585         Rectangle r = new Rectangle(100, 100);
1586         root.getChildren().add(r);
1587 
1588         Rectangle r2 = new Rectangle(200, 0, 100, 100);
1589         root.getChildren().add(r2);
1590         return new Node[] { r, r2 };
1591     }
1592 
1593     private static Node[] oneNodeInSubScene() {
1594         Group root = new Group();
1595         getScene(root);
1596 
1597         Rectangle r = new Rectangle(100, 100);
1598         SubScene subScene = new SubScene(new Group(r), 200, 200);
1599         root.getChildren().add(subScene);
1600 
1601         return new Node[] { subScene, r };
1602     }
1603 
1604 
1605     private static Scene getScene(Group root) {
1606         final Scene scene = new Scene(root, 400, 400);
1607 
1608         Stage stage = new Stage();
1609         stage.setScene(scene);
1610         stage.show();
1611 
1612         return scene;
1613     }
1614     
1615     // Mock toolkit
1616     
1617     private class ClipboardImpl implements TKClipboard {
1618 
1619         private List<Pair<DataFormat, Object>> content;
1620         private Set<TransferMode> transferModes;
1621         private Image image;
1622         private double offsetX;
1623         private double offsetY;
1624 
1625         @Override
1626         public void setSecurityContext(AccessControlContext ctx) {
1627         }
1628 
1629         @Override
1630         public Object getContent(DataFormat df) {
1631             for (Pair<DataFormat, Object> pair : content) {
1632                 if (pair.getKey() == df) {
1633                     return pair.getValue();
1634                 }
1635             }
1636             return null;
1637         }
1638 
1639         @Override
1640         public Set<DataFormat> getContentTypes() {
1641             Set<DataFormat> types = new HashSet<DataFormat>();
1642             for (Pair<DataFormat, Object> pair : content) {
1643                 types.add(pair.getKey());
1644             }
1645             return types;
1646         }
1647 
1648         @Override
1649         public Set<TransferMode> getTransferModes() {
1650             return transferModes;
1651         }
1652 
1653         public void setTransferModes(Set<TransferMode> tms) {
1654             this.transferModes = tms;
1655         }
1656 
1657         @Override
1658         public boolean hasContent(DataFormat df) {
1659             return content != null && !content.isEmpty();
1660         }
1661 
1662         @Override
1663         public boolean putContent(Pair<DataFormat, Object>... pairs) {
1664             content = new ArrayList<Pair<DataFormat, Object>>();
1665             content.addAll(Arrays.asList(pairs));
1666             return true;
1667         }
1668         
1669         @Override
1670         public void setDragView(Image image) {
1671             this.image = image;
1672         }
1673 
1674         @Override
1675         public void setDragViewOffsetX(double offsetX) {
1676             this.offsetX = offsetX;
1677         }
1678 
1679         @Override
1680         public void setDragViewOffsetY(double offsetY) {
1681             this.offsetY = offsetY;
1682         }
1683 
1684         @Override
1685         public Image getDragView() {
1686             return image;
1687         }
1688 
1689         @Override
1690         public double getDragViewOffsetX() {
1691             return offsetX;
1692         }
1693 
1694         @Override
1695         public double getDragViewOffsetY() {
1696             return offsetY;
1697         }
1698 
1699         public void flush() {
1700             image = null;
1701             offsetX = offsetY = 0;
1702         }
1703     }
1704     
1705     private class DndToolkit implements StubToolkit.DndDelegate {
1706 
1707         boolean dragging = false;
1708         TKDragSourceListener srcListener;
1709         TKDragGestureListener gstrListener;
1710         TKDropTargetListener trgListener;
1711         TKClipboard db;
1712 
1713         @Override
1714         public void registerListener(TKDragGestureListener l) {
1715             this.gstrListener = l;
1716         }
1717 
1718         @Override
1719         public void enableDrop(TKDropTargetListener l) {
1720             this.trgListener = l;
1721         }
1722         
1723         
1724         @Override
1725         public TKClipboard createDragboard() {
1726             db = new ClipboardImpl();
1727             return db;
1728         }
1729 
1730         @Override
1731         public void startDrag(TKScene scene, Set<TransferMode> tm, 
1732                 TKDragSourceListener l, Dragboard dragboard) {
1733             ((ClipboardImpl)db).setTransferModes(tm);
1734             ((ClipboardImpl)db).flush();
1735             dragging = true;
1736             srcListener = l;
1737         }
1738 
1739         @Override
1740         public DragEvent convertDragEventToFx(Object event, Dragboard dragboard) {
1741             DragEvent de = (DragEvent) event;
1742             return new DragEvent(de.getSource(), de.getTarget(), de.getEventType(),
1743                     dragboard, de.getSceneX(), de.getSceneY(),
1744                     de.getScreenX(), de.getScreenY(), de.getTransferMode(),
1745                     de.getGestureSource(), de.getGestureTarget(), de.getPickResult());
1746         }
1747         
1748         public TransferMode dragTo(double x, double y, TransferMode tm) {
1749             return trgListener.dragOver(x, y, x, y, tm);
1750         }
1751         
1752         public TransferMode drop(double x, double y, TransferMode tm) {
1753             return trgListener.drop(x, y, x, y, tm);
1754         }
1755         
1756         public void done(TransferMode tm) {
1757             srcListener.dragDropEnd(0, 0, 0, 0, tm);
1758         }
1759         
1760         public void stopDrag() {
1761             dragging = false;
1762         }
1763         
1764     }
1765 }