Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.scene.input; 027 028import java.util.EnumSet; 029import java.util.Set; 030 031import javafx.event.Event; 032import javafx.event.EventTarget; 033import javafx.event.EventType; 034import javafx.geometry.Point3D; 035 036import com.sun.javafx.scene.input.InputEventUtils; 037import java.io.IOException; 038 039// PENDING_DOC_REVIEW 040/** 041 * Drag events replace mouse events during drag-and-drop gesture. 042 * The difference between press-drag-release and drag-and-drop gestures 043 * is described at {@link javafx.scene.input.MouseEvent MouseEvent}. 044 * <p> 045 * Drag and drop gesture can be started by calling {@code startDragAndDrop()} 046 * (on a node or scene) inside of a {@link MouseEvent#DRAG_DETECTED DRAG_DETECTED} event handler. 047 * The data to be transfered to drop target are placed to a {@code dragBoard} 048 * at this moment. 049 * <p> 050 * Drag entered/exited events behave similarly to mouse entered/exited 051 * events, please see {@code MouseEvent} overview. 052 * <p> 053 * 054 * <br><h4>Drag sources: initiating a drag and drop gesture</h4> 055 * 056 * When a drag gesture is detected, an application can decide whether to 057 * start a drag and drop gesture or continue with a press-drag-release gesture. 058 * <p> 059 * The default drag detection mechanism uses mouse movements with a pressed 060 * button in combination with hysteresis. This behavior can be 061 * augmented by the application. Each {@code MOUSE_PRESSED} and 062 * {@code MOUSE_DRAGGED} event has a {@code dragDetect} flag that determines 063 * whether a drag gesture has been detected. The default value of this flag 064 * depends on the default detection mechanism and can be modified by calling 065 * {@code setDragDetect()} inside of an event handler. When processing of 066 * one of these events ends with the {@code dragDetect} flag set to true, 067 * a {@code DRAG_DETECTED} {@code MouseEvent} is sent to the potential gesture 068 * source (the object on which a mouse button has been pressed). This event 069 * notifies about the gesture detection. 070 * <p> 071 * Inside a {@code DRAG_DETECTED} event handler, if the 072 * {@code startDragAndDrop()} method is called on a node or scene and a dragged 073 * data is made available to the returned {@code Dragboard}, the object on which 074 * {@code startDragAndDrop()} has been called is considred a gesture source 075 * and the drag and drop gesture is started. The {@code Dragboard} has system 076 * clipboard functionality but is specifically used for drag and drop data 077 * transfer. 078 * <p> 079 * The {@code startDragAndDrop()} method takes a set of {@code TransferMode}s 080 * supported by the gesture source. For instance passing only 081 * {@code TransferMode.COPY} indicates that the gesture source allows only 082 * copying of the data, not moving or referencing. 083 * <p> 084 * Following example shows a simple drag and drop source: 085 * <code><pre> 086Rectangle rect = new Rectangle(100, 100); 087rect.setOnDragDetected(new EventHandler<MouseEvent>() { 088 @Override public void handle(MouseEvent event) { 089 Dragboard db = startDragAndDrop(TransferMode.ANY); 090 ClipboardContent content = new ClipboardContent(); 091 content.putString("Hello!"); 092 db.setContent(content); 093 event.consume(); 094 } 095}); 096 * </pre></code> 097 * 098 * <br><h4>Potential drop targets</h4> 099 * 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 * <code><pre> 160Rectangle rect = new Rectangle(100, 100); 161 162rect.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 172rect.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></code> 185 * 186 * <br><h4>Drag sources: finalizing drag and drop gesture</h4> 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 */ 203public final class DragEvent extends InputEvent { 204 205 private static final long serialVersionUID = 20121107L; 206 207 /** 208 * Common supertype for all drag event types. 209 */ 210 public static final EventType<DragEvent> ANY = 211 new EventType<DragEvent>(InputEvent.ANY, "DRAG"); 212 213 /** 214 * This event occurs when drag gesture enters a node. It's the 215 * bubbling variant, which is delivered also to all parents of the 216 * entered node (unless it was consumed). When notifications about 217 * entering some of node's children are not desired, 218 * {@code DRAG_ENTERED} event handler should be used. 219 * 220 * @see MouseEvent MouseEvent for more information about mouse entered/exited handling 221 * which is similar 222 */ 223 public static final EventType<DragEvent> DRAG_ENTERED_TARGET = 224 new EventType<DragEvent>(DragEvent.ANY, "DRAG_ENTERED_TARGET"); 225 226 /** 227 * This event occurs when drag gesture enters a node. 228 * This event type is delivered only to the entered node, 229 * if parents want to filter it or get the bubbling event, 230 * they need to use {@code DRAG_ENTERED_TARGET}. 231 * 232 * @see MouseEvent MouseEvent for more information about mouse entered/exited handling 233 * which is similar 234 */ 235 public static final EventType<DragEvent> DRAG_ENTERED = 236 new EventType<DragEvent>(DragEvent.DRAG_ENTERED_TARGET, "DRAG_ENTERED"); 237 238 /** 239 * This event occurs when drag gesture exits a node. It's the 240 * bubbling variant, which is delivered also to all parents of the 241 * eixited node (unless it was consumed). When notifications about 242 * exiting some of node's children are not desired, 243 * {@code DRAG_EXITED} event handler should be used. 244 * 245 * @see MouseEvent MouseEvent for more information about mouse entered/exited handling 246 * which is similar 247 */ 248 public static final EventType<DragEvent> DRAG_EXITED_TARGET = 249 new EventType<DragEvent>(DragEvent.ANY, "DRAG_EXITED_TARGET"); 250 251 /** 252 * This event occurs when drag gesture exits a node. 253 * This event type is delivered only to the exited node, 254 * if parents want to filter it or get the bubbling event, 255 * they need to use {@code DRAG_EXITED_TARGET}. 256 * 257 * @see MouseEvent MouseEvent for more information about mouse entered/exited handling 258 * which is similar 259 */ 260 public static final EventType<DragEvent> DRAG_EXITED = 261 new EventType<DragEvent>(DragEvent.DRAG_EXITED_TARGET, "DRAG_EXITED"); 262 263 /** 264 * This event occurs when drag gesture progresses within this node. 265 */ 266 public static final EventType<DragEvent> DRAG_OVER = 267 new EventType<DragEvent>(DragEvent.ANY, "DRAG_OVER"); 268 269 // Do we want DRAG_TRANSFER_MODE_CHANGED event? 270// /** 271// * This event occurs on a potential drag-and-drop target when the user 272// * takes action to change the intended {@code TransferMode}. 273// * The user can change the intended {@link TransferMode} by holding down 274// * or releasing key modifiers. 275// */ 276// public static final EventType<DragEvent> DRAG_TRANSFER_MODE_CHANGED = 277// new EventType<DragEvent>(DragEvent.ANY, "DRAG_TRANSFER_MODE_CHANGED"); 278 279 /** 280 * This event occurs when the mouse button is released during drag and drop 281 * gesture on a drop target. Transfer of data from the 282 * {@link DragEvent}'s {@link DragEvent#dragboard dragboard} should happen 283 * in handler of this event. 284 */ 285 public static final EventType<DragEvent> DRAG_DROPPED = 286 new EventType<DragEvent>(DragEvent.ANY, "DRAG_DROPPED"); 287 288 /** 289 * This event occurs on drag-and-drop gesture source after its data has 290 * been dropped on a drop target. The {@code transferMode} of the 291 * event shows what just happened at the drop target. 292 * If {@code transferMode} has the value {@code MOVE}, then the source can 293 * clear out its data. Clearing the source's data gives the appropriate 294 * appearance to a user that the data has been moved by the drag and drop 295 * gesture. A {@code transferMode} that has the value {@code NONE} 296 * indicates that no data was transferred during the drag and drop gesture. 297 */ 298 public static final EventType<DragEvent> DRAG_DONE = 299 new EventType<DragEvent>(DragEvent.ANY, "DRAG_DONE"); 300 301 /** 302 * Creates a copy of the given drag event with the given fields substituted. 303 * @param source the new source of the copied event 304 * @param target the new target of the copied event 305 * @param gestureSource the new gesture source. 306 * @param gestureTarget the new gesture target. 307 * @param eventType the new eventType 308 * @return the event copy with the fields 309 */ 310 public DragEvent copyFor(Object source, EventTarget target, 311 Object gestureSource, Object gestureTarget, 312 EventType<DragEvent> eventType) { 313 314 DragEvent copyEvent = copyFor(source, target, eventType); 315 recomputeCoordinatesToSource(copyEvent, source); 316 copyEvent.gestureSource = gestureSource; 317 copyEvent.gestureTarget = gestureTarget; 318 return copyEvent; 319 } 320 321 /** 322 * Constructs new DragEvent event. 323 * For DRAG_DROPPED and DRAG_DONE event types, the {@code accepted} state 324 * and {@code acceptedTransferMode} are set according to the passed 325 * {@code transferMode}. 326 * @param source the source of the event. Can be null. 327 * @param target the target of the event. Can be null. 328 * @param eventType The type of the event. 329 * @param dragboard the dragboard of the event. 330 * @param x The x with respect to the scene. 331 * @param y The y with respect to the scene. 332 * @param screenX The x coordinate relative to screen. 333 * @param screenY The y coordinate relative to screen. 334 * @param transferMode the transfer mode of the event. 335 * @param gestureSource the source of the DnD gesture of the event. 336 * @param gestureTarget the target of the DnD gesture of the event. 337 * @param pickResult pick result. Can be null, in this case a 2D pick result 338 * without any further values is constructed 339 * based on the scene coordinates and the target 340 */ 341 public DragEvent(Object source, EventTarget target, EventType<DragEvent> eventType, Dragboard dragboard, 342 double x, double y, 343 double screenX, double screenY, TransferMode transferMode, 344 Object gestureSource, Object gestureTarget, PickResult pickResult) { 345 super(source, target, eventType); 346 this.gestureSource = gestureSource; 347 this.gestureTarget = gestureTarget; 348 this.x = x; 349 this.y = y; 350 this.screenX = screenX; 351 this.screenY = screenY; 352 this.sceneX = x; 353 this.sceneY = y; 354 this.transferMode = transferMode; 355 this.dragboard = dragboard; 356 357 if (eventType == DragEvent.DRAG_DROPPED 358 || eventType == DragEvent.DRAG_DONE) { 359 state.accepted = transferMode != null; 360 state.acceptedTrasferMode = transferMode; 361 } 362 363 this.pickResult = pickResult != null ? pickResult : new PickResult( 364 eventType == DRAG_DONE ? null : target, x, y); 365 final Point3D p = InputEventUtils.recomputeCoordinates(this.pickResult, null); 366 this.x = p.getX(); 367 this.y = p.getY(); 368 this.z = p.getZ(); 369 } 370 371 /** 372 * Constructs new DragEvent event with empty source and target. 373 * @param eventType The type of the event. 374 * @param dragboard the dragboard of the event. 375 * @param x The x with respect to the scene. 376 * @param y The y with respect to the scene. 377 * @param screenX The x coordinate relative to screen. 378 * @param screenY The y coordinate relative to screen. 379 * @param transferMode the transfer mode of the event. 380 * @param gestureSource the source of the DnD gesture of the event. 381 * @param gestureTarget the target of the DnD gesture of the event. 382 * @param pickResult pick result. Can be null, in this case a 2D pick result 383 * without any further values is constructed 384 * based on the scene coordinates 385 */ 386 public DragEvent(EventType<DragEvent> eventType, Dragboard dragboard, 387 double x, double y, 388 double screenX, double screenY, TransferMode transferMode, 389 Object gestureSource, Object gestureTarget, PickResult pickResult) { 390 this(null, null, eventType, dragboard, x, y, screenX, screenY, transferMode, 391 gestureSource, gestureTarget, pickResult); 392 } 393 394 /** 395 * Fills the given event by this event's coordinates recomputed to the given 396 * source object 397 * @param newEvent Event whose coordinates are to be filled 398 * @param newSource Source object to compute coordinates for 399 */ 400 private void recomputeCoordinatesToSource(DragEvent newEvent, Object newSource) { 401 402 if (newEvent.getEventType() == DRAG_DONE) { 403 // DRAG_DONE contains all zeros, doesn't make sense to recompute it 404 return; 405 } 406 407 final Point3D newCoordinates = InputEventUtils.recomputeCoordinates( 408 pickResult, newSource); 409 410 newEvent.x = newCoordinates.getX(); 411 newEvent.y = newCoordinates.getY(); 412 newEvent.z = newCoordinates.getZ(); 413 } 414 415 @Override 416 public DragEvent copyFor(Object newSource, EventTarget newTarget) { 417 DragEvent e = (DragEvent) super.copyFor(newSource, newTarget); 418 recomputeCoordinatesToSource(e, newSource); 419 return e; 420 } 421 422 /** 423 * Creates a copy of the given drag event with the given fields substituted. 424 * @param source the new source of the copied event 425 * @param target the new target of the copied event 426 * @param eventType the new eventType 427 * @return the event copy with the fields 428 */ 429 public DragEvent copyFor(Object source, EventTarget target, EventType<DragEvent> type) { 430 DragEvent e = (DragEvent) copyFor(source, target); 431 e.eventType = type; 432 return e; 433 } 434 435 @Override 436 public EventType<DragEvent> getEventType() { 437 return (EventType<DragEvent>) super.getEventType(); 438 } 439 440 /** 441 * Horizontal x position of the event relative to the 442 * origin of the MouseEvent's node. 443 */ 444 private transient double x; 445 446 /** 447 * Horizontal position of the event relative to the 448 * origin of the DragEvent's source. 449 * 450 * @return horizontal position of the event relative to the 451 * origin of the DragEvent's source. 452 */ 453 public final double getX() { 454 return x; 455 } 456 457 /** 458 * Vertical y position of the event relative to the 459 * origin of the MouseEvent's node. 460 */ 461 private transient double y; 462 463 /** 464 * Vertical position of the event relative to the 465 * origin of the DragEvent's source. 466 * 467 * @return vertical position of the event relative to the 468 * origin of the DragEvent's source. 469 */ 470 public final double getY() { 471 return y; 472 } 473 474 /** 475 * Depth z position of the event relative to the 476 * origin of the MouseEvent's node. 477 */ 478 private transient double z; 479 480 /** 481 * Depth position of the event relative to the 482 * origin of the MouseEvent's source. 483 * 484 * @return depth position of the event relative to the 485 * origin of the MouseEvent's source. 486 */ 487 public final double getZ() { 488 return z; 489 } 490 491 /** 492 * Absolute horizontal x position of the event. 493 */ 494 private final double screenX; 495 496 /** 497 * Returns absolute horizontal position of the event. 498 * @return absolute horizontal position of the event 499 */ 500 public final double getScreenX() { 501 return screenX; 502 } 503 504 /** 505 * Absolute vertical y position of the event. 506 */ 507 private final double screenY; 508 509 /** 510 * Returns absolute vertical position of the event. 511 * @return absolute vertical position of the event 512 */ 513 public final double getScreenY() { 514 return screenY; 515 } 516 517 /** 518 * Horizontal x position of the event relative to the 519 * origin of the {@code Scene} that contains the DragEvent's node. 520 * If the node is not in a {@code Scene}, then the value is relative to 521 * the boundsInParent of the root-most parent of the DragEvent's node. 522 */ 523 private final double sceneX; 524 525 /** 526 * Returns horizontal position of the event relative to the 527 * origin of the {@code Scene} that contains the DragEvent's source. 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 * Note that in 3D scene, this represents the flat coordinates after 531 * applying the projection transformations. 532 * 533 * @return horizontal position of the event relative to the 534 * origin of the {@code Scene} that contains the DragEvent's source 535 */ 536 public final double getSceneX() { 537 return sceneX; 538 } 539 540 /** 541 * Vertical y position of the event relative to the 542 * origin of the {@code Scene} that contains the DragEvent's node. 543 * If the node is not in a {@code Scene}, then the value is relative to 544 * the boundsInParent of the root-most parent of the DragEvent's node. 545 */ 546 private final double sceneY; 547 548 /** 549 * Returns vertical position of the event relative to the 550 * origin of the {@code Scene} that contains the DragEvent's source. 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 * Note that in 3D scene, this represents the flat coordinates after 554 * applying the projection transformations. 555 * 556 * @return vertical position of the event relative to the 557 * origin of the {@code Scene} that contains the DragEvent's source 558 */ 559 public final double getSceneY() { 560 return sceneY; 561 } 562 563 /** 564 * Information about the pick if the picked {@code Node} is a 565 * {@code Shape3D} node and its pickOnBounds is false. 566 */ 567 private PickResult pickResult; 568 569 /** 570 * Returns information about the pick. 571 * 572 * @return new PickResult object that contains information about the pick 573 */ 574 public final PickResult getPickResult() { 575 return pickResult; 576 } 577 578 /** 579 * The source object of the drag and drop gesture. 580 * Gesture source is the object that started drag and drop operation. 581 * The value {@code null} is valid in the case that the gesture comes 582 * from another application. 583 */ 584 public final Object getGestureSource() { return gestureSource; } 585 private Object gestureSource; 586 587 /** 588 * The target object of the drag and drop gesture. 589 * Gesture target is the object that accepts drag events. 590 * The value {@code null} is valid in the case that the drag and drop 591 * gesture has been canceled or completed without a transfer taking place 592 * or there is currently no event target accepting the drag events. 593 */ 594 public final Object getGestureTarget() { return gestureTarget; } 595 private Object gestureTarget; 596 597 /** 598 * Data transfer mode. Before the data transfer is is performed, 599 * this is the default transfer mode set by system according to 600 * input events such as the user holding some modifiers. 601 * In time of data transfer (in DRAG_DROPPED event) it determines 602 * the transfer mode accepted by previous DRAG_OVER handler. 603 * After the data transfer (in DRAG_DONE event) 604 * it determines the actual mode of the transfer done. 605 */ 606 public final TransferMode getTransferMode() { return transferMode; } 607 private TransferMode transferMode; 608 609 private final State state = new State(); 610 611 /** 612 * Indicates if this event has been accepted. 613 * @see #acceptTransferModes 614 * @defaultValue false 615 */ 616 public final boolean isAccepted() { return state.accepted; } 617 618 /** 619 * Gets transfer mode accepted by potential target. 620 * @return transfer mode accepted by potential target. 621 */ 622 public final TransferMode getAcceptedTransferMode() { 623 return state.acceptedTrasferMode; 624 } 625 626 /** 627 * The object that accepted the drag. 628 * @return the object that accepted the drag. 629 */ 630 public final Object getAcceptingObject() { 631 return state.acceptingObject; 632 } 633 634 /** 635 * A dragboard that is available to transfer data. 636 * Data can be placed onto this dragboard in handler of the 637 * {@code DRAG_DETECTED} mouse event. Data can be copied from this 638 * dragboard in handler of the {@code DRAG_DROPPED} event. 639 */ 640 public final Dragboard getDragboard() { 641 return dragboard; 642 } 643 private transient Dragboard dragboard; 644 645 /** 646 * Chooses a transfer mode for the operation 647 * @param supported Transfer modes supported by gesture source 648 * @param accepted Transfer modes accepted by gesture 649 * @param proposed Transfer mode proposed by platform 650 * @return The chosen transfer mode, null if none would work 651 */ 652 private static TransferMode chooseTransferMode(Set<TransferMode> supported, 653 TransferMode[] accepted, TransferMode proposed) { 654 655 TransferMode result = null; 656 Set<TransferMode> intersect = EnumSet.noneOf(TransferMode.class); 657 658 for (TransferMode tm : InputEventUtils.safeTransferModes(accepted)) { 659 if (supported.contains(tm)) { 660 intersect.add(tm); 661 } 662 } 663 664 if (intersect.contains(proposed)) { 665 result = proposed; 666 } else { 667 if (intersect.contains(TransferMode.MOVE)) { 668 result = TransferMode.MOVE; 669 } else if (intersect.contains(TransferMode.COPY)) { 670 result = TransferMode.COPY; 671 } else if (intersect.contains(TransferMode.LINK)) { 672 result = TransferMode.LINK; 673 } 674 } 675 676 return result; 677 } 678 679 /** 680 * Accepts this {@code DragEvent}, choosing the transfer mode for the 681 * drop operation. 682 * Used to indicate that the potential drop target 683 * that receives this event is a drop target from {@code DRAG_OVER} 684 * event handler. 685 * <p> 686 * It accepts one of the transfer modes that are both passed into this 687 * method and supported by the gesture source. It accepts the default 688 * transfer mode if possible, otherwise the most common one of the 689 * acceptable modes. 690 */ 691 public void acceptTransferModes(TransferMode... transferModes) { 692 693 if (dragboard == null || dragboard.getTransferModes() == null || 694 transferMode == null) { 695 state.accepted = false; 696 return; 697 } 698 699 TransferMode tm = chooseTransferMode(dragboard.getTransferModes(), 700 transferModes, transferMode); 701 702 if (tm == null && getEventType() == DRAG_DROPPED) { 703 throw new IllegalStateException("Accepting unsupported transfer " 704 + "modes inside DRAG_DROPPED handler"); 705 } 706 707 state.accepted = tm != null; 708 state.acceptedTrasferMode = tm; 709 state.acceptingObject = state.accepted ? source : null; 710 } 711 712 /** 713 * Indicates that transfer handling of this {@code DragEvent} was completed 714 * successfully during a {@code DRAG_DROPPED} event handler. 715 * No {@link #dragboard} access can happen after this call. 716 * 717 * @param isTransferDone {@code true} indicates that the transfer was successful. 718 * @throws IllegalStateException if this is not a DRAG_DROPPED event 719 */ 720 public void setDropCompleted(boolean isTransferDone) { 721 if (getEventType() != DRAG_DROPPED) { 722 throw new IllegalStateException("setDropCompleted can be called " + 723 "only from DRAG_DROPPED handler"); 724 } 725 726 state.dropCompleted = isTransferDone; 727 } 728 729 /** 730 * Whether {@code setDropCompleted(true)} has been called on this event. 731 * @return true if {@code setDropCompleted(true)} has been called 732 */ 733 public boolean isDropCompleted() { 734 return state.dropCompleted; 735 } 736 737 private void readObject(java.io.ObjectInputStream in) 738 throws IOException, ClassNotFoundException { 739 in.defaultReadObject(); 740 x = sceneX; 741 y = sceneY; 742 } 743 744 /** 745 * These properties need to live in a separate object shared among all the 746 * copied events to make sure that the values are propagated to the 747 * original event. 748 */ 749 private static class State { 750 /** 751 * Whether this event has been accepted. 752 */ 753 boolean accepted = false; 754 755 /** 756 * Whether drop completed successfully. 757 */ 758 boolean dropCompleted = false; 759 760 /** 761 * Transfer mode accepted by the potential gesture target. 762 */ 763 TransferMode acceptedTrasferMode = null; 764 765 /** 766 * Object that accepted this event. 767 */ 768 Object acceptingObject = null; 769 } 770 771}