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