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

(-)src/core/org/apache/jmeter/resources/messages_fr.properties (+2 lines)
Lines 662-667 Link Here
662
read_soap_response=Lire la r\u00E9ponse SOAP
662
read_soap_response=Lire la r\u00E9ponse SOAP
663
realm=Univers (realm)
663
realm=Univers (realm)
664
record_controller_title=Contr\u00F4leur Enregistreur
664
record_controller_title=Contr\u00F4leur Enregistreur
665
redo=R\u00E9tablir
665
ref_name_field=Nom de r\u00E9f\u00E9rence \:
666
ref_name_field=Nom de r\u00E9f\u00E9rence \:
666
regex_extractor_title=Extracteur Expression r\u00E9guli\u00E8re
667
regex_extractor_title=Extracteur Expression r\u00E9guli\u00E8re
667
regex_field=Expression r\u00E9guli\u00E8re \:
668
regex_field=Expression r\u00E9guli\u00E8re \:
Lines 991-996 Link Here
991
transaction_controller_parent=G\u00E9n\u00E9rer en \u00E9chantillon parent
992
transaction_controller_parent=G\u00E9n\u00E9rer en \u00E9chantillon parent
992
transaction_controller_title=Contr\u00F4leur Transaction
993
transaction_controller_title=Contr\u00F4leur Transaction
993
unbind=D\u00E9connexion de l'unit\u00E9
994
unbind=D\u00E9connexion de l'unit\u00E9
995
undo=Annuler
994
unescape_html_string=Cha\u00EEne \u00E0 \u00E9chapper
996
unescape_html_string=Cha\u00EEne \u00E0 \u00E9chapper
995
unescape_string=Cha\u00EEne de caract\u00E8res contenant des\u00E9chappements Java
997
unescape_string=Cha\u00EEne de caract\u00E8res contenant des\u00E9chappements Java
996
uniform_timer_delay=D\u00E9lai de d\u00E9calage constant (en millisecondes) \:
998
uniform_timer_delay=D\u00E9lai de d\u00E9calage constant (en millisecondes) \:
(-)src/core/org/apache/jmeter/resources/messages.properties (-1 / +3 lines)
Lines 668-673 Link Here
668
read_soap_response=Read SOAP Response
668
read_soap_response=Read SOAP Response
669
realm=Realm
669
realm=Realm
670
record_controller_title=Recording Controller
670
record_controller_title=Recording Controller
671
redo=Redo
671
ref_name_field=Reference Name\:
672
ref_name_field=Reference Name\:
672
regex_extractor_title=Regular Expression Extractor
673
regex_extractor_title=Regular Expression Extractor
673
regex_field=Regular Expression\:
674
regex_field=Regular Expression\:
Lines 997-1002 Link Here
997
transaction_controller_parent=Generate parent sample
998
transaction_controller_parent=Generate parent sample
998
transaction_controller_title=Transaction Controller
999
transaction_controller_title=Transaction Controller
999
unbind=Thread Unbind
1000
unbind=Thread Unbind
1001
undo=Undo
1000
unescape_html_string=String to unescape
1002
unescape_html_string=String to unescape
1001
unescape_string=String containing Java escapes
1003
unescape_string=String containing Java escapes
1002
uniform_timer_delay=Constant Delay Offset (in milliseconds)\:
1004
uniform_timer_delay=Constant Delay Offset (in milliseconds)\:
Lines 1159-1162 Link Here
1159
xpath_tidy_show_warnings=Show warnings
1161
xpath_tidy_show_warnings=Show warnings
1160
you_must_enter_a_valid_number=You must enter a valid number
1162
you_must_enter_a_valid_number=You must enter a valid number
1161
zh_cn=Chinese (Simplified)
1163
zh_cn=Chinese (Simplified)
1162
zh_tw=Chinese (Traditional)
1164
zh_tw=Chinese (Traditional)
(-)src/core/org/apache/jmeter/gui/util/MenuFactory.java (+24 lines)
Lines 196-201 Link Here
196
    }
196
    }
