KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > explorer > view > TreeViewDropSupport


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.explorer.view;
20
21 import java.util.logging.Level JavaDoc;
22 import java.util.logging.Logger JavaDoc;
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 JavaDoc;
29 import java.awt.Point JavaDoc;
30 import java.awt.Rectangle JavaDoc;
31 import java.awt.datatransfer.Transferable JavaDoc;
32 import java.awt.dnd.*;
33 import java.awt.event.ActionEvent JavaDoc;
34 import java.awt.event.ActionListener JavaDoc;
35 import java.awt.geom.Line2D JavaDoc;
36 import java.awt.geom.Line2D.Double;
37 import java.util.ArrayList JavaDoc;
38
39 import java.util.Arrays JavaDoc;
40 import java.util.Comparator JavaDoc;
41 import java.util.Iterator JavaDoc;
42 import java.util.List JavaDoc;
43 import java.util.TreeSet JavaDoc;
44
45 import javax.swing.JTree JavaDoc;
46 import javax.swing.SwingUtilities JavaDoc;
47 import javax.swing.Timer JavaDoc;
48 import javax.swing.tree.TreeCellEditor JavaDoc;
49 import javax.swing.tree.TreePath JavaDoc;
50
51 /** Implementation of drop support for asociated Tree View.
52 *
53 * @author Dafe Simonek, Jiri Rechtacek
54 */

