Lines 21-26
package org.apache.jmeter.gui.tree;
Link Here
|
21 |
import java.awt.datatransfer.DataFlavor; |
21 |
import java.awt.datatransfer.DataFlavor; |
22 |
import java.awt.datatransfer.Transferable; |
22 |
import java.awt.datatransfer.Transferable; |
23 |
import java.awt.datatransfer.UnsupportedFlavorException; |
23 |
import java.awt.datatransfer.UnsupportedFlavorException; |
|
|
24 |
import java.util.ArrayList; |
25 |
import java.util.Arrays; |
26 |
import java.util.Comparator; |
27 |
import java.util.Enumeration; |
28 |
import java.util.List; |
24 |
|
29 |
|
25 |
import javax.swing.JComponent; |
30 |
import javax.swing.JComponent; |
26 |
import javax.swing.JTree; |
31 |
import javax.swing.JTree; |
Lines 40-50
public class JMeterTreeTransferHandler extends TransferHandler {
Link Here
|
40 |
|
45 |
|
41 |
private DataFlavor nodeFlavor; |
46 |
private DataFlavor nodeFlavor; |
42 |
private DataFlavor[] jMeterTreeNodeDataFlavors = new DataFlavor[1]; |
47 |
private DataFlavor[] jMeterTreeNodeDataFlavors = new DataFlavor[1]; |
|
|
48 |
|
49 |
// hold the nodes that should be removed on drop |
50 |
private List<JMeterTreeNode> nodesForRemoval = null; |
43 |
|
51 |
|
44 |
public JMeterTreeTransferHandler() { |
52 |
public JMeterTreeTransferHandler() { |
45 |
try { |
53 |
try { |
46 |
String mimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=\"" + JMeterTreeNode[].class.getName() + "\""; |
54 |
// only allow a drag&drop inside the current jvm |
47 |
nodeFlavor = new DataFlavor(mimeType); |
55 |
String jvmLocalFlavor = DataFlavor.javaJVMLocalObjectMimeType + ";class=\"" + JMeterTreeNode[].class.getName() + "\""; |
|
|
56 |
nodeFlavor = new DataFlavor(jvmLocalFlavor); |
48 |
jMeterTreeNodeDataFlavors[0] = nodeFlavor; |
57 |
jMeterTreeNodeDataFlavors[0] = nodeFlavor; |
49 |
} |
58 |
} |
50 |
catch (ClassNotFoundException e) { |
59 |
catch (ClassNotFoundException e) { |
Lines 61-81
public class JMeterTreeTransferHandler extends TransferHandler {
Link Here
|
61 |
|
70 |
|
62 |
@Override |
71 |
@Override |
63 |
protected Transferable createTransferable(JComponent c) { |
72 |
protected Transferable createTransferable(JComponent c) { |
|
|
73 |
this.nodesForRemoval = null; |
64 |
JTree tree = (JTree) c; |
74 |
JTree tree = (JTree) c; |
65 |
TreePath[] paths = tree.getSelectionPaths(); |
75 |
TreePath[] paths = tree.getSelectionPaths(); |
66 |
if (paths != null) { |
76 |
if (paths != null) { |
67 |
|
|
|
68 |
//TODO : deal with all the selected nodes |
69 |
JMeterTreeNode node = (JMeterTreeNode) paths[0].getLastPathComponent(); |
70 |
|
77 |
|
71 |
return new NodesTransferable(new JMeterTreeNode[] {node}); |
78 |
// sort the selected tree path by row |
|
|
79 |
sortTreePathByRow(paths, tree); |
80 |
|
81 |
// if child and a parent are selected : only keep the parent |
82 |
boolean[] toRemove = new boolean[paths.length]; |
83 |
int size = paths.length; |
84 |
for (int i = 0; i < paths.length; i++) { |
85 |
for (int j = 0; j < paths.length; j++) { |
86 |
if(i!=j && ((JMeterTreeNode)paths[i].getLastPathComponent()).isNodeAncestor((JMeterTreeNode)paths[j].getLastPathComponent())) { |
87 |
toRemove[i] = true; |
88 |
size--; |
89 |
break; |
90 |
} |
91 |
} |
92 |
} |
93 |
|
94 |
// remove unneeded nodes |
95 |
JMeterTreeNode[] nodes = new JMeterTreeNode[size]; |
96 |
size = 0; |
97 |
for (int i = 0; i < paths.length; i++) { |
98 |
if(!toRemove[i]) { |
99 |
JMeterTreeNode node = (JMeterTreeNode) paths[i].getLastPathComponent(); |
100 |
nodes[size++] = node; |
101 |
} |
102 |
} |
103 |
|
104 |
return new NodesTransferable(nodes); |
72 |
} |
105 |
} |
73 |
|
106 |
|
74 |
return null; |
107 |
return null; |
75 |
} |
108 |
} |
76 |
|
109 |
|
|
|
110 |
|
111 |
private static void sortTreePathByRow(TreePath[] paths, final JTree tree) { |
112 |
Comparator<TreePath> cp = new Comparator<TreePath>() { |
113 |
|
114 |
@Override |
115 |
public int compare(TreePath o1, TreePath o2) { |
116 |
int row1 = tree.getRowForPath(o1); |
117 |
int row2 = tree.getRowForPath(o2); |
118 |
|
119 |
return (row1<row2 ? -1 : (row1==row2 ? 0 : 1)); |
120 |
} |
121 |
}; |
122 |
|
123 |
Arrays.sort(paths, cp); |
124 |
} |
125 |
|
126 |
|
77 |
@Override |
127 |
@Override |
78 |
protected void exportDone(JComponent source, Transferable data, int action) { |
128 |
protected void exportDone(JComponent source, Transferable data, int action) { |
|
|
129 |
|
130 |
if(this.nodesForRemoval != null |
131 |
&& ((action & MOVE) == MOVE)) { |
132 |
GuiPackage guiInstance = GuiPackage.getInstance(); |
133 |
for (JMeterTreeNode jMeterTreeNode : nodesForRemoval) { |
134 |
guiInstance.getTreeModel().removeNodeFromParent(jMeterTreeNode); |
135 |
} |
136 |
|
137 |
nodesForRemoval = null; |
138 |
} |
79 |
} |
139 |
} |
80 |
|
140 |
|
81 |
@Override |
141 |
@Override |
Lines 108-121
public class JMeterTreeTransferHandler extends TransferHandler {
Link Here
|
108 |
|
168 |
|
109 |
// Do not allow a drop on the drag source selections. |
169 |
// Do not allow a drop on the drag source selections. |
110 |
JTree.DropLocation dl = (JTree.DropLocation) support.getDropLocation(); |
170 |
JTree.DropLocation dl = (JTree.DropLocation) support.getDropLocation(); |
111 |
JTree tree = (JTree) support.getComponent(); |
|
|
112 |
int dropRow = tree.getRowForPath(dl.getPath()); |
113 |
int[] selRows = tree.getSelectionRows(); |
114 |
for (int i = 0; i < selRows.length; i++) { |
115 |
if (selRows[i] == dropRow) { |
116 |
return false; |
117 |
} |
118 |
} |
119 |
|
171 |
|
120 |
TreePath dest = dl.getPath(); |
172 |
TreePath dest = dl.getPath(); |
121 |
JMeterTreeNode target = (JMeterTreeNode) dest.getLastPathComponent(); |
173 |
JMeterTreeNode target = (JMeterTreeNode) dest.getLastPathComponent(); |
Lines 125-141
public class JMeterTreeTransferHandler extends TransferHandler {
Link Here
|
125 |
return false; |
177 |
return false; |
126 |
} |
178 |
} |
127 |
|
179 |
|
128 |
TreePath path = tree.getPathForRow(selRows[0]); |
180 |
JMeterTreeNode[] nodes = getDraggedNodes(support.getTransferable()); |
129 |
JMeterTreeNode draggedNode = (JMeterTreeNode) path.getLastPathComponent(); |
181 |
if(nodes == null || nodes.length == 0) { |
130 |
|
|
|
131 |
// Do not allow a non-leaf node to be moved into one of its children |
132 |
if (draggedNode.getChildCount() > 0 |
133 |
&& target.isNodeAncestor(draggedNode)) { |
134 |
return false; |
182 |
return false; |
135 |
} |
183 |
} |
136 |
|
184 |
|
|
|
185 |
for (int i = 0; i < nodes.length; i++) { |
186 |
if(target == nodes[i]) { |
187 |
return false; |
188 |
} |
189 |
|
190 |
// Do not allow a non-leaf node to be moved into one of its children |
191 |
if (nodes[i].getChildCount() > 0 |
192 |
&& target.isNodeAncestor(nodes[i])) { |
193 |
return false; |
194 |
} |
195 |
} |
196 |
|
137 |
// re-use node association logic |
197 |
// re-use node association logic |
138 |
return MenuFactory.canAddTo(target, new JMeterTreeNode[] { draggedNode }); |
198 |
return MenuFactory.canAddTo(target, nodes); |
139 |
} |
199 |
} |
140 |
|
200 |
|
141 |
|
201 |
|
Lines 163-175
public class JMeterTreeTransferHandler extends TransferHandler {
Link Here
|
163 |
} |
223 |
} |
164 |
|
224 |
|
165 |
// Extract transfer data. |
225 |
// Extract transfer data. |
166 |
JMeterTreeNode[] nodes = null; |
226 |
JMeterTreeNode[] nodes = getDraggedNodes(t); |
167 |
try { |
|
|
168 |
nodes = (JMeterTreeNode[]) t.getTransferData(nodeFlavor); |
169 |
} |
170 |
catch (Exception e) { |
171 |
LOG.error("Unsupported Flavor in Transferable", e); |
172 |
} |
173 |
|
227 |
|
174 |
if(nodes == null || nodes.length == 0) { |
228 |
if(nodes == null || nodes.length == 0) { |
175 |
return false; |
229 |
return false; |
Lines 180-207
public class JMeterTreeTransferHandler extends TransferHandler {
Link Here
|
180 |
TreePath dest = dl.getPath(); |
234 |
TreePath dest = dl.getPath(); |
181 |
JMeterTreeNode target = (JMeterTreeNode) dest.getLastPathComponent(); |
235 |
JMeterTreeNode target = (JMeterTreeNode) dest.getLastPathComponent(); |
182 |
|
236 |
|
183 |
//TODO : deal with all the selected nodes |
237 |
nodesForRemoval = new ArrayList<JMeterTreeNode>(); |
184 |
JMeterTreeNode draggedNode = nodes[0]; |
|
|
185 |
|
186 |
int index = dl.getChildIndex(); |
238 |
int index = dl.getChildIndex(); |
187 |
if (index == -1) { // drop mode is ON |
239 |
for (int i = 0; i < nodes.length; i++) { |
188 |
index = target.getChildCount(); |
240 |
|
189 |
if(draggedNode.getParent() == target) { |
241 |
if (index == -1) { // drop mode == DropMode.ON |
190 |
//when the target is the current parent of the node being dragged |
242 |
index = target.getChildCount(); |
191 |
// re-add it as the last child |
|
|
192 |
index--; |
193 |
} |
243 |
} |
194 |
} |
244 |
|
195 |
else if(draggedNode.getParent() == target) { // insert mode |
245 |
// Insert a clone of the node, the original one will be removed by the exportDone method |
196 |
if(guiInstance.getTreeModel().getIndexOfChild(target, draggedNode) < index) { |
246 |
// the children are not cloned but moved to the cloned node |
197 |
index--; |
247 |
// working on the original node would be harder as |
|
|
248 |
// you'll have to deal with the insertion index offset if you re-order a node inside a parent |
249 |
JMeterTreeNode copy = (JMeterTreeNode) nodes[i].clone(); |
250 |
Enumeration<?> enumFrom = nodes[i].children(); |
251 |
while (enumFrom.hasMoreElements()) { |
252 |
JMeterTreeNode child = (JMeterTreeNode) enumFrom.nextElement(); |
253 |
copy.add(child); |
198 |
} |
254 |
} |
199 |
} |
255 |
|
200 |
|
256 |
guiInstance.getTreeModel().insertNodeInto(copy, target, index++); |
201 |
// remove - add the nodes |
257 |
nodesForRemoval.add(nodes[i]); |
202 |
for (int i = 0; i < nodes.length; i++) { |
|
|
203 |
guiInstance.getTreeModel().removeNodeFromParent(nodes[i]); |
204 |
guiInstance.getTreeModel().insertNodeInto(nodes[i], target, index); |
205 |
} |
258 |
} |
206 |
|
259 |
|
207 |
// expand the destination node |
260 |
// expand the destination node |
Lines 211-216
public class JMeterTreeTransferHandler extends TransferHandler {
Link Here
|
211 |
return true; |
264 |
return true; |
212 |
} |
265 |
} |
213 |
|
266 |
|
|
|
267 |
|
268 |
private JMeterTreeNode[] getDraggedNodes(Transferable t) { |
269 |
JMeterTreeNode[] nodes = null; |
270 |
try { |
271 |
nodes = (JMeterTreeNode[]) t.getTransferData(nodeFlavor); |
272 |
} |
273 |
catch (Exception e) { |
274 |
LOG.error("Unsupported Flavor in Transferable", e); |
275 |
} |
276 |
return nodes; |
277 |
} |
278 |
|
214 |
private class NodesTransferable implements Transferable { |
279 |
private class NodesTransferable implements Transferable { |
215 |
JMeterTreeNode[] nodes; |
280 |
JMeterTreeNode[] nodes; |
216 |
|
281 |
|
217 |
- |
|
|