197
197
198
    public static void addFileMenu(JPopupMenu menu) {
198
    public static void addFileMenu(JPopupMenu menu) {
199
        // the undo/redo as a standard goes first in Edit menus
200
        // maybe there's better place for them in JMeter?
201
        addUndoItems(menu); 
202
        
199
        addSeparator(menu);
203
        addSeparator(menu);
200
        menu.add(makeMenuItemRes("open", ActionNames.OPEN));// $NON-NLS-1$
204
        menu.add(makeMenuItemRes("open", ActionNames.OPEN));// $NON-NLS-1$
201
        menu.add(makeMenuItemRes("menu_merge", ActionNames.MERGE));// $NON-NLS-1$
205
        menu.add(makeMenuItemRes("menu_merge", ActionNames.MERGE));// $NON-NLS-1$
Lines 235-240 Link Here
235
        menu.add(makeMenuItemRes("help", ActionNames.HELP));// $NON-NLS-1$
239
        menu.add(makeMenuItemRes("help", ActionNames.HELP));// $NON-NLS-1$
236
    }
240
    }
237
241
242
    /**
243
     * Add undo / redo
244
     * @param menu JPopupMenu
245
     */
246
    private static void addUndoItems(JPopupMenu menu) {
247
        addSeparator(menu);
248
        JMenuItem redo = makeMenuItemRes("redo", ActionNames.REDO); //$NON-NLS-1$    
249
        redo.setAccelerator(KeyStrokes.REDO);
250
        // we could even show some hints on action being undone here
251
        // if this will be required (by passing those hints into history
252
        // records)
253
        redo.setEnabled(GuiPackage.getInstance().getTreeModel().canRedo());
254
        menu.add(redo);
255
        JMenuItem undo = makeMenuItemRes("undo", ActionNames.UNDO); //$NON-NLS-1$    
256
        undo.setAccelerator(KeyStrokes.UNDO);
257
        undo.setEnabled(GuiPackage.getInstance().getTreeModel().canUndo());
258
        menu.add(undo);
259
    }
260
261
    
