1 19 20 21 package org.netbeans.core.windows.view.dnd; 22 23 24 25 import java.awt.AWTEvent ; 26 import java.awt.Component ; 27 import java.awt.Cursor ; 28 import java.awt.Dialog ; 29 import java.awt.Image ; 30 import java.awt.Point ; 31 import java.awt.Rectangle ; 32 import java.awt.Toolkit ; 33 import java.awt.datatransfer.*; 34 import java.awt.dnd.*; 35 import java.awt.event.*; 36 import java.lang.ref.*; 37 import java.util.*; 38 import java.util.logging.Level ; 39 import java.util.logging.Logger ; 40 import javax.swing.*; 41 import org.netbeans.core.windows.*; 42 import org.netbeans.core.windows.view.ui.*; 43 import org.openide.util.*; 44 import org.openide.windows.TopComponent; 45 46 47 48 66 final class TopComponentDragSupport 67 implements AWTEventListener, DragSourceListener { 68 69 70 public static final String MIME_TOP_COMPONENT = 71 DataFlavor.javaJVMLocalObjectMimeType 72 + "; class=org.openide.windows.TopComponent"; 76 77 public static final String MIME_TOP_COMPONENT_CLONEABLE = 78 DataFlavor.javaJVMLocalObjectMimeType 79 + "; class=org.openide.windows.TopComponent$Cloneable"; 81 82 83 public static final String MIME_TOP_COMPONENT_ARRAY = 84 DataFlavor.javaJVMLocalObjectMimeType 85 + "; class=org.netbeans.core.windows.view.dnd.TopComponentDragSupport$TopComponentArray"; 87 88 89 private static final int CURSOR_COPY = 0; 90 91 private static final int CURSOR_COPY_NO = 1; 92 93 private static final int CURSOR_MOVE = 2; 94 95 private static final int CURSOR_MOVE_NO = 3; 96 100 private static final int CURSOR_COPY_NO_MOVE = 4; 101 102 private static final int CURSOR_MOVE_FREE = 5; 103 104 105 private static final String NAME_CURSOR_COPY = "CursorTopComponentCopy"; 107 private static final String NAME_CURSOR_COPY_NO = "CursorTopComponentCopyNo"; 109 private static final String NAME_CURSOR_MOVE = "CursorTopComponentMove"; 111 private static final String NAME_CURSOR_MOVE_NO = "CursorTopComponentMoveNo"; 113 private static final String NAME_CURSOR_COPY_NO_MOVE = "CursorTopComponentCopyNoMove"; 115 private static final String NAME_CURSOR_MOVE_FREE = "CursorTopComponentMoveFree"; 117 118 private static final boolean DEBUG = Debug.isLoggable(TopComponentDragSupport.class); 119 120 private final WindowDnDManager windowDnDManager; 121 122 125 private Reference<DragSourceContext> dragContextWRef = new WeakReference<DragSourceContext>(null); 126 127 130 private boolean canCopy; 131 132 135 private int hackUserDropAction; 136 137 139 private boolean hackESC; 140 141 142 private final Set keyObservers = new WeakSet(4); 143 144 private Point startingPoint; 145 private Component startingComponent; 146 private long startingTime; 147 148 149 150 TopComponentDragSupport(WindowDnDManager windowDnDManager) { 151 this.windowDnDManager = windowDnDManager; 152 } 153 154 155 160 public boolean isCopyOperationPossible() { 161 return canCopy; 162 } 163 164 166 public void eventDispatched(AWTEvent evt) { 167 MouseEvent me = (MouseEvent) evt; 168 169 if((me.getID() == MouseEvent.MOUSE_PRESSED) && SwingUtilities.isLeftMouseButton(me)) { 171 startingPoint = me.getPoint(); 172 startingComponent = me.getComponent(); 173 startingTime = me.getWhen(); 174 } else if(me.getID() == MouseEvent.MOUSE_RELEASED) { 175 startingPoint = null; 176 startingComponent = null; 177 } 178 179 if(evt.getID() != MouseEvent.MOUSE_DRAGGED) { 180 return; 181 } 182 if(windowDnDManager.isDragging()) { 183 return; 184 } 185 if(startingPoint == null) { 186 return; 187 } 188 if( evt.getSource() instanceof JButton ) { 189 return; 191 } 192 193 Component srcComp = startingComponent; 194 if(srcComp == null) { 195 return; 196 } 197 198 final Point point = new Point (startingPoint); 199 Point currentPoint = me.getPoint(); 200 Component currentComponent = me.getComponent(); 201 if(currentComponent == null) { 202 return; 203 } 204 currentPoint = SwingUtilities.convertPoint(currentComponent, currentPoint, srcComp); 205 if(Math.abs(currentPoint.x - point.x) <= Constants.DRAG_GESTURE_START_DISTANCE 206 && Math.abs(currentPoint.y - point.y) <= Constants.DRAG_GESTURE_START_DISTANCE) { 207 return; 208 } 209 if (me.getWhen() - startingTime <= Constants.DRAG_GESTURE_START_TIME) { 211 return; 212 } 213 startingPoint = null; 214 startingComponent = null; 215 216 if(DEBUG) { 217 debugLog(""); debugLog("eventDispatched (MOUSE_DRAGGED)"); } 220 221 if((srcComp instanceof JTree) 223 && ((JTree)srcComp).getPathForLocation(me.getX(), me.getY()) != null) { 224 return; 225 } 226 227 srcComp = SwingUtilities.getDeepestComponentAt(srcComp, point.x, point.y); 230 231 boolean ctrlDown = me.isControlDown(); 232 233 TopComponent tc = null; 234 Tabbed tabbed; 235 236 if(srcComp instanceof Tabbed) { 237 tabbed = (Tabbed)srcComp; 238 } else { 239 tabbed = (Tabbed)SwingUtilities.getAncestorOfClass(Tabbed.class, srcComp); 240 } 241 if (tabbed == null) { 242 if(srcComp instanceof Tabbed.Accessor) { 243 tabbed = ((Tabbed.Accessor)srcComp).getTabbed(); 244 } else { 245 Tabbed.Accessor acc = (Tabbed.Accessor)SwingUtilities.getAncestorOfClass(Tabbed.Accessor.class, srcComp); 246 tabbed = acc != null ? acc.getTabbed() : null; 247 } 248 } 249 if(tabbed == null) { 250 return; 251 } 252 253 Point ppp = new Point (point); 254 Point p = SwingUtilities.convertPoint(srcComp, ppp, tabbed.getComponent()); 255 256 tc = tabbed.getTopComponentAt(tabbed.tabForCoordinate(p)); 257 if (tc == null) { 258 return; 259 } 260 261 if (ctrlDown) { 263 hackUserDropAction = DnDConstants.ACTION_COPY; 264 } 265 else { 266 hackUserDropAction = DnDConstants.ACTION_MOVE; 267 } 268 269 270 List<MouseEvent> list = new ArrayList<MouseEvent>(); 271 list.add(me); 272 273 TopComponentDroppable startDroppable = (TopComponentDroppable)SwingUtilities 275 .getAncestorOfClass(TopComponentDroppable.class, tc); 276 Point startPoint; 277 if (startDroppable == null) { 278 startDroppable = (TopComponentDroppable)SwingUtilities 279 .getAncestorOfClass(TopComponentDroppable.class, tabbed.getComponent()); 280 } 281 if(startDroppable != null) { 282 startPoint = point; 283 Point pp = new Point (point); 284 startPoint = SwingUtilities.convertPoint(srcComp, pp, (Component )startDroppable); 285 } else { 286 startPoint = null; 287 } 288 290 doStartDrag( 291 srcComp, 292 tc, 293 new DragGestureEvent( 294 new FakeDragGestureRecognizer(windowDnDManager, me), 295 hackUserDropAction, 296 point, 297 list 298 ), 299 startDroppable, 300 startPoint 301 ); 302 } 303 304 305 private void doStartDrag(Component startingComp, Object transfer, DragGestureEvent evt, 306 TopComponentDroppable startingDroppable, Point startingPoint) { 307 if(DEBUG) { 308 debugLog(""); debugLog("doStartDrag"); } 311 312 TopComponent firstTC = transfer instanceof TopComponent 313 ? (TopComponent)transfer 314 : (((TopComponent[])transfer)[0]); 315 316 Dialog dlg = (Dialog )SwingUtilities.getAncestorOfClass( 318 Dialog .class, firstTC); 319 if(dlg != null && dlg.isModal()) { 320 return; 321 } 322 323 if(firstTC instanceof TopComponent.Cloneable) { 324 canCopy = true; 325 } else { 326 canCopy = false; 327 } 328 329 windowDnDManager.dragStarting(startingDroppable, startingPoint, firstTC); 332 333 Cursor cursor = hackUserDropAction == DnDConstants.ACTION_MOVE 334 ? getDragCursor(startingComp, CURSOR_MOVE) 335 : (canCopy 336 ? getDragCursor(startingComp, CURSOR_COPY) 337 : getDragCursor(startingComp, CURSOR_COPY_NO_MOVE)); 338 339 addListening(); 341 hackESC = false; 342 343 Tabbed tabbed = (Tabbed) SwingUtilities.getAncestorOfClass (Tabbed.class, 344 startingComp); 345 if (tabbed == null) { 346 Tabbed.Accessor acc = (Tabbed.Accessor) SwingUtilities.getAncestorOfClass (Tabbed.Accessor.class, 347 startingComp); 348 tabbed = acc != null ? acc.getTabbed() : null; 349 } 350 351 Image img = null; 352 if (tabbed != null && Constants.SWITCH_USE_DRAG_IMAGES) { 353 int idx = tabbed.indexOf(firstTC); 354 img = tabbed.createImageOfTab(idx); 355 } 356 try { 357 evt.startDrag( 358 cursor, 359 img, 360 new Point (0,0), 361 (transfer instanceof TopComponent 362 ? (Transferable)new TopComponentTransferable( 363 (TopComponent)transfer) 364 : (Transferable)new TopComponentArrayTransferable( 365 (TopComponent[])transfer)), 366 this 367 ); 368 } catch(InvalidDnDOperationException idoe) { 369 Logger.getLogger(TopComponentDragSupport.class.getName()).log(Level.WARNING, null, idoe); 370 371 removeListening(); 372 windowDnDManager.resetDragSource(); 373 } 374 } 375 376 private AWTEventListener keyListener = new AWTEventListener() { 377 public void eventDispatched(AWTEvent event) { 378 KeyEvent keyevent = (KeyEvent)event; 379 380 if (keyevent.getID() == KeyEvent.KEY_RELEASED && 381 keyevent.getKeyCode() == KeyEvent.VK_ESCAPE) { 382 hackESC = true; 383 } 384 } 385 386 }; 387 389 private void addListening() { 390 Toolkit.getDefaultToolkit().addAWTEventListener(keyListener, AWTEvent.KEY_EVENT_MASK); 391 } 392 393 394 private void removeListening() { 395 Toolkit.getDefaultToolkit().removeAWTEventListener(keyListener); 396 } 397 398 405 public void dragEnter(DragSourceDragEvent evt) { 406 if(DEBUG) { 407 debugLog(""); debugLog("dragEnter"); } 410 411 if(dragContextWRef.get() == null) { 414 dragContextWRef = new java.lang.ref.WeakReference <DragSourceContext>(evt.getDragSourceContext()); 415 } 416 } 417 418 419 public void dragOver(DragSourceDragEvent evt) { 420 if(DEBUG) { 421 debugLog(""); debugLog("dragOver"); } 424 } 425 426 432 public void dragExit(DragSourceEvent evt) { 433 if(DEBUG) { 434 debugLog(""); debugLog("dragExit"); } 437 438 if(dragContextWRef.get() == null) { 441 dragContextWRef = new WeakReference<DragSourceContext>(evt.getDragSourceContext()); 442 } 443 } 444 445 448 public void dropActionChanged(DragSourceDragEvent evt) { 449 if(DEBUG) { 450 debugLog(""); debugLog("dropActionChanged"); } 453 String name = evt.getDragSourceContext().getCursor().getName(); 454 455 if(name == null) { 456 return; 458 } 459 460 int userAction = evt.getUserAction(); 462 463 if(userAction == DnDConstants.ACTION_NONE) { 465 userAction = DnDConstants.ACTION_MOVE; 466 } 467 hackUserDropAction = userAction; 469 470 int type; 471 if((NAME_CURSOR_COPY.equals(name) 472 || NAME_CURSOR_COPY_NO_MOVE.equals(name)) 473 && userAction == DnDConstants.ACTION_MOVE) { 474 type = CURSOR_MOVE; 475 } else if(NAME_CURSOR_COPY_NO.equals(name) 476 && userAction == DnDConstants.ACTION_MOVE) { 477 type = CURSOR_MOVE_NO; 478 } else if(NAME_CURSOR_MOVE.equals(name) 479 && userAction == DnDConstants.ACTION_COPY) { 480 type = CURSOR_COPY; 481 } else if(NAME_CURSOR_MOVE_NO.equals(name) 482 && userAction == DnDConstants.ACTION_COPY) { 483 type = CURSOR_COPY_NO; 484 } else { 485 return; 486 } 487 488 if(type == CURSOR_COPY && !canCopy) { 491 type = CURSOR_COPY_NO_MOVE; 492 } 493 494 if(getDragCursorName(type).equals( 496 evt.getDragSourceContext().getCursor().getName())) { 497 return; 498 } 499 500 evt.getDragSourceContext().setCursor(getDragCursor(evt.getDragSourceContext().getComponent(),type)); 501 } 502 503 506 public void dragDropEnd(final DragSourceDropEvent evt) { 507 if(DEBUG) { 508 debugLog(""); debugLog("dragDropEnd"); } 511 512 windowDnDManager.dragFinished(); 513 514 try { 515 if(checkDropSuccess(evt)) { 516 removeListening(); 517 return; 518 } 519 520 522 RequestProcessor.getDefault().post(new Runnable () { 525 public void run() { 526 SwingUtilities.invokeLater(createDropIntoFreeAreaTask( 527 evt, evt.getLocation())); 528 }}, 529 250 ); 531 } finally { 532 windowDnDManager.dragFinishedEx(); 533 } 534 } 535 537 538 private boolean checkDropSuccess(DragSourceDropEvent evt) { 539 if(windowDnDManager.isDropSuccess()) { 541 return true; 542 } 543 544 Point location = evt.getLocation(); 546 if(location == null) { 547 return true; 548 } 549 550 if(WindowDnDManager.isInMainWindow(location) 551 || windowDnDManager.isInFloatingFrame(location) 552 || WindowDnDManager.isAroundCenterPanel(location)) { 553 return false; 554 } 555 return false; 559 } 560 561 563 private Runnable createDropIntoFreeAreaTask(final DragSourceDropEvent evt, 564 final Point location) { 565 return new Runnable () { 566 public void run() { 567 if(hackESC) { 570 removeListening(); 571 return; 572 } 573 574 TopComponent[] tcArray = WindowDnDManager.extractTopComponent( 575 false, 576 evt.getDragSourceContext().getTransferable() 577 ); 578 579 if(tcArray != null) { 581 windowDnDManager.tryPerformDrop( 587 windowDnDManager.getController(), 588 windowDnDManager.getFloatingFrames(), 589 location, 590 DnDConstants.ACTION_MOVE, evt.getDragSourceContext().getTransferable()); 592 } 593 } 594 }; 595 } 596 597 598 private static Rectangle getBoundsForNewMode(TopComponent tc, Point location) { 599 int width = tc.getWidth(); 600 int height = tc.getHeight(); 601 602 java.awt.Window window = SwingUtilities.getWindowAncestor(tc); 604 if(window != null) { 605 java.awt.Insets ins = window.getInsets(); 606 width += ins.left + ins.right; 607 height += ins.top + ins.bottom; 608 } 609 611 Rectangle tcBounds = tc.getBounds(); 612 Rectangle initBounds = new Rectangle ( 613 location.x, 614 location.y, 615 width, 616 height 617 ); 618 619 return initBounds; 620 } 621 622 627 void setSuccessCursor (boolean freeArea) { 628 int dropAction = hackUserDropAction; 629 DragSourceContext ctx = dragContextWRef.get(); 630 631 if(ctx == null) { 632 return; 633 } 634 635 int type; 636 if(dropAction == DnDConstants.ACTION_MOVE) { 637 type = freeArea ? CURSOR_MOVE_FREE : CURSOR_MOVE; 638 } else if(dropAction == DnDConstants.ACTION_COPY) { 639 if(canCopy) { 640 type = CURSOR_COPY; 641 } else { 642 type = CURSOR_COPY_NO_MOVE; 643 } 644 } else { 645 Logger.getLogger(TopComponentDragSupport.class.getName()).log(Level.WARNING, null, 647 new java.lang.IllegalStateException ("Invalid action type->" + 648 dropAction)); return; 650 } 651 652 if(getDragCursorName(type).equals(ctx.getCursor().getName())) { 654 return; 655 } 656 657 ctx.setCursor(getDragCursor(ctx.getComponent(),type)); 658 } 659 660 664 void setUnsuccessCursor() { 665 DragSourceContext ctx = dragContextWRef.get(); 666 667 if(ctx == null) { 668 return; 669 } 670 671 String name = ctx.getCursor().getName(); 672 673 int type; 674 if(NAME_CURSOR_COPY.equals(name) 675 || NAME_CURSOR_COPY_NO_MOVE.equals(name)) { 676 type = CURSOR_COPY_NO; 677 } else if(NAME_CURSOR_MOVE.equals(name) || NAME_CURSOR_MOVE_NO.equals(name)) { 678 type = CURSOR_MOVE_NO; 679 } else { 680 return; 681 } 682 683 ctx.setCursor(getDragCursor(ctx.getComponent(),type)); 684 } 685 686 689 void dragFinished() { 690 dragContextWRef = new WeakReference<DragSourceContext>(null); 691 } 692 693 private static void debugLog(String message) { 694 Debug.log(TopComponentDragSupport.class, message); 695 } 696 697 701 private static String getDragCursorName(int type) { 702 if(type == CURSOR_COPY) { 703 return NAME_CURSOR_COPY; 704 } else if(type == CURSOR_COPY_NO) { 705 return NAME_CURSOR_COPY_NO; 706 } else if(type == CURSOR_MOVE) { 707 return NAME_CURSOR_MOVE; 708 } else if(type == CURSOR_MOVE_NO) { 709 return NAME_CURSOR_MOVE_NO; 710 } else if(type == CURSOR_COPY_NO_MOVE) { 711 return NAME_CURSOR_COPY_NO_MOVE; 712 } else if(type == CURSOR_MOVE_FREE) { 713 return NAME_CURSOR_MOVE_FREE; 714 } else { 715 return null; 716 } 717 } 718 719 723 private static Cursor getDragCursor( Component comp, int type ) { 724 Image image = null; 725 String name = null; 726 727 if(type == CURSOR_COPY) { 728 image = Utilities.loadImage( 729 "org/netbeans/core/resources/topComponentDragCopy.gif"); name = NAME_CURSOR_COPY; 731 } else if(type == CURSOR_COPY_NO) { 732 image = Utilities.loadImage( 733 "org/netbeans/core/resources/topComponentDragCopyNo.gif"); name = NAME_CURSOR_COPY_NO; 735 } else if(type == CURSOR_MOVE) { 736 image = Utilities.loadImage( 737 "org/netbeans/core/resources/topComponentDragMove.gif"); name = NAME_CURSOR_MOVE; 739 } else if(type == CURSOR_MOVE_NO) { 740 image = Utilities.loadImage( 741 "org/netbeans/core/resources/topComponentDragMoveNo.gif"); name = NAME_CURSOR_MOVE_NO; 743 } else if(type == CURSOR_COPY_NO_MOVE) { 744 image = Utilities.loadImage( 745 "org/netbeans/core/resources/topComponentDragCopyNo.gif"); name = NAME_CURSOR_COPY_NO_MOVE; 747 } else if(type == CURSOR_MOVE_FREE) { 748 image = Utilities.loadImage( 749 "org/netbeans/core/windows/resources/topComponentDragMoveFreeArea.gif"); name = NAME_CURSOR_MOVE_FREE; 751 } else { 752 throw new IllegalArgumentException ("Unknown cursor type=" + type); } 754 755 return Utilities.createCustomCursor( comp, image, name ); 756 } 757 758 760 762 private static class TopComponentTransferable extends Object 763 implements Transferable { 764 765 766 private TopComponent tc; 767 768 769 770 public TopComponentTransferable(TopComponent tc) { 771 this.tc = tc; 772 } 773 774 775 781 public Object getTransferData(DataFlavor df) { 782 if(MIME_TOP_COMPONENT.equals(df.getMimeType())) { 783 return tc; 784 } else if(MIME_TOP_COMPONENT_CLONEABLE.equals( 785 df.getMimeType()) 786 && tc instanceof TopComponent.Cloneable) { 787 return tc; 788 } 789 790 return null; 791 } 792 793 799 public DataFlavor[] getTransferDataFlavors() { 800 try { 801 if(tc instanceof TopComponent.Cloneable) { 802 return new DataFlavor[]{ 803 new DataFlavor(MIME_TOP_COMPONENT, null, TopComponent.class.getClassLoader()), 804 new DataFlavor(MIME_TOP_COMPONENT_CLONEABLE, null, TopComponent.Cloneable.class.getClassLoader())}; 805 } else { 806 return new DataFlavor[] { 807 new DataFlavor(MIME_TOP_COMPONENT, null, TopComponent.class.getClassLoader()) 808 }; 809 } 810 } catch (ClassNotFoundException ex) { 811 Logger.getLogger(TopComponentDragSupport.class.getName()).log( 812 Level.WARNING, ex.getMessage(), ex); 813 } 814 return new DataFlavor[0]; 815 } 816 817 824 public boolean isDataFlavorSupported(DataFlavor df) { 825 if(MIME_TOP_COMPONENT.equals(df.getMimeType())) { 826 return true; 827 } else if(MIME_TOP_COMPONENT_CLONEABLE.equals( 828 df.getMimeType()) 829 && tc instanceof TopComponent.Cloneable) { 830 return true; 831 } 832 833 return false; 834 } 835 } 838 840 private static class TopComponentArrayTransferable extends Object 841 implements Transferable { 842 843 844 private TopComponent[] tcArray; 845 846 847 848 public TopComponentArrayTransferable(TopComponent[] tcArray) { 849 this.tcArray = tcArray; 850 } 851 852 853 861 public Object getTransferData(DataFlavor df) { 862 if(MIME_TOP_COMPONENT_ARRAY.equals(df.getMimeType())) { 863 return tcArray; 864 } 865 return null; 866 } 867 868 874 public DataFlavor[] getTransferDataFlavors() { 875 try { 876 return new DataFlavor[]{new DataFlavor(MIME_TOP_COMPONENT_ARRAY, 877 null, 878 TopComponent.class.getClassLoader())}; 879 } 880 catch (ClassNotFoundException ex) { 881 Logger.getLogger(TopComponentDragSupport.class.getName()).log( 882 Level.WARNING, ex.getMessage(), ex); 883 } 884 return new DataFlavor[0]; 885 } 886 887 894 public boolean isDataFlavorSupported(DataFlavor df) { 895 if(MIME_TOP_COMPONENT_ARRAY.equals( 896 df.getMimeType())) { 897 return true; 898 } 899 900 return false; 901 } 902 } 905 906 908 private static class FakeDragGestureRecognizer extends DragGestureRecognizer { 909 910 912 public FakeDragGestureRecognizer(WindowDnDManager windowDnDManager, MouseEvent evt) { 913 super(windowDnDManager.getWindowDragSource(), 914 (Component )evt.getSource(), DnDConstants.ACTION_COPY_OR_MOVE, null); 915 916 appendEvent(evt); 917 } 918 919 920 public void registerListeners() {} 921 922 public void unregisterListeners() {} 923 924 } 926 927 931 static class TopComponentArray { 932 } 934 } 935 | Popular Tags |