1 19 package org.openide.explorer.view; 20 21 import java.util.logging.Level ; 22 import java.util.logging.Logger ; 23 import org.openide.nodes.Children; 24 import org.openide.nodes.Index; 25 import org.openide.nodes.Node; 26 import org.openide.util.datatransfer.PasteType; 27 28 import java.awt.Component ; 29 import java.awt.Point ; 30 import java.awt.Rectangle ; 31 import java.awt.datatransfer.Transferable ; 32 import java.awt.dnd.*; 33 import java.awt.event.ActionEvent ; 34 import java.awt.event.ActionListener ; 35 import java.awt.geom.Line2D ; 36 import java.awt.geom.Line2D.Double; 37 import java.util.ArrayList ; 38 39 import java.util.Arrays ; 40 import java.util.Comparator ; 41 import java.util.Iterator ; 42 import java.util.List ; 43 import java.util.TreeSet ; 44 45 import javax.swing.JTree ; 46 import javax.swing.SwingUtilities ; 47 import javax.swing.Timer ; 48 import javax.swing.tree.TreeCellEditor ; 49 import javax.swing.tree.TreePath ; 50 51 55 final class TreeViewDropSupport implements DropTargetListener, Runnable { 56 final static protected int FUSSY_POINTING = 3; 57 final static private int DELAY_TIME_FOR_EXPAND = 1000; 58 final static private int SHIFT_DOWN = -1; 59 final static private int SHIFT_RIGHT = 10; 60 final static private int SHIFT_LEFT = 15; 61 62 64 65 boolean active = false; 66 boolean dropTargetPopupAllowed; 67 68 69 DropTarget dropTarget; 70 71 73 Rectangle lastNodeArea; 74 private int upperNodeIdx = -1; 75 private int lowerNodeIdx = -1; 76 private int dropIndex = -1; 77 78 79 Timer timer; 80 81 82 DropGlassPane dropPane; 83 private int pointAt = DragDropUtilities.NODE_CENTRAL; 84 85 87 88 protected TreeView view; 89 90 91 protected JTree tree; 92 93 95 96 public TreeViewDropSupport(TreeView view, JTree tree, boolean dropTargetPopupAllowed) { 97 this.view = view; 98 this.tree = tree; 99 this.dropTargetPopupAllowed = dropTargetPopupAllowed; 100 } 101 102 public void setDropTargetPopupAllowed(boolean value) { 103 dropTargetPopupAllowed = value; 104 } 105 106 public boolean isDropTargetPopupAllowed() { 107 return dropTargetPopupAllowed; 108 } 109 110 111 public void dragEnter(DropTargetDragEvent dtde) { 112 checkStoredGlassPane(); 113 114 dropIndex = -1; 115 116 doDragOver(dtde); 118 } 119 120 121 public void dragOver(DropTargetDragEvent dtde) { 122 checkStoredGlassPane(); 126 127 doDragOver(dtde); 129 } 130 131 private void checkStoredGlassPane() { 132 if (!DropGlassPane.isOriginalPaneStored()) { 134 Component comp = tree.getRootPane().getGlassPane(); 135 DropGlassPane.setOriginalPane(tree, comp, comp.isVisible()); 136 137 dropPane = DropGlassPane.getDefault(tree); 139 tree.getRootPane().setGlassPane(dropPane); 140 dropPane.revalidate(); 141 dropPane.setVisible(true); 142 } 143 } 144 145 146 private void doDragOver(DropTargetDragEvent dtde) { 147 ExplorerDnDManager.getDefault().setMaybeExternalDragAndDrop( true ); 148 149 int dropAction = dtde.getDropAction(); 150 int allowedDropActions = view.getAllowedDropActions(); 151 152 dropAction = ExplorerDnDManager.getDefault().getAdjustedDropAction( 153 dropAction, allowedDropActions); 154 155 TreePath tp = getTreePath(dtde, dropAction); 157 Node dropNode; 158 159 Point p = dtde.getLocation(); 161 if (tp == null) { 162 dropNode = view.manager.getRootContext (); 164 if (canDrop(dropNode, dropAction, dtde.getTransferable())) { 165 dtde.acceptDrag(dropAction); 167 } else { 168 dtde.rejectDrag(); 169 } 170 return ; 171 } else { 172 dropNode = getNodeForDrop(p); 173 } 174 175 if (dropNode == null) { 177 dropIndex = -1; 178 dtde.rejectDrag(); 179 removeDropLine(); 180 181 return; 182 } 183 184 Rectangle nodeArea = tree.getPathBounds(tp); 185 int endPointX = nodeArea.x + nodeArea.width; 186 int row = tree.getRowForPath(tp); 187 188 if (nodeArea != null) { 189 pointAt = DragDropUtilities.NODE_CENTRAL; 190 191 if (p.y <= (nodeArea.y + FUSSY_POINTING)) { 192 if (row != 0) { 194 pointAt = DragDropUtilities.NODE_UP; 196 197 TreePath upPath = tree.getPathForRow(row - 1); 198 199 if ((upPath != null) && !upPath.equals(tp)) { 200 endPointX = Math.max( 201 nodeArea.x + nodeArea.width, 202 tree.getPathBounds(upPath).x + tree.getPathBounds(upPath).width 203 ); 204 } 205 206 if (dropNode.getParentNode() != null) { 208 dropNode = dropNode.getParentNode(); 209 tp = null; 210 } 211 } 212 } else if (p.y >= ((nodeArea.y + nodeArea.height) - FUSSY_POINTING)) { 213 if (!view.isExpanded(dropNode)) { 215 pointAt = DragDropUtilities.NODE_DOWN; 217 218 TreePath downPath = tree.getPathForRow(row + 1); 219 220 if ((downPath != null) && !downPath.equals(tp)) { 221 endPointX = Math.max( 222 nodeArea.x + nodeArea.width, 223 tree.getPathBounds(downPath).x + tree.getPathBounds(downPath).width 224 ); 225 } 226 227 if (dropNode.getParentNode() != null) { 229 dropNode = dropNode.getParentNode(); 230 tp = null; 231 } 232 } 233 } 234 } 235 236 endPointX = endPointX + SHIFT_RIGHT; 237 238 Index indexCookie = (Index) dropNode.getCookie(Index.class); 240 241 if (indexCookie != null) { 242 if (pointAt == DragDropUtilities.NODE_UP) { 243 lowerNodeIdx = indexCookie.indexOf(getNodeForDrop(p)); 244 upperNodeIdx = lowerNodeIdx - 1; 245 } else if (pointAt == DragDropUtilities.NODE_DOWN) { 246 upperNodeIdx = indexCookie.indexOf(getNodeForDrop(p)); 247 lowerNodeIdx = upperNodeIdx + 1; 248 } 249 dropIndex = lowerNodeIdx; 250 } 251 if( dropNode == getNodeForDrop(p) ) 252 dropIndex = -1; 253 254 if ( 256 ((timer == null) || !timer.isRunning()) && (dropNode != null) && !dropNode.isLeaf() && 257 !view.isExpanded(dropNode) 258 ) { 259 final Node cn = dropNode; 262 263 removeTimer(); 265 266 timer = new Timer ( 268 DELAY_TIME_FOR_EXPAND, 269 new ActionListener () { 270 final public void actionPerformed(ActionEvent e) { 271 view.expandNode(cn); 272 } 273 } 274 ); 275 timer.setRepeats(false); 276 timer.start(); 277 } 278 279 if (pointAt == DragDropUtilities.NODE_CENTRAL) { 282 dropPane.setDropLine(null); 284 } else { 285 if (pointAt == DragDropUtilities.NODE_UP) { 287 Line2D line = new Double ( 288 nodeArea.x - SHIFT_LEFT, nodeArea.y + SHIFT_DOWN, endPointX, nodeArea.y + SHIFT_DOWN 289 ); 290 convertBoundsAndSetDropLine(line); 291 292 Rectangle lineArea = new Rectangle ( 294 nodeArea.x - SHIFT_LEFT, (nodeArea.y + SHIFT_DOWN) - 3, endPointX - nodeArea.x + SHIFT_LEFT, 5 295 ); 296 nodeArea = (Rectangle ) nodeArea.createUnion(lineArea); 297 } else { 298 Line2D line = new Double ( 299 nodeArea.x - SHIFT_LEFT, nodeArea.y + nodeArea.height + SHIFT_DOWN, endPointX, 300 nodeArea.y + nodeArea.height + SHIFT_DOWN 301 ); 302 convertBoundsAndSetDropLine(line); 303 304 Rectangle lineArea = new Rectangle ( 306 nodeArea.x - SHIFT_LEFT, nodeArea.y + nodeArea.height, endPointX - nodeArea.x + SHIFT_LEFT, 307 SHIFT_DOWN + 3 308 ); 309 nodeArea = (Rectangle ) nodeArea.createUnion(lineArea); 310 } 311 312 314 319 } 320 321 if ((lastNodeArea != null) && (!lastNodeArea.equals(nodeArea))) { 323 NodeRenderer.dragExit(); 324 repaint(lastNodeArea); 325 } 326 327 if (!nodeArea.equals(lastNodeArea)) { 329 if (tp != null) { 330 NodeRenderer.dragEnter(tp.getLastPathComponent()); 331 } 332 333 repaint(nodeArea); 334 lastNodeArea = nodeArea; 335 removeTimer(); 336 } 337 338 if (canDrop(dropNode, dropAction, dtde.getTransferable())) { 340 dtde.acceptDrag(dropAction); 342 } else { 343 Node[] draggedNodes = ExplorerDnDManager.getDefault().getDraggedNodes(); 345 if( null != draggedNodes && canReorderWhenMoving(dropNode, draggedNodes) ) { 346 dtde.acceptDrag(dropAction); 348 } else { 349 dtde.rejectDrag(); 350 } 351 } 352 } 353 354 357 private void repaint(Rectangle r) { 358 tree.repaint(r.x - 5, r.y - 5, r.width + 10, r.height + 10); 359 } 360 361 364 private void convertBoundsAndSetDropLine(final Line2D line) { 365 int x1 = (int) line.getX1(); 366 int x2 = (int) line.getX2(); 367 int y1 = (int) line.getY1(); 368 int y2 = (int) line.getY2(); 369 Point p1 = SwingUtilities.convertPoint(tree, x1, y1, tree.getRootPane()); 370 Point p2 = SwingUtilities.convertPoint(tree, x2, y2, tree.getRootPane()); 371 line.setLine(p1, p2); 372 dropPane.setDropLine(line); 373 } 374 375 376 private void removeTimer() { 377 if (timer != null) { 378 ActionListener [] l = (ActionListener []) timer.getListeners(ActionListener .class); 379 380 for (int i = 0; i < l.length; i++) { 381 timer.removeActionListener(l[i]); 382 } 383 384 timer.stop(); 385 timer = null; 386 } 387 } 388 389 public void dropActionChanged(DropTargetDragEvent dtde) { 390 Node[] nodes = ExplorerDnDManager.getDefault().getDraggedNodes(); 392 if( null != nodes ) { 393 int dropAction = ExplorerDnDManager.getDefault().getAdjustedDropAction( 394 dtde.getDropAction(), view.getAllowedDropActions() 395 ); 396 397 for (int i = 0; i < nodes.length; i++) { 398 if ( 399 ((view.getAllowedDropActions() & dropAction) == 0) || 400 !DragDropUtilities.checkNodeForAction(nodes[i], dropAction) 401 ) { 402 dtde.rejectDrag(); 404 405 return; 406 } 407 } 408 } 409 410 return; 411 } 412 413 414 public void dragExit(DropTargetEvent dte) { 415 dropIndex = -1; 416 417 ExplorerDnDManager.getDefault().setMaybeExternalDragAndDrop( false ); 418 stopDragging(); 419 } 420 421 private void removeDropLine() { 422 if( null != dropPane ) { 423 dropPane.setDropLine(null); 424 } 425 426 if (lastNodeArea != null) { 427 NodeRenderer.dragExit(); 428 repaint(lastNodeArea); 429 lastNodeArea = null; 430 } 431 } 432 433 private void stopDragging() { 434 removeDropLine(); 435 removeTimer(); 436 437 if (DropGlassPane.isOriginalPaneStored()) { 439 DropGlassPane.putBackOriginal(); 440 } 441 } 442 443 444 private Node getNodeForDrop(Point p) { 445 if (p != null) { 446 TreePath tp = tree.getPathForLocation(p.x, p.y); 447 if( null == tp ) { 448 tp = tree.getPathForLocation(p.x, p.y-tree.getRowHeight()/2); 450 } 451 452 if (tp != null) { 453 return DragDropUtilities.secureFindNode(tp.getLastPathComponent()); 454 } 455 } 456 457 return null; 458 } 459 460 private boolean canReorderWhenMoving(Node folder, Node[] dragNodes) { 461 if ((ExplorerDnDManager.getDefault().getNodeAllowedActions() & DnDConstants.ACTION_MOVE) == 0) { 462 return false; 463 } 464 return canReorder( folder, dragNodes ); 465 } 466 467 private boolean canReorder(Node folder, Node[] dragNodes) { 468 if ((folder == null) || (dragNodes.length == 0)) { 469 return false; 470 } 471 472 Index ic = (Index) folder.getCookie(Index.class); 474 475 if (ic == null) { 476 return false; 477 } 478 479 for (int i = 0; i < dragNodes.length; i++) { 482 if (dragNodes[i] == null) { 484 return false; 485 } 486 487 if (dragNodes[i].getParentNode() == null) { 488 return false; 489 } 490 491 if (!dragNodes[i].getParentNode().equals(folder)) { 492 return false; 493 } 494 } 495 496 return true; 497 } 498 499 private void performReorder(final Node folder, Node[] dragNodes, int lNode, int uNode) { 500 try { 501 Index indexCookie = (Index) folder.getCookie(Index.class); 502 503 if (indexCookie != null) { 504 int[] perm = new int[indexCookie.getNodesCount()]; 505 int[] indexes = new int[dragNodes.length]; 506 int indexesLength = 0; 507 508 for (int i = 0; i < dragNodes.length; i++) { 509 int idx = indexCookie.indexOf(dragNodes[i]); 510 511 if ((idx >= 0) && (idx < perm.length)) { 512 indexes[indexesLength++] = idx; 513 } 514 } 515 516 Arrays.sort(indexes); 519 520 if ((lNode < 0) || (uNode >= perm.length) || (indexesLength == 0)) { 521 return; 522 } 523 524 int k = 0; 525 526 for (int i = 0; i < perm.length; i++) { 527 if (i <= uNode) { 528 if (!containsNumber(indexes, indexesLength, i)) { 529 perm[i] = k++; 530 } 531 532 if (i == uNode) { 533 for (int j = 0; j < indexesLength; j++) { 534 if (indexes[j] <= uNode) { 535 perm[indexes[j]] = k++; 536 } 537 } 538 } 539 } else { 540 if (i == lNode) { 541 for (int j = 0; j < indexesLength; j++) { 542 if (indexes[j] >= lNode) { 543 perm[indexes[j]] = k++; 544 } 545 } 546 } 547 548 if (!containsNumber(indexes, indexesLength, i)) { 549 perm[i] = k++; 550 } 551 } 552 } 553 554 for (int i = 0; i < perm.length; i++) { 556 if (perm[i] != i) { 557 indexCookie.reorder(perm); 558 559 break; 560 } 561 } 562 } 563 } catch (Exception e) { 564 Logger.getLogger(TreeViewDropSupport.class.getName()).log(Level.WARNING, null, e); 566 } 567 } 568 569 private boolean containsNumber(int[] arr, int arrLength, int n) { 570 for (int i = 0; i < arrLength; i++) { 571 if (arr[i] == n) { 572 return true; 573 } 574 } 575 576 return false; 577 } 578 579 private Node[] findDropedNodes(Node folder, Node[] dragNodes) { 580 if ((folder == null) || (dragNodes.length == 0)) { 581 return null; 582 } 583 584 Node[] dropNodes = new Node[dragNodes.length]; 585 Children children = folder.getChildren(); 586 587 for (int i = 0; i < dragNodes.length; i++) { 588 dropNodes[i] = children.findChild(dragNodes[i].getName()); 589 } 590 591 return dropNodes; 592 } 593 594 595 596 private boolean canDrop(Node n, int dropAction, Transferable dndEventTransferable) { 598 if (n == null) { 599 return false; 600 } 601 602 if ((view.getAllowedDropActions() & dropAction) == 0) { 604 return false; 605 } 606 607 if ((DnDConstants.ACTION_MOVE & dropAction) != 0) { 610 Node[] nodes = ExplorerDnDManager.getDefault().getDraggedNodes(); 611 612 if (nodes != null) { 613 for (int i = 0; i < nodes.length; i++) { 614 if (n.equals(nodes[i].getParentNode())) { 615 return false; 616 } 617 } 618 } 619 } 620 621 Transferable trans = ExplorerDnDManager.getDefault().getDraggedTransferable( 622 (DnDConstants.ACTION_MOVE & dropAction) != 0 623 ); 624 625 if (trans == null) { 626 trans = dndEventTransferable; 627 if( null == trans ) { 628 return false; 629 } 630 } 631 632 PasteType pt = DragDropUtilities.getDropType(n, trans, dropAction, dropIndex); 634 635 return (pt != null); 636 } 637 638 641 public void drop(DropTargetDropEvent dtde) { 642 stopDragging(); 643 644 Node dropNode = getNodeForDrop(dtde.getLocation()); 646 647 if (dropNode == null) { 649 dropNode = view.manager.getRootContext (); 650 } else if (pointAt != DragDropUtilities.NODE_CENTRAL) { 651 dropNode = dropNode.getParentNode(); 652 } 653 654 Node[] dragNodes = ExplorerDnDManager.getDefault().getDraggedNodes(); 655 int dropAction = ExplorerDnDManager.getDefault().getAdjustedDropAction( 656 dtde.getDropAction(), view.getAllowedDropActions() 657 ); 658 659 ExplorerDnDManager.getDefault().setMaybeExternalDragAndDrop( false ); 660 661 dtde.acceptDrop(dropAction); 663 664 if (!canDrop(dropNode, dropAction, dtde.getTransferable())) { 665 if( null != dragNodes && canReorderWhenMoving(dropNode, dragNodes)) { 666 performReorder(dropNode, dragNodes, lowerNodeIdx, upperNodeIdx); 667 dtde.dropComplete(true); 668 } else { 669 dtde.dropComplete(false); 670 } 671 672 return; 673 } 674 675 if (DnDConstants.ACTION_LINK == dropAction && null != dragNodes) { 676 PasteType[] ptCut = new PasteType[] { }; 678 679 PasteType[] ptCopy = new PasteType[] { }; 681 682 if ((ExplorerDnDManager.getDefault().getNodeAllowedActions() & DnDConstants.ACTION_MOVE) != 0) { 684 ptCut = DragDropUtilities.getPasteTypes( 685 dropNode, ExplorerDnDManager.getDefault().getDraggedTransferable(true) 686 ); 687 } 688 689 if ((ExplorerDnDManager.getDefault().getNodeAllowedActions() & DnDConstants.ACTION_COPY) != 0) { 691 ptCopy = DragDropUtilities.getPasteTypes( 692 dropNode, ExplorerDnDManager.getDefault().getDraggedTransferable(false) 693 ); 694 } 695 696 TreeSet <PasteType> setPasteTypes = new TreeSet <PasteType>( 697 new Comparator <PasteType>() { 698 public int compare(PasteType obj1, PasteType obj2) { 699 return obj1.getName().compareTo(obj2.getName()); 700 701 } 702 } 703 ); 704 705 for (int i = 0; i < ptCut.length; i++) { 706 setPasteTypes.add(ptCut[i]); 708 } 709 710 for (int i = 0; i < ptCopy.length; i++) { 711 setPasteTypes.add(ptCopy[i]); 713 } 714 715 DragDropUtilities.createDropFinishPopup(setPasteTypes).show( 716 tree, Math.max(dtde.getLocation().x - 5, 0), Math.max(dtde.getLocation().y - 5, 0) 717 ); 718 719 if (canReorder(dropNode, dragNodes)) { 721 final Node tempDropNode = dropNode; 722 final int tmpUpper = upperNodeIdx; 723 final int tmpLower = lowerNodeIdx; 724 final Node[] tempDragNodes = dragNodes; 725 DragDropUtilities.setPostDropRun( 726 new Runnable () { 727 public void run() { 728 performReorder( 729 tempDropNode, findDropedNodes(tempDropNode, tempDragNodes), tmpLower, tmpUpper 730 ); 731 } 732 } 733 ); 734 } 735 } else if( dropAction != DnDConstants.ACTION_LINK ) { 736 Transferable t = ExplorerDnDManager.getDefault().getDraggedTransferable( (DnDConstants.ACTION_MOVE & dropAction) != 0 ); 738 if( null == t ) { 739 t = dtde.getTransferable(); 740 } 741 PasteType pt = DragDropUtilities.getDropType( dropNode, t, dropAction, dropIndex ); 742 743 final Node[] preNodes = dropNode.getChildren().getNodes( true ); 745 final Node parentNode = dropNode; 746 747 Node[] diffNodes = DragDropUtilities.performPaste(pt, dropNode); 748 749 ExplorerDnDManager.getDefault().setDraggedNodes(diffNodes); 750 751 SwingUtilities.invokeLater( new Runnable () { 754 public void run() { 755 Node[] diffNodes = getDiffNodes( parentNode, preNodes ); 756 if( canReorder( parentNode, diffNodes ) ) { 757 performReorder( parentNode, diffNodes, lowerNodeIdx, upperNodeIdx ); 758 } 759 } 760 }); 761 } 762 763 TreeCellEditor tce = tree.getCellEditor(); 764 765 if (tce instanceof TreeViewCellEditor) { 766 ((TreeViewCellEditor) tce).setDnDActive(false); 767 } 768 769 dtde.dropComplete(true); 771 } 772 773 private Node[] getDiffNodes( Node parent, Node[] childrenBefore ) { 774 Node[] childrenCurrent = parent.getChildren().getNodes(true); 775 776 List <Node> pre = Arrays.asList(childrenBefore); 778 List <Node> post = Arrays.asList(childrenCurrent); 779 Iterator <Node> it = post.iterator(); 780 List <Node> diff = new ArrayList <Node>(); 781 782 while (it.hasNext()) { 783 Node n = it.next(); 784 785 if (!pre.contains(n)) { 786 diff.add(n); 787 } 788 } 789 790 return diff.toArray(new Node[diff.size()]); 791 } 792 793 798 public void activate(boolean active) { 799 if (this.active == active) { 800 return; 801 } 802 803 this.active = active; 804 getDropTarget().setActive(active); 805 } 806 807 809 public void run() { 810 if (!SwingUtilities.isEventDispatchThread()) { 811 SwingUtilities.invokeLater(this); 812 813 return; 814 } 815 816 DragDropUtilities.dropNotSuccesfull(); 817 } 818 819 823 TreePath getTreePath(DropTargetDragEvent dtde, int dropAction) { 824 Point location = dtde.getLocation(); 826 TreePath tp = tree.getPathForLocation(location.x, location.y); 827 if( null == tp ) { 828 tp = tree.getPathForLocation(location.x, location.y-tree.getRowHeight()/2); 830 } 831 832 return ((tp != null) && (DragDropUtilities.secureFindNode(tp.getLastPathComponent()) != null)) ? tp : null; 833 } 834 835 837 DropTarget getDropTarget() { 838 if (dropTarget == null) { 839 dropTarget = new DropTarget(tree, view.getAllowedDropActions(), this, false); 840 } 841 842 return dropTarget; 843 } 844 } 845 846 | Popular Tags |