55 final class TreeViewDropSupport implements DropTargetListener, Runnable JavaDoc {
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     // Attributes
63

64     /** true if support is active, false otherwise */
65     boolean active = false;
66     boolean dropTargetPopupAllowed;
67
68     /** Drop target asociated with the tree */
69     DropTarget dropTarget;
70
71     /** Node area which we were during
72     * DnD operation. */

73     Rectangle JavaDoc lastNodeArea;
74     private int upperNodeIdx = -1;
75     private int lowerNodeIdx = -1;
76     private int dropIndex = -1;
77
78     /** Swing Timer for expand node's parent with delay time. */
79     Timer JavaDoc timer;
80
81     /** Glass pane for JTree which is associate with this class. */
82     DropGlassPane dropPane;
83     private int pointAt = DragDropUtilities.NODE_CENTRAL;
84
85     // Associations
86

87     /** View manager. */
88     protected TreeView view;
89
90     /** The component we are supporting with drop support */
91     protected JTree JavaDoc tree;
92
93     // Operations
94

95     /** Creates new TreeViewDropSupport */
96     public TreeViewDropSupport(TreeView view, JTree JavaDoc 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     /** User is starting to drag over us */
111     public void dragEnter(DropTargetDragEvent dtde) {
112         checkStoredGlassPane();
113
114         dropIndex = -1;
115         
116         // set a status and cursor of dnd action
117
doDragOver(dtde);
118     }
119
120     /** User drags over us */
121     public void dragOver(DropTargetDragEvent dtde) {
122         // bugfix #34483; jdk1.4.1 on w2k could calls dragOver() before dragEnter()
123
// (jkdbug fixed in 1.4.2)
124
// this check make dragOver/Enter more robust
125
checkStoredGlassPane();
126
127         // set a status and cursor of dnd action
128
doDragOver(dtde);
129     }
130
131     private void checkStoredGlassPane() {
132         // remember current glass pane to set back at end of dragging over this compoment
133
if (!DropGlassPane.isOriginalPaneStored()) {
134             Component JavaDoc comp = tree.getRootPane().getGlassPane();
135             DropGlassPane.setOriginalPane(tree, comp, comp.isVisible());
136
137             // set glass pane for paint selection line
138
dropPane = DropGlassPane.getDefault(tree);
139             tree.getRootPane().setGlassPane(dropPane);
140             dropPane.revalidate();
141             dropPane.setVisible(true);
142         }
143     }
144
145     /** Process events dragEnter or dragOver. */
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         // 1. test if I'm over any node
156
TreePath JavaDoc tp = getTreePath(dtde, dropAction);
157         Node dropNode;
158         
159         // 2. find node for drop
160
Point JavaDoc p = dtde.getLocation();
161         if (tp == null) {
162             // #64469: Can't drop into empty explorer area
163
dropNode = view.manager.getRootContext ();
164             if (canDrop(dropNode, dropAction, dtde.getTransferable())) {
165                 // ok, root accept
166
dtde.acceptDrag(dropAction);
167             } else {
168                 dtde.rejectDrag();
169             }
170             return ;
171         } else {
172             dropNode = getNodeForDrop(p);
173         }
174
175         // if I haven't any node for drop then reject drop
176
if (dropNode == null) {
177             dropIndex = -1;
178             dtde.rejectDrag();
179             removeDropLine();
180
181             return;
182         }
183
184         Rectangle JavaDoc 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                 // don't get line above root
193
if (row != 0) {
194                     // point above node
195
pointAt = DragDropUtilities.NODE_UP;
196
197                     TreePath JavaDoc 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                     // drop candidate is parent
207
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                 // exclude expanded folder
214
if (!view.isExpanded(dropNode)) {
215                     // point bellow node
216
pointAt = DragDropUtilities.NODE_DOWN;
217
218                     TreePath JavaDoc 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                     // drop candidate is parent
228
if (dropNode.getParentNode() != null) {
229                         dropNode = dropNode.getParentNode();
230                         tp = null;
231                     }
232                 }
233             }
234         }
235
236         endPointX = endPointX + SHIFT_RIGHT;
237
238         // 2.b. check index cookie
239
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         // 3. expand with a delay
255
if (
256             ((timer == null) || !timer.isRunning()) && (dropNode != null) && !dropNode.isLeaf() &&
257                 !view.isExpanded(dropNode)
258         ) {
259             // ok, let's expand in a while
260
// node is candidate for expand
261
final Node cn = dropNode;
262
263             // remove old timer
264
removeTimer();
265
266             // create new timer
267
timer = new Timer JavaDoc(
268                     DELAY_TIME_FOR_EXPAND,
269                     new ActionListener JavaDoc() {
270                         final public void actionPerformed(ActionEvent JavaDoc e) {
271                             view.expandNode(cn);
272                         }
273                     }
274                 );
275             timer.setRepeats(false);
276             timer.start();
277         }
278
279         // 4. present node for drop
280
// prepare selection or line
281
if (pointAt == DragDropUtilities.NODE_CENTRAL) {
282             // no line
283
dropPane.setDropLine(null);
284         } else {
285             // line and selection of parent if any
286
if (pointAt == DragDropUtilities.NODE_UP) {
287                 Line2D JavaDoc line = new Double JavaDoc(
288                         nodeArea.x - SHIFT_LEFT, nodeArea.y + SHIFT_DOWN, endPointX, nodeArea.y + SHIFT_DOWN
289                     );
290                 convertBoundsAndSetDropLine(line);
291
292                 // enlagre node area with area for line
293
Rectangle JavaDoc lineArea = new Rectangle JavaDoc(
294                         nodeArea.x - SHIFT_LEFT, (nodeArea.y + SHIFT_DOWN) - 3, endPointX - nodeArea.x + SHIFT_LEFT, 5
295                     );
296                 nodeArea = (Rectangle JavaDoc) nodeArea.createUnion(lineArea);
297             } else {
298                 Line2D JavaDoc line = new Double JavaDoc(
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                 // enlagre node area with area for line
305
Rectangle JavaDoc lineArea = new Rectangle JavaDoc(
306                         nodeArea.x - SHIFT_LEFT, nodeArea.y + nodeArea.height, endPointX - nodeArea.x + SHIFT_LEFT,
307                         SHIFT_DOWN + 3
308                     );
309                 nodeArea = (Rectangle JavaDoc) nodeArea.createUnion(lineArea);
310             }
311
312             // the parent node won't be selected
313

314             /*// select parent and enlarge paint area
315             if (tp.getParentPath ()!=null) {
316                 tp = tp.getParentPath ();
317             }
318             nodeArea = (Rectangle)nodeArea.createUnion (tree.getPathBounds (tp));*/

319         }
320
321         // back normal view w/o any selecetion nor line
322
if ((lastNodeArea != null) && (!lastNodeArea.equals(nodeArea))) {
323             NodeRenderer.dragExit();
324             repaint(lastNodeArea);
325         }
326
327         // paint new state
328
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         // 5. show to cursor belong to state
339
if (canDrop(dropNode, dropAction, dtde.getTransferable())) {
340             // ok, can accept
341
dtde.acceptDrag(dropAction);
342         } else {
343             // can only reorder?
344
Node[] draggedNodes = ExplorerDnDManager.getDefault().getDraggedNodes();
345             if( null != draggedNodes && canReorderWhenMoving(dropNode, draggedNodes) ) {
346                 // ok, can accept only reoder
347
dtde.acceptDrag(dropAction);
348             } else {
349                 dtde.rejectDrag();
350             }
351         }
352     }
353
354     /** Repaints TreeView, the given rectangle is enlarged for 5 pixels
355      * because some parts was not repainted correctly.
356      * @param Rectangle r rectangle which will be repainted.*/

357     private void repaint(Rectangle JavaDoc r) {
358         tree.repaint(r.x - 5, r.y - 5, r.width + 10, r.height + 10);
359     }
360
361     /** Converts line's bounds by the bounds of the root pane. Drop glass pane
362      * is over this root pane. After covert a given line is set to drop glass pane.
363      * @param line line for show in drop glass pane */

364     private void convertBoundsAndSetDropLine(final Line2D JavaDoc 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 JavaDoc p1 = SwingUtilities.convertPoint(tree, x1, y1, tree.getRootPane());
370         Point JavaDoc p2 = SwingUtilities.convertPoint(tree, x2, y2, tree.getRootPane());
371         line.setLine(p1, p2);
372         dropPane.setDropLine(line);
373     }
374
375     /** Removes timer and all listeners. */
376     private void removeTimer() {
377         if (timer != null) {
378             ActionListener JavaDoc[] l = (ActionListener JavaDoc[]) timer.getListeners(ActionListener JavaDoc.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         // check if the nodes are willing to do selected action
391
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                     // this action is not supported
403
dtde.rejectDrag();
404
405                     return;
406                 }
407             }
408         }
409
410         return;
411     }
412
413     /** User exits the dragging */
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         // set back the remembered glass pane
438
if (DropGlassPane.isOriginalPaneStored()) {
439             DropGlassPane.putBackOriginal();
440         }
441     }
442
443     /** Get a node on given point or null if there none*/
444     private Node getNodeForDrop(Point JavaDoc p) {
445         if (p != null) {
446             TreePath JavaDoc tp = tree.getPathForLocation(p.x, p.y);
447             if( null == tp ) {
448                 //make the drop area a bit bigger at the end of the tree
449
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         // has folder a index cookie?
473
Index ic = (Index) folder.getCookie(Index.class);
474
475         if (ic == null) {
476             return false;
477         }
478
479         // folder has index cookie
480
// check if all dragNodes are from same folder
481
for (int i = 0; i < dragNodes.length; i++) {
482             // bugfix #23988, check if dragNodes[i] isn't null
483
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                 // XXX: normally indexes of dragged nodes should be in ascending order, but
517
// it seems that Tree.getSelectionPaths doesn't keep this order
518
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                 // check for identity permutation
555
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 JavaDoc e) {
564             // Pending: add annotation or remove try/catch block
565
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     /** Can node recieve given drop action? */
595
596     // XXX canditate for more general support
597
private boolean canDrop(Node n, int dropAction, Transferable JavaDoc dndEventTransferable) {
598         if (n == null) {
599             return false;
600         }
601
602         // Test to see if the target node supports the drop action
603
if ((view.getAllowedDropActions() & dropAction) == 0) {
604             return false;
605         }
606
607         // test if a parent of the dragged nodes isn't the node over
608
// only for MOVE action
609
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 JavaDoc 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         // get paste types for given transferred transferable
633
PasteType pt = DragDropUtilities.getDropType(n, trans, dropAction, dropIndex);
634
635         return (pt != null);
636     }
637
638     /** Performs the drop action, if we are dropping on
639     * right node and target node agrees.
640     */

641     public void drop(DropTargetDropEvent dtde) {
642         stopDragging();
643
644         // find node for the drop perform
645
Node dropNode = getNodeForDrop(dtde.getLocation());
646         
647         // #64469: Can't drop into empty explorer area
648
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         // finally perform the drop
662
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             // construct all paste types
677
PasteType[] ptCut = new PasteType[] { };
678
679             // construct all paste types
680
PasteType[] ptCopy = new PasteType[] { };
681
682             // do not try get paste types for move if MOVE is not allowed
683
if ((ExplorerDnDManager.getDefault().getNodeAllowedActions() & DnDConstants.ACTION_MOVE) != 0) {
684                 ptCut = DragDropUtilities.getPasteTypes(
685                         dropNode, ExplorerDnDManager.getDefault().getDraggedTransferable(true)
686                     );
687             }
688
689             // do not try get paste types for copy if COPY is not allowed
690
if ((ExplorerDnDManager.getDefault().getNodeAllowedActions() & DnDConstants.ACTION_COPY) != 0) {
691                 ptCopy = DragDropUtilities.getPasteTypes(
692                         dropNode, ExplorerDnDManager.getDefault().getDraggedTransferable(false)
693                     );
694             }
695
696             TreeSet JavaDoc<PasteType> setPasteTypes = new TreeSet JavaDoc<PasteType>(
697                     new Comparator JavaDoc<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                 //System.out.println(ptCut[i].getName()+", "+System.identityHashCode(ptCut[i]));
707
setPasteTypes.add(ptCut[i]);
708             }
709
710             for (int i = 0; i < ptCopy.length; i++) {
711                 //System.out.println(ptCopy[i].getName()+", "+System.identityHashCode(ptCopy[i]));
712
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             // reorder have to be perform
720
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 JavaDoc() {
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             // get correct paste type
737
Transferable JavaDoc 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             //remember the Nodes before the drop
744
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             //postpone the potential re-order so that the drop Node has enough
752
//time to re-create its children
753
SwingUtilities.invokeLater( new Runnable JavaDoc() {
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 JavaDoc tce = tree.getCellEditor();
764
765         if (tce instanceof TreeViewCellEditor) {
766             ((TreeViewCellEditor) tce).setDnDActive(false);
767         }
768
769         // finished
770
dtde.dropComplete(true);
771     }
772
773     private Node[] getDiffNodes( Node parent, Node[] childrenBefore ) {
774         Node[] childrenCurrent = parent.getChildren().getNodes(true);
775
776         // calculate new nodes
777
List JavaDoc<Node> pre = Arrays.asList(childrenBefore);
778         List JavaDoc<Node> post = Arrays.asList(childrenCurrent);
779         Iterator JavaDoc<Node> it = post.iterator();
780         List JavaDoc<Node> diff = new ArrayList JavaDoc<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     /** Activates or deactivates Drag support on asociated JTree
794     * component
795     * @param active true if the support should be active, false
796     * otherwise
797     */

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     /** Implementation of the runnable interface.
808     * Notifies user in AWT thread. */

809     public void run() {
810         if (!SwingUtilities.isEventDispatchThread()) {
811             SwingUtilities.invokeLater(this);
812
813             return;
814         }
815
816         DragDropUtilities.dropNotSuccesfull();
817     }
818
819     /** @return The tree path to the node the cursor is above now or
820     * null if no such node currently exists or if conditions were not
821     * satisfied to continue with DnD operation.
822     */

823     TreePath JavaDoc getTreePath(DropTargetDragEvent dtde, int dropAction) {
824         // check location
825
Point JavaDoc location = dtde.getLocation();
826         TreePath JavaDoc tp = tree.getPathForLocation(location.x, location.y);
827         if( null == tp ) {
828             //make the drop area a bit bigger at the end of the tree
829
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     /** Safe accessor to the drop target which is asociated
836     * with the tree */

837     DropTarget getDropTarget() {
838         if (dropTarget == null) {
839             dropTarget = new DropTarget(tree, view.getAllowedDropActions(), this, false);
840         }
841
842         return dropTarget;
843     }
844 }
845  /* end class TreeViewDropSupport */
846
Popular Tags