1 /* 2 * Copyright (c) 2011, 2015, 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.scene.input; 27 28 import java.util.EnumSet; 29 import java.util.Set; 30 31 import javafx.beans.NamedArg; 32 import javafx.event.Event; 33 import javafx.event.EventTarget; 34 import javafx.event.EventType; 35 import javafx.geometry.Point3D; 36 37 import com.sun.javafx.scene.input.InputEventUtils; 38 import java.io.IOException; 39 40 // PENDING_DOC_REVIEW 41 /** 42 * Drag events replace mouse events during drag-and-drop gesture. 43 * The difference between press-drag-release and drag-and-drop gestures 44 * is described at {@link javafx.scene.input.MouseEvent MouseEvent}. 45 * <p> 46 * Drag and drop gesture can be started by calling {@code startDragAndDrop()} 47 * (on a node or scene) inside of a {@link MouseEvent#DRAG_DETECTED DRAG_DETECTED} event handler. 48 * The data to be transfered to drop target are placed to a {@code dragBoard} 49 * at this moment. 50 * <p> 51 * Drag entered/exited events behave similarly to mouse entered/exited 52 * events, please see {@code MouseEvent} overview. 53 * <p> 54 * 55 * <br><h4>Drag sources: initiating a drag and drop gesture</h4> 56 * 57 * When a drag gesture is detected, an application can decide whether to 58 * start a drag and drop gesture or continue with a press-drag-release gesture. 59 * <p> 60 * The default drag detection mechanism uses mouse movements with a pressed 61 * button in combination with hysteresis. This behavior can be 62 * augmented by the application. Each {@code MOUSE_PRESSED} and 63 * {@code MOUSE_DRAGGED} event has a {@code dragDetect} flag that determines 64 * whether a drag gesture has been detected. The default value of this flag 65 * depends on the default detection mechanism and can be modified by calling 66 * {@code setDragDetect()} inside of an event handler. When processing of 67 * one of these events ends with the {@code dragDetect} flag set to true, 68 * a {@code DRAG_DETECTED} {@code MouseEvent} is sent to the potential gesture 69 * source (the object on which a mouse button has been pressed). This event 70 * notifies about the gesture detection. 71 * <p> 72 * Inside a {@code DRAG_DETECTED} event handler, if the 73 * {@code startDragAndDrop()} method is called on a node or scene and a dragged 74 * data is made available to the returned {@code Dragboard}, the object on which 75 * {@code startDragAndDrop()} has been called is considred a gesture source 76 * and the drag and drop gesture is started. The {@code Dragboard} has system 77 * clipboard functionality but is specifically used for drag and drop data 78 * transfer. 79 * <p> 80 * The {@code startDragAndDrop()} method takes a set of {@code TransferMode}s 81 * supported by the gesture source. For instance passing only 82 * {@code TransferMode.COPY} indicates that the gesture source allows only 83 * copying of the data, not moving or referencing. 84 * <p> 85 * Following example shows a simple drag and drop source: 86 * <code><pre> 87 Rectangle rect = new Rectangle(100, 100); 88 rect.setOnDragDetected(new EventHandler<MouseEvent>() { 89 @Override public void handle(MouseEvent event) { 90 Dragboard db = startDragAndDrop(TransferMode.ANY); 91 ClipboardContent content = new ClipboardContent(); 92 content.putString("Hello!"); 93 db.setContent(content); 94 event.consume(); 95 } 96 }); 97 * </pre></code> 98 * 99 * <br><h4>Potential drop targets</h4> 100 * 101 * <p> 102 * After the drag and drop gesture has been started, any object 103 * ({@code Node}, {@code Scene}) over which the mouse is dragged is 104 * a potential drop target. 105 * <p> 106 * When the mouse is dragged into the boundaries of potential drop target, 107 * the potential target gets a {@code DRAG_ENTERED} event. When the mouse is 108 * dragged outside of the potential target's bounds, it gets a 109 * {@code DRAG_EXITED} event. There are also the bubbling 110 * {@code DRAG_ENTERED_TARGET} and {@code DRAG_EXITED_TARGET} variants. They 111 * behave similarly to mouse entered/exited events, please see 112 * {@code MouseEvent} overview. 113 * <p> 114 * A potential drop target can decide to change its appearance to 115 * let the user know that the dragged data can be dropped on it. This can be 116 * done in a {@code DRAG_OVER} event handler, based on the position of the 117 * mouse. Another option is to change the potential target's appearance in 118 * a {@code DRAG_ENTERED} and {@code DRAG_EXITED} handlers. 119 * <p> 120 * In {@code DRAG_OVER} event handler a potential drop target has the ability 121 * to make it known that it is an actual target. This is done by calling 122 * {@code acceptTransferModes(TransferMode...)} on the event, 123 * passing transfer modes it is willing to accept. 124 * If it <i>is not called</i> during the event delivery or if none of the 125 * passed transfer modes is supported by gesture source, then the potential 126 * drop target <i>is not considered to be an actual drop target</i>. 127 * <p> 128 * When deciding weather to accept the event by calling {@code acceptTransferModes(TransferMode...)}, 129 * the type of data available on the {@code Dragboard} should be considered. 130 * Access to the {@code Dragboard} is provided by the {@code getDragboard()} 131 * method. 132 * <p> 133 * When accepting an event, the potential gesture target decides which 134 * {@code TransferMode} is accepted for the operation. To make the decision, 135 * {@code DragBoard.getTransferModes()} (set of transfer modes supported by 136 * the gesture source) and {@code DragEvent.getTransferMode()} (default 137 * transfer mode issued by platform, driven by key modifiers) can be used. 138 * It is poosible to pass more transfer modes into the 139 * {@code acceptTransferModes(TransferMode...)} method. In this case 140 * it makes the decision in behalf of the 141 * application (it chooses the default mode if it's supported by gesture source 142 * and accepted by gesture target, otherwise it chooses the most common mode 143 * of the supported and accepted ones). 144 * The {@code DRAG_DROPPED} event's {@code getTransferMode()} later reports the 145 * transfer mode accepted by the {@code DRAG_OVER} event handler. 146 * <p> 147 * A drag and drop gesture ends when the mouse button is released. 148 * If this happens over a gesture target that accepted previous {@code DRAG_OVER} 149 * events with a transfer mode supported by gesture source, 150 * a {@code DRAG_DROPPED} event is sent to the gesture target. 151 * In its handler, the gesture target can access the data on the dragboard. 152 * After data has been transferred (or decided not to transfer), the gesture 153 * needs to be completed by calling {@code setDropCompleted(Boolean)} on the event. 154 * The {@code Boolean} argument indicates if the data has been transferred 155 * successfully or not. If it is not called, the gesture is considered 156 * unsuccessful. 157 * 158 * <p> 159 * Following example shows a simple drag and drop target for text data: 160 * <code><pre> 161 Rectangle rect = new Rectangle(100, 100); 162 163 rect.setOnDragOver(new EventHandler<DragEvent>() { 164 @Override public void handle(DragEvent event) { 165 Dragboard db = event.getDragboard(); 166 if (db.hasString()) { 167 event.acceptTransferModes(TransferMode.COPY_OR_MOVE); 168 } 169 event.consume(); 170 } 171 }); 172 173 rect.setOnDragDropped(new EventHandler<DragEvent>() { 174 @Override public void handle(DragEvent event) { 175 Dragboard db = event.getDragboard(); 176 boolean success = false; 177 if (db.hasString()) { 178 System.out.println("Dropped: " + db.getString()); 179 success = true; 180 } 181 event.setDropCompleted(success); 182 event.consume(); 183 } 184 }); 185 * </pre></code> 186 * 187 * <br><h4>Drag sources: finalizing drag and drop gesture</h4> 188 * 189 * <p> 190 * After the gesture has been finished, whether by successful or unsuccessful 191 * data transfer or being canceled, the {@code DRAG_DONE} event is sent to 192 * the gesture source. The {@code getTransferMode()} method of the event 193 * indicates to the gesture source how the transfer of data was completed. 194 * If the transfer mode has the value {@code MOVE}, then this allows the source 195 * to clear out its data. Clearing the source's data gives the appropriate 196 * appearance to a user that the data has been moved by the drag and drop 197 * gesture. If it has the value {@code null}, then the drag and drop gesture 198 * ended without any data being transferred. This could happen as a result of 199 * a mouse release event over a node that is not a drop target, or the user 200 * pressing the ESC key to cancel the drag and drop gesture, or by 201 * the gesture target reporting an unsuccessful data transfer. 202 * </p> 203 * @since JavaFX 2.0 204 */ 205 public final class DragEvent extends InputEvent { 206 207 private static final long serialVersionUID = 20121107L; 208 209 /** 210 * Common supertype for all drag event types. 211 */ 212 public static final EventType<DragEvent> ANY = 213 new EventType<DragEvent>(InputEvent.ANY, "DRAG"); 214 215 /** 216 * This event occurs when drag gesture enters a node. It's the 217 * bubbling variant, which is delivered also to all parents of the 218 * entered node (unless it was consumed). When notifications about 219 * entering some of node's children are not desired, 220 * {@code DRAG_ENTERED} event handler should be used. 221 * 222 * @see MouseEvent MouseEvent for more information about mouse entered/exited handling 223 * which is similar 224 */ 225 public static final EventType<DragEvent> DRAG_ENTERED_TARGET = 226 new EventType<DragEvent>(DragEvent.ANY, "DRAG_ENTERED_TARGET"); 227 228 /** 229 * This event occurs when drag gesture enters a node. 230 * This event type is delivered only to the entered node, 231 * if parents want to filter it or get the bubbling event, 232 * they need to use {@code DRAG_ENTERED_TARGET}. 233 * 234 * @see MouseEvent MouseEvent for more information about mouse entered/exited handling 235 * which is similar 236 */ 237 public static final EventType<DragEvent> DRAG_ENTERED = 238 new EventType<DragEvent>(DragEvent.DRAG_ENTERED_TARGET, "DRAG_ENTERED"); 239 240 /** 241 * This event occurs when drag gesture exits a node. It's the 242 * bubbling variant, which is delivered also to all parents of the 243 * eixited node (unless it was consumed). When notifications about 244 * exiting some of node's children are not desired, 245 * {@code DRAG_EXITED} event handler should be used. 246 * 247 * @see MouseEvent MouseEvent for more information about mouse entered/exited handling 248 * which is similar 249 */ 250 public static final EventType<DragEvent> DRAG_EXITED_TARGET = 251 new EventType<DragEvent>(DragEvent.ANY, "DRAG_EXITED_TARGET"); 252 253 /** 254 * This event occurs when drag gesture exits a node. 255 * This event type is delivered only to the exited node, 256 * if parents want to filter it or get the bubbling event, 257 * they need to use {@code DRAG_EXITED_TARGET}. 258 * 259 * @see MouseEvent MouseEvent for more information about mouse entered/exited handling 260 * which is similar 261 */ 262 public static final EventType<DragEvent> DRAG_EXITED = 263 new EventType<DragEvent>(DragEvent.DRAG_EXITED_TARGET, "DRAG_EXITED"); 264 265 /** 266 * This event occurs when drag gesture progresses within this node. 267 */ 268 public static final EventType<DragEvent> DRAG_OVER = 269 new EventType<DragEvent>(DragEvent.ANY, "DRAG_OVER"); 270 271 // Do we want DRAG_TRANSFER_MODE_CHANGED event? 272 // /** 273 // * This event occurs on a potential drag-and-drop target when the user 274 // * takes action to change the intended {@code TransferMode}. 275 // * The user can change the intended {@link TransferMode} by holding down 276 // * or releasing key modifiers. 277 // */ 278 // public static final EventType<DragEvent> DRAG_TRANSFER_MODE_CHANGED = 279 // new EventType<DragEvent>(DragEvent.ANY, "DRAG_TRANSFER_MODE_CHANGED"); 280 281 /** 282 * This event occurs when the mouse button is released during drag and drop 283 * gesture on a drop target. Transfer of data from the 284 * {@link DragEvent}'s {@link DragEvent#dragboard dragboard} should happen 285 * in handler of this event. 286 */ 287 public static final EventType<DragEvent> DRAG_DROPPED = 288 new EventType<DragEvent>(DragEvent.ANY, "DRAG_DROPPED"); 289 290 /** 291 * This event occurs on drag-and-drop gesture source after its data has 292 * been dropped on a drop target. The {@code transferMode} of the 293 * event shows what just happened at the drop target. 294 * If {@code transferMode} has the value {@code MOVE}, then the source can 295 * clear out its data. Clearing the source's data gives the appropriate 296 * appearance to a user that the data has been moved by the drag and drop 297 * gesture. A {@code transferMode} that has the value {@code NONE} 298 * indicates that no data was transferred during the drag and drop gesture. 299 */ 300 public static final EventType<DragEvent> DRAG_DONE = 301 new EventType<DragEvent>(DragEvent.ANY, "DRAG_DONE"); 302 303 /** 304 * Creates a copy of the given drag event with the given fields substituted. 305 * @param source the new source of the copied event 306 * @param target the new target of the copied event 307 * @param gestureSource the new gesture source. 308 * @param gestureTarget the new gesture target. 309 * @param eventType the new eventType 310 * @return the event copy with the fields 311 * @since JavaFX 8.0 312 */ 313 public DragEvent copyFor(Object source, EventTarget target, 314 Object gestureSource, Object gestureTarget, 315 EventType<DragEvent> eventType) { 316 317 DragEvent copyEvent = copyFor(source, target, eventType); 318 recomputeCoordinatesToSource(copyEvent, source); 319 copyEvent.gestureSource = gestureSource; 320 copyEvent.gestureTarget = gestureTarget; 321 return copyEvent; 322 } 323 324 /** 325 * Constructs new DragEvent event. 326 * For DRAG_DROPPED and DRAG_DONE event types, the {@code accepted} state 327 * and {@code acceptedTransferMode} are set according to the passed 328 * {@code transferMode}. 329 * @param source the source of the event. Can be null. 330 * @param target the target of the event. Can be null. 331 * @param eventType The type of the event. 332 * @param dragboard the dragboard of the event. 333 * @param x The x with respect to the scene. 334 * @param y The y with respect to the scene. 335 * @param screenX The x coordinate relative to screen. 336 * @param screenY The y coordinate relative to screen. 337 * @param transferMode the transfer mode of the event. 338 * @param gestureSource the source of the DnD gesture of the event. 339 * @param gestureTarget the target of the DnD gesture of the event. 340 * @param pickResult pick result. Can be null, in this case a 2D pick result 341 * without any further values is constructed 342 * based on the scene coordinates and the target 343 * @since JavaFX 8.0 344 */ 345 public DragEvent(@NamedArg("source") Object source, @NamedArg("target") EventTarget target, @NamedArg("eventType") EventType<DragEvent> eventType, @NamedArg("dragboard") Dragboard dragboard, 346 @NamedArg("x") double x, @NamedArg("y") double y, 347 @NamedArg("screenX") double screenX, @NamedArg("screenY") double screenY, @NamedArg("transferMode") TransferMode transferMode, 348 @NamedArg("gestureSource") Object gestureSource, @NamedArg("gestureTarget") Object gestureTarget, @NamedArg("pickResult") PickResult pickResult) { 349 super(source, target, eventType); 350 this.gestureSource = gestureSource; 351 this.gestureTarget = gestureTarget; 352 this.x = x; 353 this.y = y; 354 this.screenX = screenX; 355 this.screenY = screenY; 356 this.sceneX = x; 357 this.sceneY = y; 358 this.transferMode = transferMode; 359 this.dragboard = dragboard; 360 361 if (eventType == DragEvent.DRAG_DROPPED 362 || eventType == DragEvent.DRAG_DONE) { 363 state.accepted = transferMode != null; 364 state.acceptedTransferMode = transferMode; 365 state.acceptingObject = state.accepted ? source : null; 366 } 367 368 this.pickResult = pickResult != null ? pickResult : new PickResult( 369 eventType == DRAG_DONE ? null : target, x, y); 370 final Point3D p = InputEventUtils.recomputeCoordinates(this.pickResult, null); 371 this.x = p.getX(); 372 this.y = p.getY(); 373 this.z = p.getZ(); 374 } 375 376 /** 377 * Constructs new DragEvent event with empty source and target. 378 * @param eventType The type of the event. 379 * @param dragboard the dragboard of the event. 380 * @param x The x with respect to the scene. 381 * @param y The y with respect to the scene. 382 * @param screenX The x coordinate relative to screen. 383 * @param screenY The y coordinate relative to screen. 384 * @param transferMode the transfer mode of the event. 385 * @param gestureSource the source of the DnD gesture of the event. 386 * @param gestureTarget the target of the DnD gesture of the event. 387 * @param pickResult pick result. Can be null, in this case a 2D pick result 388 * without any further values is constructed 389 * based on the scene coordinates 390 * @since JavaFX 8.0 391 */ 392 public DragEvent(@NamedArg("eventType") EventType<DragEvent> eventType, @NamedArg("dragboard") Dragboard dragboard, 393 @NamedArg("x") double x, @NamedArg("y") double y, 394 @NamedArg("screenX") double screenX, @NamedArg("screenY") double screenY, @NamedArg("transferMode") TransferMode transferMode, 395 @NamedArg("gestureSource") Object gestureSource, @NamedArg("gestureTarget") Object gestureTarget, @NamedArg("pickResult") PickResult pickResult) { 396 this(null, null, eventType, dragboard, x, y, screenX, screenY, transferMode, 397 gestureSource, gestureTarget, pickResult); 398 } 399 400 /** 401 * Fills the given event by this event's coordinates recomputed to the given 402 * source object 403 * @param newEvent Event whose coordinates are to be filled 404 * @param newSource Source object to compute coordinates for 405 */ 406 private void recomputeCoordinatesToSource(DragEvent newEvent, Object newSource) { 407 408 if (newEvent.getEventType() == DRAG_DONE) { 409 // DRAG_DONE contains all zeros, doesn't make sense to recompute it 410 return; 411 } 412 413 final Point3D newCoordinates = InputEventUtils.recomputeCoordinates( 414 pickResult, newSource); 415 416 newEvent.x = newCoordinates.getX(); 417 newEvent.y = newCoordinates.getY(); 418 newEvent.z = newCoordinates.getZ(); 419 } 420 421 @Override 422 public DragEvent copyFor(Object newSource, EventTarget newTarget) { 423 DragEvent e = (DragEvent) super.copyFor(newSource, newTarget); 424 recomputeCoordinatesToSource(e, newSource); 425 return e; 426 } 427 428 /** 429 * Creates a copy of the given drag event with the given fields substituted. 430 * @param source the new source of the copied event 431 * @param target the new target of the copied event 432 * @param eventType the new eventType 433 * @return the event copy with the fields 434 * @since JavaFX 8.0 435 */ 436 public DragEvent copyFor(Object source, EventTarget target, EventType<DragEvent> type) { 437 DragEvent e = (DragEvent) copyFor(source, target); 438 e.eventType = type; 439 return e; 440 } 441 442 @Override 443 public EventType<DragEvent> getEventType() { 444 return (EventType<DragEvent>) super.getEventType(); 445 } 446 447 /** 448 * Horizontal x position of the event relative to the 449 * origin of the MouseEvent's node. 450 */ 451 private transient double x; 452 453 /** 454 * Horizontal position of the event relative to the 455 * origin of the DragEvent's source. 456 * 457 * @return horizontal position of the event relative to the 458 * origin of the DragEvent's source. 459 */ 460 public final double getX() { 461 return x; 462 } 463 464 /** 465 * Vertical y position of the event relative to the 466 * origin of the MouseEvent's node. 467 */ 468 private transient double y; 469 470 /** 471 * Vertical position of the event relative to the 472 * origin of the DragEvent's source. 473 * 474 * @return vertical position of the event relative to the 475 * origin of the DragEvent's source. 476 */ 477 public final double getY() { 478 return y; 479 } 480 481 /** 482 * Depth z position of the event relative to the 483 * origin of the MouseEvent's node. 484 */ 485 private transient double z; 486 487 /** 488 * Depth position of the event relative to the 489 * origin of the MouseEvent's source. 490 * 491 * @return depth position of the event relative to the 492 * origin of the MouseEvent's source. 493 * @since JavaFX 8.0 494 */ 495 public final double getZ() { 496 return z; 497 } 498 499 /** 500 * Absolute horizontal x position of the event. 501 */ 502 private final double screenX; 503 504 /** 505 * Returns absolute horizontal position of the event. 506 * @return absolute horizontal position of the event 507 */ 508 public final double getScreenX() { 509 return screenX; 510 } 511 512 /** 513 * Absolute vertical y position of the event. 514 */ 515 private final double screenY; 516 517 /** 518 * Returns absolute vertical position of the event. 519 * @return absolute vertical position of the event 520 */ 521 public final double getScreenY() { 522 return screenY; 523 } 524 525 /** 526 * Horizontal x position of the event relative to the 527 * origin of the {@code Scene} that contains the DragEvent's node. 528 * If the node is not in a {@code Scene}, then the value is relative to 529 * the boundsInParent of the root-most parent of the DragEvent's node. 530 */ 531 private final double sceneX; 532 533 /** 534 * Returns horizontal position of the event relative to the 535 * origin of the {@code Scene} that contains the DragEvent's source. 536 * If the node is not in a {@code Scene}, then the value is relative to 537 * the boundsInParent of the root-most parent of the DragEvent's node. 538 * Note that in 3D scene, this represents the flat coordinates after 539 * applying the projection transformations. 540 * 541 * @return horizontal position of the event relative to the 542 * origin of the {@code Scene} that contains the DragEvent's source 543 */ 544 public final double getSceneX() { 545 return sceneX; 546 } 547 548 /** 549 * Vertical y position of the event relative to the 550 * origin of the {@code Scene} that contains the DragEvent's node. 551 * If the node is not in a {@code Scene}, then the value is relative to 552 * the boundsInParent of the root-most parent of the DragEvent's node. 553 */ 554 private final double sceneY; 555 556 /** 557 * Returns vertical position of the event relative to the 558 * origin of the {@code Scene} that contains the DragEvent's source. 559 * If the node is not in a {@code Scene}, then the value is relative to 560 * the boundsInParent of the root-most parent of the DragEvent's node. 561 * Note that in 3D scene, this represents the flat coordinates after 562 * applying the projection transformations. 563 * 564 * @return vertical position of the event relative to the 565 * origin of the {@code Scene} that contains the DragEvent's source 566 */ 567 public final double getSceneY() { 568 return sceneY; 569 } 570 571 /** 572 * Information about the pick if the picked {@code Node} is a 573 * {@code Shape3D} node and its pickOnBounds is false. 574 */ 575 private PickResult pickResult; 576 577 /** 578 * Returns information about the pick. 579 * 580 * @return new PickResult object that contains information about the pick 581 * @since JavaFX 8.0 582 */ 583 public final PickResult getPickResult() { 584 return pickResult; 585 } 586 587 /** 588 * The source object of the drag and drop gesture. 589 * Gesture source is the object that started drag and drop operation. 590 * The value {@code null} is valid in the case that the gesture comes 591 * from another application. 592 */ 593 public final Object getGestureSource() { return gestureSource; } 594 private Object gestureSource; 595 596 /** 597 * The target object of the drag and drop gesture. 598 * Gesture target is the object that accepts drag events. 599 * The value {@code null} is valid in the case that the drag and drop 600 * gesture has been canceled or completed without a transfer taking place 601 * or there is currently no event target accepting the drag events. 602 */ 603 public final Object getGestureTarget() { return gestureTarget; } 604 private Object gestureTarget; 605 606 /** 607 * Data transfer mode. Before the data transfer is is performed, 608 * this is the default transfer mode set by system according to 609 * input events such as the user holding some modifiers. 610 * In time of data transfer (in DRAG_DROPPED event) it determines 611 * the transfer mode accepted by previous DRAG_OVER handler. 612 * After the data transfer (in DRAG_DONE event) 613 * it determines the actual mode of the transfer done. 614 */ 615 public final TransferMode getTransferMode() { return transferMode; } 616 private TransferMode transferMode; 617 618 private final State state = new State(); 619 620 /** 621 * Indicates if this event has been accepted. 622 * @see #acceptTransferModes 623 * @defaultValue false 624 */ 625 public final boolean isAccepted() { return state.accepted; } 626 627 /** 628 * Gets transfer mode accepted by potential target. 629 * @return transfer mode accepted by potential target. 630 */ 631 public final TransferMode getAcceptedTransferMode() { 632 return state.acceptedTransferMode; 633 } 634 635 /** 636 * The object that accepted the drag. 637 * @return the object that accepted the drag. 638 * @since JavaFX 8.0 639 */ 640 public final Object getAcceptingObject() { 641 return state.acceptingObject; 642 } 643 644 /** 645 * A dragboard that is available to transfer data. 646 * Data can be placed onto this dragboard in handler of the 647 * {@code DRAG_DETECTED} mouse event. Data can be copied from this 648 * dragboard in handler of the {@code DRAG_DROPPED} event. 649 */ 650 public final Dragboard getDragboard() { 651 return dragboard; 652 } 653 private transient Dragboard dragboard; 654 655 /** 656 * Chooses a transfer mode for the operation 657 * @param supported Transfer modes supported by gesture source 658 * @param accepted Transfer modes accepted by gesture 659 * @param proposed Transfer mode proposed by platform 660 * @return The chosen transfer mode, null if none would work 661 */ 662 private static TransferMode chooseTransferMode(Set<TransferMode> supported, 663 TransferMode[] accepted, TransferMode proposed) { 664 665 TransferMode result = null; 666 Set<TransferMode> intersect = EnumSet.noneOf(TransferMode.class); 667 668 for (TransferMode tm : InputEventUtils.safeTransferModes(accepted)) { 669 if (supported.contains(tm)) { 670 intersect.add(tm); 671 } 672 } 673 674 if (intersect.contains(proposed)) { 675 result = proposed; 676 } else { 677 if (intersect.contains(TransferMode.MOVE)) { 678 result = TransferMode.MOVE; 679 } else if (intersect.contains(TransferMode.COPY)) { 680 result = TransferMode.COPY; 681 } else if (intersect.contains(TransferMode.LINK)) { 682 result = TransferMode.LINK; 683 } 684 } 685 686 return result; 687 } 688 689 /** 690 * Accepts this {@code DragEvent}, choosing the transfer mode for the 691 * drop operation. 692 * Used to indicate that the potential drop target 693 * that receives this event is a drop target from {@code DRAG_OVER} 694 * event handler. 695 * <p> 696 * It accepts one of the transfer modes that are both passed into this 697 * method and supported by the gesture source. It accepts the default 698 * transfer mode if possible, otherwise the most common one of the 699 * acceptable modes. 700 */ 701 public void acceptTransferModes(TransferMode... transferModes) { 702 703 if (dragboard == null || dragboard.getTransferModes() == null || 704 transferMode == null) { 705 state.accepted = false; 706 return; 707 } 708 709 TransferMode tm = chooseTransferMode(dragboard.getTransferModes(), 710 transferModes, transferMode); 711 712 if (tm == null && getEventType() == DRAG_DROPPED) { 713 throw new IllegalStateException("Accepting unsupported transfer " 714 + "modes inside DRAG_DROPPED handler"); 715 } 716 717 state.accepted = tm != null; 718 state.acceptedTransferMode = tm; 719 state.acceptingObject = state.accepted ? source : null; 720 } 721 722 /** 723 * Indicates that transfer handling of this {@code DragEvent} was completed 724 * successfully during a {@code DRAG_DROPPED} event handler. 725 * No {@link #dragboard} access can happen after this call. 726 * 727 * @param isTransferDone {@code true} indicates that the transfer was successful. 728 * @throws IllegalStateException if this is not a DRAG_DROPPED event 729 */ 730 public void setDropCompleted(boolean isTransferDone) { 731 if (getEventType() != DRAG_DROPPED) { 732 throw new IllegalStateException("setDropCompleted can be called " + 733 "only from DRAG_DROPPED handler"); 734 } 735 736 state.dropCompleted = isTransferDone; 737 } 738 739 /** 740 * Whether {@code setDropCompleted(true)} has been called on this event. 741 * @return true if {@code setDropCompleted(true)} has been called 742 */ 743 public boolean isDropCompleted() { 744 return state.dropCompleted; 745 } 746 747 private void readObject(java.io.ObjectInputStream in) 748 throws IOException, ClassNotFoundException { 749 in.defaultReadObject(); 750 x = sceneX; 751 y = sceneY; 752 } 753 754 /** 755 * These properties need to live in a separate object shared among all the 756 * copied events to make sure that the values are propagated to the 757 * original event. 758 */ 759 private static class State { 760 /** 761 * Whether this event has been accepted. 762 */ 763 boolean accepted = false; 764 765 /** 766 * Whether drop completed successfully. 767 */ 768 boolean dropCompleted = false; 769 770 /** 771 * Transfer mode accepted by the potential gesture target. 772 */ 773 TransferMode acceptedTransferMode = null; 774 775 /** 776 * Object that accepted this event. 777 */ 778 Object acceptingObject = null; 779 } 780 781 }