238
    public static JMenu makeMenus(String[] categories, String label, String actionCommand) {
262
    public static JMenu makeMenus(String[] categories, String label, String actionCommand) {
239
        JMenu addMenu = new JMenu(label);
263
        JMenu addMenu = new JMenu(label);
240
        for (int i = 0; i < categories.length; i++) {
264
        for (int i = 0; i < categories.length; i++) {
(-)src/core/org/apache/jmeter/gui/tree/UndoHistory.java (+310 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.gui.tree;
20
21
import java.awt.event.ActionEvent;
22
import java.util.ArrayList;
23
import java.util.List;
24
25
import javax.swing.event.TreeModelEvent;
26
import javax.swing.event.TreeModelListener;
27
import javax.swing.tree.TreePath;
28
29
import org.apache.jmeter.engine.TreeCloner;
30
import org.apache.jmeter.gui.GuiPackage;
31
import org.apache.jmeter.gui.action.Load;
32
import org.apache.jmeter.gui.action.UndoCommand;
33
import org.apache.jorphan.collections.HashTree;
34
import org.apache.jorphan.logging.LoggingManager;
35
import org.apache.log.Logger;
36
37
/**
38
 * Users expected record situations: initial empty tree; before node deletion;
39
 * before node insertion; after each walk off edited node (modifyTestElement)
40
 * 
41
 */
42
public class UndoHistory implements TreeModelListener {
43
    /**
44
     * Avoid storing too many elements
45
     * @param <T>
46
     */
47
    private static class LimitedArrayList<T> extends ArrayList<T>{
48
        /**
49
         * 
50
         */
51
        private static final long serialVersionUID = -6574380490156356507L;
52
        private int limit;
53
54
        public LimitedArrayList(int limit){
55
            this.limit = limit;
56
        }
57
58
        @Override
59
        public boolean add(T item){
60
            if(this.size()+1 > limit) {
61
                this.remove(0);
62
            }
63
            return super.add(item);
64
        }
65
    }
66
67
    private static final int INITIAL_POS = -1;
68
    private static final Logger log = LoggingManager.getLoggerForClass();
69
70
    /**
71
     * History item
72
     */
73
    private static class HistoryItem {
74
75
        private final HashTree tree;
76
        private final TreePath path;
77
        // maybe the comment should be removed since it is not used yet
78
        private final String comment;
79
80
        /**
81
         * 
82
         * @param copy
83
         * @param apath
84
         * @param acomment
85
         */
86
        public HistoryItem(HashTree copy, TreePath apath, String acomment) {
87
            tree = copy;
88
            path = apath;
89
            comment = acomment;
90
        }
91
92
        /**
93
         * @return {@link HashTree}
94
         */
95
        public HashTree getKey() {
96
            return tree;
97
        }
98
99
        /**
100
         * 
101
         * @return {@link TreePath} 
102
         */
103
        public TreePath getValue() {
104
            return path;
105
        }
106
107
        /**
108
         * 
109
         * @return String comment
110
         */
111
        public String getComment() {
112
            return comment;
113
        }
114
    }
115
116
    private List<HistoryItem> history = new LimitedArrayList<HistoryItem>(25); // TODO Make this configurable or too many properties ?
117
    private int position = INITIAL_POS;
118
    /**
119
     * flag to prevent recursive actions
120
     */
121
    private boolean working = false;
122
    private boolean recording=true;
123
124
    public UndoHistory() {
125
    }
126
    
127
    /**
128
     * @return true if must not put in history
129
     */
130
    private boolean noop() {
131
        return !recording || working;
132
    }
133
    
134
    /**
135
     * 
136
     */
137
    public void clear() {
138
        if (noop()) {
139
            return;
140
        }
141
        log.debug("Clearing history", new Throwable());
142
        history.clear();
143
        position = INITIAL_POS;
144
    }
145
146
    /**
147
     * this method relies on the rule that the record in history made AFTER
148
     * change has been made to test plan
149
     * 
150
     * @param treeModel
151
     * @param path
152
     * @param comment
153
     */
154
    void add(JMeterTreeModel treeModel, TreePath path, String comment) {
155
        // don't add element if we are in the middle of undo/redo or a big loading
156
        if (noop()) {
157
            return;
158
        }
159
        if(log.isDebugEnabled()) {
160
            log.debug("Adding history element", new Throwable());
161
        }
162
        JMeterTreeNode root = (JMeterTreeNode) ((JMeterTreeNode) treeModel
163
                .getRoot());
164
        if (root.getChildCount() < 1) {
165
            return;
166
        }
167
168
        working = true;
169
        // get test plan tree
170
        HashTree tree = treeModel.getCurrentSubTree((JMeterTreeNode) treeModel
171
                .getRoot());
172
        // first clone to not convert original tree
173
        tree = (HashTree) tree.getTree(tree.getArray()[0]).clone();
174
175
        position++;
176
        while (history.size() > position) {
177
            log.debug("Removing further record, position: " + position
178
                    + ", size: " + history.size());
179
            history.remove(history.size() - 1);
180
        }
181
182
        // convert before clone!
183
        UndoCommand.convertSubTree(tree);
184
        TreeCloner cloner = new TreeCloner(false);
185
        tree.traverse(cloner);
186
        HashTree copy = cloner.getClonedTree();
187
188
        history.add(new HistoryItem(copy, path, comment));
189
190
        log.debug("Added history element, position: " + position + ", size: "
191
                + history.size());
192
        working = false;
193
    }
194
195
    public TreePath getRelativeState(int offset, JMeterTreeModel acceptorModel) {
196
        log.debug("Moving history from position " + position + " with step "
197
                + offset + ", size is " + history.size());
198
        if (offset < 0 && !canUndo()) {
199
            log.warn("Can't undo, we're already on the last record");
200
            return null;
201
        }
202
203
        if (offset > 0 && !canRedo()) {
204
            log.warn("Can't redo, we're already on the first record");
205
            return null;
206
        }
207
208
        position += offset;
209
210
        if (!history.isEmpty()) {
211
            HashTree newModel = history.get(position).getKey();
212
            acceptorModel.removeTreeModelListener(this);
213
            working = true;
214
            try {
215
                boolean res = Load.insertLoadedTree(
216
                        ActionEvent.ACTION_PERFORMED, newModel);
217
                if (!res) {
218
                    throw new RuntimeException("Loaded data is not TestPlan");
219
                }
220
221
            } catch (Exception ex) {
222
                log.error("Failed to load from history", ex);
223
            }
224
            acceptorModel.addTreeModelListener(this);
225
            working = false;
226
        }
227
        log.debug("Current position " + position + ", size is "
228
                + history.size());
229
        // select historical path
230
        return history.get(position).getValue();
231
    }
232
233
    /**
234
     * @return true if remaing items
235
     */
236
    public boolean canRedo() {
237
        return position < history.size() - 1;
238
    }
239
240
    /**
241
     * 
242
     * @return true if not at first element
243
     */
244
    public boolean canUndo() {
245
        return position > INITIAL_POS + 1;
246
    }
247
248
    public void treeNodesChanged(TreeModelEvent tme) {
249
        log.debug("Nodes changed");
250
    }
251
252
    /**
253
     * 
254
     */
255
    // is there better way to record test plan load events?
256
    // currently it records each node added separately
257
    public void treeNodesInserted(TreeModelEvent tme) {
258
        log.debug("Nodes inserted");
259
        final JMeterTreeModel sender = (JMeterTreeModel) tme.getSource();
260
        add(sender, getTreePathToRecord(tme), "Add");
261
    }
262
263
    /**
264
     * 
265
     */
266
    public void treeNodesRemoved(TreeModelEvent tme) {
267
        log.debug("Nodes removed");
268
        add((JMeterTreeModel) tme.getSource(), getTreePathToRecord(tme),
269
                "Remove");
270
    }
271
272
    /**
273
     * 
274
     */
275
    public void treeStructureChanged(TreeModelEvent tme) {
276
        log.debug("Nodes struct changed");
277
        add((JMeterTreeModel) tme.getSource(), getTreePathToRecord(tme),
278
                "Complex Change");
279
    }
280
281
    /**
282
     * 
283
     * @param tme TreeModelEvent
284
     * @return TreePath
285
     */
286
    private TreePath getTreePathToRecord(TreeModelEvent tme) {
287
        TreePath path;
288
        if (GuiPackage.getInstance() != null) {
289
            path = GuiPackage.getInstance().getMainFrame().getTree()
290
                    .getSelectionPath();
291
        } else {
292
            path = tme.getTreePath();
293
        }
294
        return path;
295
    }
296
297
    /**
298
     * Resume inserting in UndoHistory
299
     */
300
    public void resumeRecording() {
301
        this.recording=true;
302
    }
303
    
304
    /**
305
     * Stop inserting in UndoHistory
306
     */
307
    public void pauseRecording() {
308
        this.recording=false;
309
    }
310
}
(-)src/core/org/apache/jmeter/gui/tree/JMeterTreeModel.java (-2 / +64 lines)
Lines 24-29 Link Here
24
import java.util.List;
24
import java.util.List;
25
25
26
import javax.swing.tree.DefaultTreeModel;
26
import javax.swing.tree.DefaultTreeModel;
27
import javax.swing.tree.TreePath;
27
28
28
import org.apache.jmeter.config.gui.AbstractConfigGui;
29
import org.apache.jmeter.config.gui.AbstractConfigGui;
29
import org.apache.jmeter.control.gui.TestPlanGui;
30
import org.apache.jmeter.control.gui.TestPlanGui;
Lines 41-50 Link Here
41
public class JMeterTreeModel extends DefaultTreeModel {
42
public class JMeterTreeModel extends DefaultTreeModel {
42
43
43
    private static final long serialVersionUID = 240L;
44
    private static final long serialVersionUID = 240L;
45
    private UndoHistory undoHistory = new UndoHistory();
44
46
45
    public JMeterTreeModel(TestElement tp, TestElement wb) {
47
    public JMeterTreeModel(TestElement tp, TestElement wb) {
46
        super(new JMeterTreeNode(wb, null));
48
        super(new JMeterTreeNode(wb, null));
47
        initTree(tp,wb);
49
        addTreeModelListener(undoHistory);
50
        initTree(tp, wb);
48
    }
51
    }
49
52
50
    public JMeterTreeModel() {
53
    public JMeterTreeModel() {
Lines 213-218 Link Here
213
     * @param testPlan the node to use as the testplan top node
216
     * @param testPlan the node to use as the testplan top node
214
     */
217
     */
215
    public void clearTestPlan(TestElement testPlan) {
218
    public void clearTestPlan(TestElement testPlan) {
219
        pauseUndoHistoryRecording();
216
        // Remove the workbench and testplan nodes
220
        // Remove the workbench and testplan nodes
217
        int children = getChildCount(getRoot());
221
        int children = getChildCount(getRoot());
218
        while (children > 0) {
222
        while (children > 0) {
Lines 220-225 Link Here
220
            super.removeNodeFromParent(child);
224
            super.removeNodeFromParent(child);
221
            children = getChildCount(getRoot());
225
            children = getChildCount(getRoot());
222
        }
226
        }
227
        resumeUndoHistoryRecording();
223
        // Init the tree
228
        // Init the tree
224
        initTree(testPlan,new WorkBenchGui().createTestElement()); // Assumes this is only called from GUI mode
229
        initTree(testPlan,new WorkBenchGui().createTestElement()); // Assumes this is only called from GUI mode
225
    }
230
    }
Lines 231-236 Link Here
231
     * @param wb the element to use as workbench
236
     * @param wb the element to use as workbench
232
     */
237
     */
233
    private void initTree(TestElement tp, TestElement wb) {
238
    private void initTree(TestElement tp, TestElement wb) {
239
        pauseUndoHistoryRecording();
234
        // Insert the test plan node
240
        // Insert the test plan node
235
        insertNodeInto(new JMeterTreeNode(tp, this), (JMeterTreeNode) getRoot(), 0);
241
        insertNodeInto(new JMeterTreeNode(tp, this), (JMeterTreeNode) getRoot(), 0);
236
        // Insert the workbench node
242
        // Insert the workbench node
Lines 239-243 Link Here
239
        // This should not be necessary, but without it, nodes are not shown when the user
245
        // This should not be necessary, but without it, nodes are not shown when the user
240
        // uses the Close menu item
246
        // uses the Close menu item
241
        nodeStructureChanged((JMeterTreeNode)getRoot());
247
        nodeStructureChanged((JMeterTreeNode)getRoot());
248
        resumeUndoHistoryRecording();
249
        undoHistory.clear();
250
        saveUndoPoint(new TreePath(((JMeterTreeNode)getRoot()).getPath()), "Initial Tree");
251
    }
252
253
    /**
254
     * Navigate up and down in history
255
     * @param offset 
256
     * @return TreePath
257
     */
258
    public TreePath goInHistory(int offset) {
259
        return undoHistory.getRelativeState(offset, this);
260
    }
261
262
    /**
263
     * Save in undo history
264
     * @param path TreePath
265
     * @param comment
266
     */
267
    public void saveUndoPoint(TreePath path, String comment) {
268
        undoHistory.add(this, path, comment);
269
    }
270
271
    /**
272
     * Clear undo history
273
     */
274
    public void clearUndo() {
275
        undoHistory.clear();
276
    }
277
278
    /**
279
     * @return true if history contains redo item
280
     */
281
    public boolean canRedo() {
282
        return undoHistory.canRedo();
242
    }
283
    }
243
}
284
285
    /**
286
     * @return true if history contains undo item
287
     */
288
    public boolean canUndo() {
289
        return undoHistory.canUndo();
290
    }
291
    
292
    /**
293
     * 
294
     */
295
    public void pauseUndoHistoryRecording() {
296
        undoHistory.pauseRecording();
297
    }
298
    
299
    /**
300
     * 
301
     */
302
    public void resumeUndoHistoryRecording() {
303
        undoHistory.resumeRecording();
304
    }
305
}
(-)src/core/org/apache/jmeter/gui/GuiPackage.java (-1 / +40 lines)
Lines 33-38 Link Here
33
import javax.swing.JPopupMenu;
33
import javax.swing.JPopupMenu;
34
import javax.swing.JToolBar;
34
import javax.swing.JToolBar;
35
import javax.swing.SwingUtilities;
35
import javax.swing.SwingUtilities;
36
import javax.swing.tree.TreePath;
36
37
37
import org.apache.jmeter.engine.util.ValueReplacer;
38
import org.apache.jmeter.engine.util.ValueReplacer;
38
import org.apache.jmeter.exceptions.IllegalUserActionException;
39
import org.apache.jmeter.exceptions.IllegalUserActionException;
Lines 44-49 Link Here
44
import org.apache.jmeter.testbeans.gui.TestBeanGUI;
45
import org.apache.jmeter.testbeans.gui.TestBeanGUI;
45
import org.apache.jmeter.testelement.TestElement;
46
import org.apache.jmeter.testelement.TestElement;
46
import org.apache.jmeter.testelement.TestPlan;
47
import org.apache.jmeter.testelement.TestPlan;
48
import org.apache.jmeter.testelement.property.JMeterProperty;
49
import org.apache.jmeter.testelement.property.PropertyIterator;
50
import org.apache.jmeter.testelement.property.TestElementProperty;
47
import org.apache.jmeter.util.JMeterUtils;
51
import org.apache.jmeter.util.JMeterUtils;
48
import org.apache.jmeter.util.LocaleChangeEvent;
52
import org.apache.jmeter.util.LocaleChangeEvent;
49
import org.apache.jmeter.util.LocaleChangeListener;
53
import org.apache.jmeter.util.LocaleChangeListener;
Lines 412-418 Link Here
412
                log.debug("Updating current node " + currentNode.getName());
416
                log.debug("Updating current node " + currentNode.getName());
413
                JMeterGUIComponent comp = getGui(currentNode.getTestElement());
417
                JMeterGUIComponent comp = getGui(currentNode.getTestElement());
414
                TestElement el = currentNode.getTestElement();
418
                TestElement el = currentNode.getTestElement();
419
                int before=getTestElementCheckSum(el);
415
                comp.modifyTestElement(el);
420
                comp.modifyTestElement(el);
421
                int after=getTestElementCheckSum(el);
422
                if (before!=after) {
423
                    treeModel.saveUndoPoint(new TreePath(currentNode.getPath()), "Properties Changed");
424
                }
416
                currentNode.nameChanged(); // Bug 50221 - ensure label is updated
425
                currentNode.nameChanged(); // Bug 50221 - ensure label is updated
417
            }
426
            }
418
            // The current node is now updated
427
            // The current node is now updated
Lines 422-427 Link Here
422
            log.error("Problem retrieving gui", e);
431
            log.error("Problem retrieving gui", e);
423
        }
432
        }
424
    }
433
    }
434
    
435
    
436
    /**
437
     * Compute checksum of TestElement to detect changes
438
     *  the method calculates properties checksum to detect testelement
439
     *  modifications
440
     * TODO would be better to override hashCode for TestElement, but I decided to touch it
441
     * @param el {@link TestElement}
442
     * @return int checksum
443
     */
444
    private int getTestElementCheckSum(TestElement el) {
445
        int ret = el.getClass().hashCode();
446
        PropertyIterator it = el.propertyIterator();
447
        while (it.hasNext()) {
448
            JMeterProperty obj = it.next();
449
            if (obj instanceof TestElementProperty) {
450
                ret ^= getTestElementCheckSum(((TestElementProperty) obj)
451
                        .getElement());
452
            } else {
453
                ret ^= obj.getName().hashCode();
454
                ret ^= obj.getStringValue().hashCode();
455
            }
456
        }
457
        return ret;
458
    }
425
459
426
    public JMeterTreeNode getCurrentNode() {
460
    public JMeterTreeNode getCurrentNode() {
427
        return treeListener.getCurrentNode();
461
        return treeListener.getCurrentNode();
Lines 468-474 Link Here
468
     *             if a subtree cannot be added to the currently selected node
502
     *             if a subtree cannot be added to the currently selected node
469
     */
503
     */
470
    public HashTree addSubTree(HashTree subTree) throws IllegalUserActionException {
504
    public HashTree addSubTree(HashTree subTree) throws IllegalUserActionException {
471
        return treeModel.addSubTree(subTree, treeListener.getCurrentNode());
505
        treeModel.pauseUndoHistoryRecording();
506
        try {
507
            return treeModel.addSubTree(subTree, treeListener.getCurrentNode());
508
        } finally {
509
            treeModel.resumeUndoHistoryRecording();
510
        }
472
    }
511
    }
473
512
474
    /**
513
    /**
(-)src/core/org/apache/jmeter/gui/action/ActionNames.java (+2 lines)
Lines 91-96 Link Here
91
    public static final String WHAT_CLASS       = "what_class"; // $NON-NLS-1$
91
    public static final String WHAT_CLASS       = "what_class"; // $NON-NLS-1$
92
    public static final String SEARCH_TREE      = "search_tree"; // $NON-NLS-1$
92
    public static final String SEARCH_TREE      = "search_tree"; // $NON-NLS-1$
93
    public static final String SEARCH_RESET      = "search_reset"; // $NON-NLS-1$
93
    public static final String SEARCH_RESET      = "search_reset"; // $NON-NLS-1$
94
    public static final String UNDO             = "undo"; // $NON-NLS-1$
95
    public static final String REDO             = "redo"; // $NON-NLS-1$
94
96
95
    // Prevent instantiation
97
    // Prevent instantiation
96
    private ActionNames(){
98
    private ActionNames(){
(-)src/core/org/apache/jmeter/gui/action/KeyStrokes.java (+3 lines)
Lines 59-64 Link Here
59
    public static final KeyStroke PASTE             = KeyStroke.getKeyStroke(KeyEvent.VK_V, CONTROL_MASK);
59
    public static final KeyStroke PASTE             = KeyStroke.getKeyStroke(KeyEvent.VK_V, CONTROL_MASK);
60
    public static final KeyStroke WHAT_CLASS        = KeyStroke.getKeyStroke(KeyEvent.VK_W, CONTROL_MASK);
60
    public static final KeyStroke WHAT_CLASS        = KeyStroke.getKeyStroke(KeyEvent.VK_W, CONTROL_MASK);
61
    public static final KeyStroke CUT               = KeyStroke.getKeyStroke(KeyEvent.VK_X, CONTROL_MASK);
61
    public static final KeyStroke CUT               = KeyStroke.getKeyStroke(KeyEvent.VK_X, CONTROL_MASK);
62
    public static final KeyStroke UNDO               = KeyStroke.getKeyStroke(KeyEvent.VK_Z, CONTROL_MASK);
63
    // does Ctrl+Shift+Z right standard for redo?
64
    public static final KeyStroke REDO               = KeyStroke.getKeyStroke(KeyEvent.VK_Z, CONTROL_MASK | KeyEvent.SHIFT_DOWN_MASK);
62
    public static final KeyStroke REMOTE_STOP_ALL   = KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.ALT_DOWN_MASK);
65
    public static final KeyStroke REMOTE_STOP_ALL   = KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.ALT_DOWN_MASK);
63
    public static final KeyStroke REMOTE_SHUT_ALL   = KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.ALT_DOWN_MASK);
66
    public static final KeyStroke REMOTE_SHUT_ALL   = KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.ALT_DOWN_MASK);
64
67
(-)src/core/org/apache/jmeter/gui/action/UndoCommand.java (+77 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.gui.action;
20
21
import java.awt.event.ActionEvent;
22
import java.util.HashSet;
23
import java.util.Set;
24
25
import javax.swing.tree.TreePath;
26
27
import org.apache.jmeter.exceptions.IllegalUserActionException;
28
import org.apache.jmeter.gui.GuiPackage;
29
import org.apache.jorphan.collections.HashTree;
30
31
/**
32
 *
33
 */
34
public class UndoCommand implements Command {
35
36
    private static final Set<String> commands = new HashSet<String>();
37
38
    static {
39
        commands.add(ActionNames.UNDO);
40
        commands.add(ActionNames.REDO);
41
    }
42
43
    public void doAction(ActionEvent e) throws IllegalUserActionException {
44
        GuiPackage guiPackage = GuiPackage.getInstance();
45
        final String command = e.getActionCommand();
46
47
        TreePath path;
48
        if (command.equals(ActionNames.UNDO)) {
49
            path = guiPackage.getTreeModel().goInHistory(-1);
50
        } else if (command.equals(ActionNames.REDO)) {
51
            path = guiPackage.getTreeModel().goInHistory(1);
52
        } else {
53
            throw new IllegalArgumentException("Wrong action called: " + command);
54
        }
55
56
        // we need to go to recorded tree path
57
        // fixme: we have a problem with unselected tree item then
58
        // also the GUI reflects old GUI properties
59
        //final JTree tree = GuiPackage.getInstance().getMainFrame().getTree();
60
        //tree.setSelectionPath(path);
61
        guiPackage.updateCurrentGui();
62
        guiPackage.getMainFrame().repaint();
63
    }
64
65
    /**
66
     * @return Set<String>
67
     */
68
    public Set<String> getActionNames() {
69
        return commands;
70
    }
71
72
    // wrapper to use package-visible method
73
    public static void convertSubTree(HashTree tree) {
74
        Save executor = new Save();
75
        executor.convertSubTree(tree);
76
    }
77
}
(-)test/src/org/apache/jmeter/gui/tree/UndoHistoryTest.java (+107 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.gui.tree;
20
21
import java.io.File;
22
import java.io.IOException;
23
import java.util.Locale;
24
import javax.swing.tree.TreePath;
25
import org.apache.jmeter.util.JMeterUtils;
26
27
/**
28
 *
29
 */
30
public class UndoHistoryTest extends junit.framework.TestCase {
31
32
    public UndoHistoryTest() {
33
        File propsFile = null;
34
        try {
35
            propsFile = File.createTempFile("jmeter-plugins", "testProps");
36
            propsFile.deleteOnExit();
37
        } catch (IOException ex) {
38
            ex.printStackTrace(System.err);
39
        }
40
41
        //propsFile=new File("/home/undera/NetBeansProjects/jmeter/trunk/bin/jmeter.properties");
42
43
        JMeterUtils.loadJMeterProperties(propsFile.getAbsolutePath());
44
        JMeterUtils.setLocale(new Locale("ignoreResources"));
45
    }
46
47
    /*
48
     * public void testGetTestElementCheckSum() {
49
     * System.out.println("getTestElementCheckSum"); TestElement el = new
50
     * TestAction(); int result = UndoHistory.getTestElementCheckSum(el);
51
     * assertTrue(result!=0); el.setProperty(new BooleanProperty());
52
     * assertTrue(result != UndoHistory.getTestElementCheckSum(el)); }
53
     *
54
     * public void testGetTestElementCheckSum_stable() {
55
     * System.out.println("getTestElementCheckSum stable"); TestElement el = new
56
     * ThreadGroup(); AbstractJMeterGuiComponent gui = new ThreadGroupGui();
57
     *
58
     * gui.modifyTestElement(el); int result1 =
59
     * UndoHistory.getTestElementCheckSum(el); gui.modifyTestElement(el); int
60
     * result2 = UndoHistory.getTestElementCheckSum(el); assertEquals(result1,
61
     * result2); el.setProperty(new BooleanProperty()); assertTrue(result1 !=
62
     * UndoHistory.getTestElementCheckSum(el)); }
63
     */
64
    public void testClear() {
65
        System.out.println("clear");
66
        UndoHistory instance = new UndoHistory();
67
        instance.clear();
68
    }
69
70
    public void testAdd() throws Exception {
71
        System.out.println("add");
72
        JMeterTreeModel treeModel = new JMeterTreeModel();
73
        UndoHistory instance = new UndoHistory();
74
        instance.add(treeModel, new TreePath(this), "");
75
    }
76
77
    public void testGetRelativeState() throws Exception {
78
        System.out.println("getRelativeState");
79
        JMeterTreeModel treeModelRecv = new JMeterTreeModel();
80
        UndoHistory instance = new UndoHistory();
81
82
        // safety check
83
        instance.getRelativeState(-1, treeModelRecv);
84
        instance.getRelativeState(1, treeModelRecv);
85
86
87
        JMeterTreeModel treeModel1 = new JMeterTreeModel();
88
        JMeterTreeModel treeModel2 = new JMeterTreeModel();
89
        JMeterTreeModel treeModel3 = new JMeterTreeModel();
90
        instance.add(treeModel1, new TreePath(this), "");
91
        instance.add(treeModel2, new TreePath(this), "");
92
        instance.add(treeModel3, new TreePath(this), "");
93
94
        // regular work check
95
        instance.getRelativeState(-1, treeModelRecv);
96
        instance.getRelativeState(-1, treeModelRecv);
97
        instance.getRelativeState(-1, treeModelRecv); // undo ignored
98
        instance.getRelativeState(1, treeModelRecv);
99
        instance.getRelativeState(1, treeModelRecv);
100
        instance.getRelativeState(1, treeModelRecv); // redo ignored
101
102
        // overwrite check
103
        instance.getRelativeState(-1, treeModelRecv);
104
        instance.getRelativeState(-1, treeModelRecv);
105
        instance.add(treeModel3, new TreePath(this), "");
106
    }
107
}

Return to bug 42248