View | Details | Raw Unified | Return to bug 54864
Collapse All | Expand All

(-)src/core/org/apache/jmeter/gui/tree/JMeterTreeTransferHandler.java (-49 / +113 lines)
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
- 

Return to bug 54864