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

(-)src/core/org/apache/jmeter/gui/GuiPackage.java (-9 / +78 lines)
Lines 44-49 Link Here
44
import org.apache.jmeter.testbeans.gui.TestBeanGUI;
44
import org.apache.jmeter.testbeans.gui.TestBeanGUI;
45
import org.apache.jmeter.testelement.TestElement;
45
import org.apache.jmeter.testelement.TestElement;
46
import org.apache.jmeter.testelement.TestPlan;
46
import org.apache.jmeter.testelement.TestPlan;
47
import org.apache.jmeter.testelement.property.JMeterProperty;
48
import org.apache.jmeter.testelement.property.PropertyIterator;
49
import org.apache.jmeter.testelement.property.TestElementProperty;
47
import org.apache.jmeter.util.JMeterUtils;
50
import org.apache.jmeter.util.JMeterUtils;
48
import org.apache.jmeter.util.LocaleChangeEvent;
51
import org.apache.jmeter.util.LocaleChangeEvent;
49
import org.apache.jmeter.util.LocaleChangeListener;
52
import org.apache.jmeter.util.LocaleChangeListener;
Lines 104-110 Link Here
104
107
105
    /** The main JMeter frame. */
108
    /** The main JMeter frame. */
106
    private MainFrame mainFrame;
109
    private MainFrame mainFrame;
107
    
110
108
    /** The main JMeter toolbar. */
111
    /** The main JMeter toolbar. */
109
    private JToolBar toolbar;
112
    private JToolBar toolbar;
110
113
Lines 121-133 Link Here
121
     */
124
     */
122
    private LoggerPanel loggerPanel;
125
    private LoggerPanel loggerPanel;
123
126
124
    
125
    /**
127
    /**
128
     * History for tree states
129
     */
130
    private UndoHistory undoHistory = new UndoHistory();
131
132
    /**
126
     * Private constructor to permit instantiation only from within this class.
133
     * Private constructor to permit instantiation only from within this class.
127
     * Use {@link #getInstance()} to retrieve a singleton instance.
134
     * Use {@link #getInstance()} to retrieve a singleton instance.
128
     */
135
     */
129
    private GuiPackage(JMeterTreeModel treeModel, JMeterTreeListener treeListener) {
136
    private GuiPackage(JMeterTreeModel treeModel, JMeterTreeListener treeListener) {
130
        this.treeModel = treeModel;
137
        this.treeModel = treeModel;
138
        this.treeModel.addTreeModelListener(undoHistory);
131
        this.treeListener = treeListener;
139
        this.treeListener = treeListener;
132
        JMeterUtils.addLocaleChangeListener(this);
140
        JMeterUtils.addLocaleChangeListener(this);
133
    }
141
    }
Lines 155-160 Link Here
155
    public static GuiPackage getInstance(JMeterTreeListener listener, JMeterTreeModel treeModel) {
163
    public static GuiPackage getInstance(JMeterTreeListener listener, JMeterTreeModel treeModel) {
156
        if (guiPack == null) {
164
        if (guiPack == null) {
157
            guiPack = new GuiPackage(treeModel, listener);
165
            guiPack = new GuiPackage(treeModel, listener);
166
            guiPack.undoHistory.add(treeModel, "Created");
158
        }
167
        }
159
        return guiPack;
168
        return guiPack;
160
    }
169
    }
Lines 408-415 Link Here
408
                log.debug("Updating current node " + currentNode.getName());
417
                log.debug("Updating current node " + currentNode.getName());
409
                JMeterGUIComponent comp = getGui(currentNode.getTestElement());
418
                JMeterGUIComponent comp = getGui(currentNode.getTestElement());
410
                TestElement el = currentNode.getTestElement();
419
                TestElement el = currentNode.getTestElement();
420
                int before = getTestElementCheckSum(el);
411
                comp.modifyTestElement(el);
421
                comp.modifyTestElement(el);
412
                currentNode.nameChanged(); // Bug 50221 - ensure label is updated
422
                int after = getTestElementCheckSum(el);
423
                if (before != after) {
424
                    currentNode.nameChanged(); // Bug 50221 - ensure label is updated
425
                }
413
            }
426
            }
414
            // The current node is now updated
427
            // The current node is now updated
415
            currentNodeUpdated = true;
428
            currentNodeUpdated = true;
Lines 464-470 Link Here
464
     *             if a subtree cannot be added to the currently selected node
477
     *             if a subtree cannot be added to the currently selected node
465
     */
478
     */
466
    public HashTree addSubTree(HashTree subTree) throws IllegalUserActionException {
479
    public HashTree addSubTree(HashTree subTree) throws IllegalUserActionException {
467
        return treeModel.addSubTree(subTree, treeListener.getCurrentNode());
480
        HashTree hashTree = treeModel.addSubTree(subTree, treeListener.getCurrentNode());
481
        undoHistory.clear();
482
        undoHistory.add(this.treeModel, "Loaded tree");
483
        return hashTree;
468
    }
484
    }
469
485
470
    /**
486
    /**
Lines 527-533 Link Here
527
    public JMeterTreeListener getTreeListener() {
543
    public JMeterTreeListener getTreeListener() {
528
        return treeListener;
544
        return treeListener;
529
    }
545
    }
530
    
546
531
    /**
547
    /**
532
     * Set the main JMeter toolbar.
548
     * Set the main JMeter toolbar.
533
     *
549
     *
Lines 546-552 Link Here
546
    public JToolBar getMainToolbar() {
562
    public JToolBar getMainToolbar() {
547
        return toolbar;
563
        return toolbar;
548
    }
564
    }
549
    
565
550
    /**
566
    /**
551
     * Set the menu item toolbar.
567
     * Set the menu item toolbar.
552
     *
568
     *
Lines 670-675 Link Here
670
        getTreeModel().clearTestPlan();
686
        getTreeModel().clearTestPlan();
671
        nodesToGui.clear();
687
        nodesToGui.clear();
672
        setTestPlanFile(null);
688
        setTestPlanFile(null);
689
        undoHistory.clear();
690
        undoHistory.add(this.treeModel, "Initial Tree");
673
    }
691
    }
674
692
675
    /**
693
    /**
Lines 680-685 Link Here
680
    public void clearTestPlan(TestElement element) {
698
    public void clearTestPlan(TestElement element) {
681
        getTreeModel().clearTestPlan(element);
699
        getTreeModel().clearTestPlan(element);
682
        removeNode(element);
700
        removeNode(element);
701
        undoHistory.clear();
702
        undoHistory.add(this.treeModel, "Initial Tree");
683
    }
703
    }
684
704
685
    public static void showErrorMessage(final String message, final String title){
705
    public static void showErrorMessage(final String message, final String title){
Lines 720-726 Link Here
720
            }
740
            }
721
        }
741
        }
722
    }
742
    }
723
    
743
724
    /**
744
    /**
725
     * Register process to stop on reload
745
     * Register process to stop on reload
726
     * @param stoppable
746
     * @param stoppable
Lines 730-736 Link Here
730
    }
750
    }
731
751
732
    /**
752
    /**
733
     * 
753
     *
734
     * @return List<IStoppable> Copy of IStoppable
754
     * @return List<IStoppable> Copy of IStoppable
735
     */
755
     */
736
    public List<Stoppable> getStoppables() {
756
    public List<Stoppable> getStoppables() {
Lines 746-752 Link Here
746
    public void setMenuItemLoggerPanel(JCheckBoxMenuItem menuItemLoggerPanel) {
766
    public void setMenuItemLoggerPanel(JCheckBoxMenuItem menuItemLoggerPanel) {
747
        this.menuItemLoggerPanel = menuItemLoggerPanel;
767
        this.menuItemLoggerPanel = menuItemLoggerPanel;
748
    }
768
    }
749
    
769
750
    /**
770
    /**
751
     * Get the menu item LoggerPanel.
771
     * Get the menu item LoggerPanel.
752
     *
772
     *
Lines 769-772 Link Here
769
    public LoggerPanel getLoggerPanel() {
789
    public LoggerPanel getLoggerPanel() {
770
        return loggerPanel;
790
        return loggerPanel;
771
    }
791
    }
792
793
    /**
794
     * Navigate back and forward through undo history
795
     *
796
     * @param offset int
797
     */
798
    public void goInHistory(int offset) {
799
        undoHistory.getRelativeState(offset, this.treeModel);
800
    }
801
802
    /**
803
     * @return true if history contains redo item
804
     */
805
    public boolean canRedo() {
806
        return undoHistory.canRedo();
807
    }
808
809
    /**
810
     * @return true if history contains undo item
811
     */
812
    public boolean canUndo() {
813
        return undoHistory.canUndo();
814
    }
815
816
    /**
817
     * Compute checksum of TestElement to detect changes
818
     * the method calculates properties checksum to detect testelement
819
     * modifications
820
     * TODO would be better to override hashCode for TestElement, but I decided to touch it
821
     *
822
     * @param el {@link TestElement}
823
     * @return int checksum
824
     */
825
    private int getTestElementCheckSum(TestElement el) {
826
        int ret = el.getClass().hashCode();
827
        PropertyIterator it = el.propertyIterator();
828
        while (it.hasNext()) {
829
            JMeterProperty obj = it.next();
830
            if (obj instanceof TestElementProperty) {
831
                ret ^= getTestElementCheckSum(((TestElementProperty) obj)
832
                        .getElement());
833
            } else {
834
                ret ^= obj.getName().hashCode();
835
                ret ^= obj.getStringValue().hashCode();
836
            }
837
        }
838
        return ret;
839
    }
840
772
}
841
}
(-)src/core/org/apache/jmeter/gui/UndoHistory.java (+314 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;
20
21
import java.io.Serializable;
22
import java.util.ArrayList;
23
import java.util.List;
24
25
import javax.swing.JTree;
26
import javax.swing.event.TreeModelEvent;
27
import javax.swing.event.TreeModelListener;
28
29
import org.apache.jmeter.gui.action.UndoCommand;
30
import org.apache.jmeter.gui.tree.JMeterTreeModel;
31
import org.apache.jmeter.gui.tree.JMeterTreeNode;
32
import org.apache.jmeter.util.JMeterUtils;
33
import org.apache.jorphan.collections.HashTree;
34
import org.apache.jorphan.logging.LoggingManager;
35
import org.apache.log.Logger;
36
37
/**
38
 * This class serves storing Test Tree state and navigating through it
39
 * to give the undo/redo ability for test plan changes
40
 */
41
public class UndoHistory implements TreeModelListener, Serializable {
42
    /**
43
     * Avoid storing too many elements
44
     *
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 Logger log = LoggingManager.getLoggerForClass();
68
69
    /**
70
     * temporary storage for GUI tree expansion state
71
     */
72
    private ArrayList<Integer> savedExpanded = new ArrayList<Integer>();
73
74
    /**
75
     * temporary storage for GUI tree selected row
76
     */
77
    private int savedSelected = 0;
78
79
    private static final int INITIAL_POS = -1;
80
    private int position = INITIAL_POS;
81
82
    private static final int HISTORY_SIZE = JMeterUtils.getPropDefault("undo.size", 25);
83
84
    private List<UndoHistoryItem> history = new LimitedArrayList<UndoHistoryItem>(HISTORY_SIZE);
85
86
    /**
87
     * flag to prevent recursive actions
88
     */
89
    private boolean working = false;
90
91
    public UndoHistory() {
92
    }
93
94
    /**
95
     * Clears the undo history
96
     */
97
    public void clear() {
98
        if (working) {
99
            return;
100
        }
101
        log.debug("Clearing undo history");
102
        history.clear();
103
        position = INITIAL_POS;
104
    }
105
106
    /**
107
     * Add tree model copy to the history
108
     * <p/>
109
     * This method relies on the rule that the record in history made AFTER
110
     * change has been made to test plan
111
     *
112
     * @param treeModel JMeterTreeModel
113
     * @param comment   String
114
     */
115
    public void add(JMeterTreeModel treeModel, String comment) {
116
        // don't add element if we are in the middle of undo/redo or a big loading
117
        if (working) {
118
            log.debug("Not adding history because of noop");
119
            return;
120
        }
121
122
        JMeterTreeNode root = (JMeterTreeNode) treeModel.getRoot();
123
        if (root.getChildCount() < 1) {
124
            log.debug("Not adding history because of no children");
125
            return;
126
        }
127
128
        String name = root.getName();
129
130
        log.debug("Adding history element " + name + ": " + comment);
131
132
        working = true;
133
        // get test plan tree
134
        HashTree tree = treeModel.getCurrentSubTree((JMeterTreeNode) treeModel.getRoot());
135
        // first clone to not convert original tree
136
        tree = (HashTree) tree.getTree(tree.getArray()[0]).clone();
137
138
        position++;
139
        while (history.size() > position) {
140
            log.debug("Removing further record, position: " + position + ", size: " + history.size());
141
            history.remove(history.size() - 1);
142
        }
143
144
        // cloning is required because we need to immute stored data
145
        HashTree copy = UndoCommand.convertAndCloneSubTree(tree);
146
147
        history.add(new UndoHistoryItem(copy, comment));
148
149
        log.debug("Added history element, position: " + position + ", size: " + history.size());
150
        working = false;
151
    }
152
153
    /**
154
     * Goes through undo history, changing GUI
155
     *
156
     * @param offset        the direction to go to, usually -1 for undo or 1 for redo
157
     * @param acceptorModel TreeModel to accept the changes
158
     */
159
    public void getRelativeState(int offset, JMeterTreeModel acceptorModel) {
160
        log.debug("Moving history from position " + position + " with step " + offset + ", size is " + history.size());
161
        if (offset < 0 && !canUndo()) {
162
            log.warn("Can't undo, we're already on the last record");
163
            return;
164
        }
165
166
        if (offset > 0 && !canRedo()) {
167
            log.warn("Can't redo, we're already on the first record");
168
            return;
169
        }
170
171
        if (history.isEmpty()) {
172
            log.warn("Can't proceed, the history is empty");
173
            return;
174
        }
175
176
        position += offset;
177
178
        final GuiPackage guiInstance = GuiPackage.getInstance();
179
180
        // save tree expansion and selection state before changing the tree
181
        saveTreeState(guiInstance);
182
183
        // load the tree
184
        loadHistoricalTree(acceptorModel, guiInstance);
185
186
        // load tree UI state
187
        restoreTreeState(guiInstance);
188
189
        log.debug("Current position " + position + ", size is " + history.size());
190
191
        // refresh the all ui
192
        guiInstance.updateCurrentGui();
193
        guiInstance.getMainFrame().repaint();
194
    }
195
196
    /**
197
     * Load the undo item into acceptorModel tree
198
     *
199
     * @param acceptorModel tree to accept the data
200
     * @param guiInstance
201
     */
202
    private void loadHistoricalTree(JMeterTreeModel acceptorModel, GuiPackage guiInstance) {
203
        HashTree newModel = history.get(position).getTree();
204
        acceptorModel.removeTreeModelListener(this);
205
        working = true;
206
        try {
207
            guiInstance.getTreeModel().clearTestPlan();
208
            guiInstance.addSubTree(newModel);
209
        } catch (Exception ex) {
210
            log.error("Failed to load from history", ex);
211
        }
212
        acceptorModel.addTreeModelListener(this);
213
        working = false;
214
    }
215
216
    /**
217
     * @return true if remaing items
218
     */
219
    public boolean canRedo() {
220
        return position < history.size() - 1;
221
    }
222
223
    /**
224
     * @return true if not at first element
225
     */
226
    public boolean canUndo() {
227
        return position > INITIAL_POS + 1;
228
    }
229
230
    /**
231
     * Record the changes in the node as the undo step
232
     *
233
     * @param tme
234
     */
235
    public void treeNodesChanged(TreeModelEvent tme) {
236
        String name = ((JMeterTreeNode) tme.getTreePath().getLastPathComponent()).getName();
237
        log.debug("Nodes changed " + name);
238
        final JMeterTreeModel sender = (JMeterTreeModel) tme.getSource();
239
        add(sender, "Node changed " + name);
240
    }
241
242
    /**
243
     * Record adding nodes as the undo step
244
     *
245
     * @param tme
246
     */
247
    public void treeNodesInserted(TreeModelEvent tme) {
248
        String name = ((JMeterTreeNode) tme.getTreePath().getLastPathComponent()).getName();
249
        log.debug("Nodes inserted " + name);
250
        final JMeterTreeModel sender = (JMeterTreeModel) tme.getSource();
251
        add(sender, "Add " + name);
252
    }
253
254
    /**
255
     * Record deleting nodes as the undo step
256
     *
257
     * @param tme
258
     */
259
    public void treeNodesRemoved(TreeModelEvent tme) {
260
        String name = ((JMeterTreeNode) tme.getTreePath().getLastPathComponent()).getName();
261
        log.debug("Nodes removed: " + name);
262
        add((JMeterTreeModel) tme.getSource(), "Remove " + name);
263
    }
264
265
    /**
266
     * Record some other change
267
     *
268
     * @param tme
269
     */
270
    public void treeStructureChanged(TreeModelEvent tme) {
271
        log.debug("Nodes struct changed");
272
        add((JMeterTreeModel) tme.getSource(), "Complex Change");
273
    }
274
275
    /**
276
     * Save tree expanded and selected state
277
     *
278
     * @param guiPackage
279
     */
280
    private void saveTreeState(GuiPackage guiPackage) {
281
        savedExpanded.clear();
282
283
        MainFrame mainframe = guiPackage.getMainFrame();
284
        if (mainframe != null) {
285
            final JTree tree = mainframe.getTree();
286
            savedSelected = tree.getMinSelectionRow();
287
288
            for (int rowN = 0; rowN < tree.getRowCount(); rowN++) {
289
                if (tree.isExpanded(rowN)) {
290
                    savedExpanded.add(rowN);
291
                }
292
            }
293
        }
294
    }
295
296
    /**
297
     * Restore tree expanded and selected state
298
     *
299
     * @param guiPackage
300
     */
301
    private void restoreTreeState(GuiPackage guiInstance) {
302
        final JTree tree = guiInstance.getMainFrame().getTree();
303
304
        if (savedExpanded.size() > 0) {
305
            for (int rowN : savedExpanded) {
306
                tree.expandRow(rowN);
307
            }
308
        } else {
309
            tree.expandRow(0);
310
        }
311
        tree.setSelectionRow(savedSelected);
312
    }
313
314
}
(-)src/core/org/apache/jmeter/gui/UndoHistoryItem.java (+38 lines)
Line 0 Link Here
1
package org.apache.jmeter.gui;
2
3
import org.apache.jorphan.collections.HashTree;
4
5
import java.io.Serializable;
6
7
/**
8
 * Undo history item
9
 */
10
public class UndoHistoryItem implements Serializable {
11
12
    private final HashTree tree;
13
    // TODO: find a way to show this comment in menu item and toolbar tooltip
14
    private final String comment;
15
16
    /**
17
     * @param copy     HashTree
18
     * @param acomment String
19
     */
20
    public UndoHistoryItem(HashTree copy, String acomment) {
21
        tree = copy;
22
        comment = acomment;
23
    }
24
25
    /**
26
     * @return {@link org.apache.jorphan.collections.HashTree}
27
     */
28
    public HashTree getTree() {
29
        return tree;
30
    }
31
32
    /**
33
     * @return String comment
34
     */
35
    public String getComment() {
36
        return comment;
37
    }
38
}
(-)src/core/org/apache/jmeter/gui/action/ActionNames.java (+2 lines)
Lines 95-100 Link Here
95
    public static final String MOVE_DOWN        = "move_down"; // $NON-NLS-1$
95
    public static final String MOVE_DOWN        = "move_down"; // $NON-NLS-1$
96
    public static final String MOVE_LEFT        = "move_left"; // $NON-NLS-1$
96
    public static final String MOVE_LEFT        = "move_left"; // $NON-NLS-1$
97
    public static final String MOVE_RIGHT       = "move_right"; // $NON-NLS-1$
97
    public static final String MOVE_RIGHT       = "move_right"; // $NON-NLS-1$
98
    public static final String UNDO             = "undo"; // $NON-NLS-1$
99
    public static final String REDO             = "redo"; // $NON-NLS-1$
98
100
99
    // Prevent instantiation
101
    // Prevent instantiation
100
    private ActionNames(){
102
    private ActionNames(){
(-)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 org.apache.jmeter.engine.TreeCloner;
26
import org.apache.jmeter.exceptions.IllegalUserActionException;
27
import org.apache.jmeter.gui.GuiPackage;
28
import org.apache.jorphan.collections.HashTree;
29
30
/**
31
 * Menu command to serve Undo/Redo
32
 */
33
public class UndoCommand implements Command {
34
35
    private static final Set<String> commands = new HashSet<String>();
36
37
    static {
38
        commands.add(ActionNames.UNDO);
39
        commands.add(ActionNames.REDO);
40
    }
41
42
    public void doAction(ActionEvent e) throws IllegalUserActionException {
43
        GuiPackage guiPackage = GuiPackage.getInstance();
44
        final String command = e.getActionCommand();
45
46
        if (command.equals(ActionNames.UNDO)) {
47
            guiPackage.goInHistory(-1);
48
        } else if (command.equals(ActionNames.REDO)) {
49
            guiPackage.goInHistory(1);
50
        } else {
51
            throw new IllegalArgumentException("Wrong action called: " + command);
52
        }
53
    }
54
55
    /**
56
     * @return Set<String>
57
     */
58
    public Set<String> getActionNames() {
59
        return commands;
60
    }
61
62
    /**
63
     * wrapper to use package-visible method
64
     * and clone tree for saving
65
     *
66
     * @param tree to be converted and cloned
67
     */
68
    public static HashTree convertAndCloneSubTree(HashTree tree) {
69
        Save executor = new Save();
70
        executor.convertSubTree(tree);
71
72
        // convert before clone
73
        TreeCloner cloner = new TreeCloner(false);
74
        tree.traverse(cloner);
75
        return cloner.getClonedTree();
76
    }
77
}
(-)src/core/org/apache/jmeter/gui/util/MenuFactory.java (+25 lines)
Lines 206-211 Link Here
206
     * @param addSaveTestFragmentMenu Add Save as Test Fragment menu if true 
206
     * @param addSaveTestFragmentMenu Add Save as Test Fragment menu if true 
207
     */
207
     */
208
    public static void addFileMenu(JPopupMenu menu, boolean addSaveTestFragmentMenu) {
208
    public static void addFileMenu(JPopupMenu menu, boolean addSaveTestFragmentMenu) {
209
        // the undo/redo as a standard goes first in Edit menus
210
        // maybe there's better place for them in JMeter?
211
        addUndoItems(menu);
212
209
        addSeparator(menu);
213
        addSeparator(menu);
210
        menu.add(makeMenuItemRes("open", ActionNames.OPEN));// $NON-NLS-1$
214
        menu.add(makeMenuItemRes("open", ActionNames.OPEN));// $NON-NLS-1$
211
        menu.add(makeMenuItemRes("menu_merge", ActionNames.MERGE));// $NON-NLS-1$
215
        menu.add(makeMenuItemRes("menu_merge", ActionNames.MERGE));// $NON-NLS-1$
Lines 247-252 Link Here
247
        menu.add(makeMenuItemRes("help", ActionNames.HELP));// $NON-NLS-1$
251
        menu.add(makeMenuItemRes("help", ActionNames.HELP));// $NON-NLS-1$
248
    }
252
    }
249
253
254
    /**
255
     * Add undo / redo
256
     * @param menu JPopupMenu
257
     */
258
    private static void addUndoItems(JPopupMenu menu) {
259
        addSeparator(menu);
260
261
        JMenuItem undo = makeMenuItemRes("undo", ActionNames.UNDO); //$NON-NLS-1$
262
        //undo.setAccelerator(KeyStrokes.UNDO);
263
        undo.setEnabled(GuiPackage.getInstance().canUndo());
264
        menu.add(undo);
265
266
        JMenuItem redo = makeMenuItemRes("redo", ActionNames.REDO); //$NON-NLS-1$
267
        //redo.setAccelerator(KeyStrokes.REDO);
268
        // TODO: we could even show some hints on action being undone here if this will be required (by passing those hints into history  records)
269
        redo.setEnabled(GuiPackage.getInstance().canRedo());
270
        menu.add(redo);
271
        // TODO: find a way to enable/disable toolbar items depending on action states
272
    }
273
274
250
    public static JMenu makeMenus(String[] categories, String label, String actionCommand) {
275
    public static JMenu makeMenus(String[] categories, String label, String actionCommand) {
251
        JMenu addMenu = new JMenu(label);
276
        JMenu addMenu = new JMenu(label);
252
        for (int i = 0; i < categories.length; i++) {
277
        for (int i = 0; i < categories.length; i++) {
(-)src/core/org/apache/jmeter/images/toolbar/icons-toolbar.properties (-2 / +4 lines)
Lines 14-20 Link Here
14
#   limitations under the License.
14
#   limitations under the License.
15
15
16
# Icons order. Keys separate by comma. Use a pipe | to have a space between two icons.
16
# Icons order. Keys separate by comma. Use a pipe | to have a space between two icons.
17
toolbar=new,templates,open,close,save,save_as_testplan,|,cut,copy,paste,|,expand,collapse,toggle,|,test_start,test_start_notimers,test_stop,test_shutdown,|,test_start_remote_all,test_stop_remote_all,test_shutdown_remote_all,|,test_clear,test_clear_all,|,search,search_reset,|,function_helper,help
17
toolbar=new,templates,open,close,save,save_as_testplan,|,undo,redo,cut,copy,paste,|,expand,collapse,toggle,|,test_start,test_start_notimers,test_stop,test_shutdown,|,test_start_remote_all,test_stop_remote_all,test_shutdown_remote_all,|,test_clear,test_clear_all,|,search,search_reset,|,function_helper,help
18
18
19
# Icon / action definition file.
19
# Icon / action definition file.
20
# Key:      button names
20
# Key:      button names
Lines 43-46 Link Here
43
search=menu_search,SEARCH_TREE,org/apache/jmeter/images/toolbar/search.png
43
search=menu_search,SEARCH_TREE,org/apache/jmeter/images/toolbar/search.png
44
search_reset=menu_search_reset,SEARCH_RESET,org/apache/jmeter/images/toolbar/searchreset.png
44
search_reset=menu_search_reset,SEARCH_RESET,org/apache/jmeter/images/toolbar/searchreset.png
45
function_helper=function_dialog_menu_item,FUNCTIONS,org/apache/jmeter/images/toolbar/function.png
45
function_helper=function_dialog_menu_item,FUNCTIONS,org/apache/jmeter/images/toolbar/function.png
46
help=help,HELP,org/apache/jmeter/images/toolbar/help.png
46
help=help,HELP,org/apache/jmeter/images/toolbar/help.png
47
undo=undo,UNDO,org/apache/jmeter/images/toolbar/undo.png
48
redo=redo,REDO,org/apache/jmeter/images/toolbar/redo.png
(-)src/core/org/apache/jmeter/resources/messages.properties (+2 lines)
Lines 769-774 Link Here
769
read_soap_response=Read SOAP Response
769
read_soap_response=Read SOAP Response
770
realm=Realm
770
realm=Realm
771
record_controller_title=Recording Controller
771
record_controller_title=Recording Controller
772
redo=Redo
772
ref_name_field=Reference Name\:
773
ref_name_field=Reference Name\:
773
regex_extractor_title=Regular Expression Extractor
774
regex_extractor_title=Regular Expression Extractor
774
regex_field=Regular Expression\:
775
regex_field=Regular Expression\:
Lines 1131-1136 Link Here
1131
transaction_controller_parent=Generate parent sample
1132
transaction_controller_parent=Generate parent sample
1132
transaction_controller_title=Transaction Controller
1133
transaction_controller_title=Transaction Controller
1133
unbind=Thread Unbind
1134
unbind=Thread Unbind
1135
undo=Undo
1134
unescape_html_string=String to unescape
1136
unescape_html_string=String to unescape
1135
unescape_string=String containing Java escapes
1137
unescape_string=String containing Java escapes
1136
uniform_timer_delay=Constant Delay Offset (in milliseconds)\:
1138
uniform_timer_delay=Constant Delay Offset (in milliseconds)\:
(-)src/core/org/apache/jmeter/resources/messages_fr.properties (+2 lines)
Lines 762-767 Link Here
762
read_soap_response=Lire la r\u00E9ponse SOAP
762
read_soap_response=Lire la r\u00E9ponse SOAP
763
realm=Univers (realm)
763
realm=Univers (realm)
764
record_controller_title=Contr\u00F4leur Enregistreur
764
record_controller_title=Contr\u00F4leur Enregistreur
765
redo=R\u00E9tablir
765
ref_name_field=Nom de r\u00E9f\u00E9rence \:
766
ref_name_field=Nom de r\u00E9f\u00E9rence \:
766
regex_extractor_title=Extracteur Expression r\u00E9guli\u00E8re
767
regex_extractor_title=Extracteur Expression r\u00E9guli\u00E8re
767
regex_field=Expression r\u00E9guli\u00E8re \:
768
regex_field=Expression r\u00E9guli\u00E8re \:
Lines 1124-1129 Link Here
1124
transaction_controller_parent=G\u00E9n\u00E9rer en \u00E9chantillon parent
1125
transaction_controller_parent=G\u00E9n\u00E9rer en \u00E9chantillon parent
1125
transaction_controller_title=Contr\u00F4leur Transaction
1126
transaction_controller_title=Contr\u00F4leur Transaction
1126
unbind=D\u00E9connexion de l'unit\u00E9
1127
unbind=D\u00E9connexion de l'unit\u00E9
1128
undo=Annuler
1127
unescape_html_string=Cha\u00EEne \u00E0 \u00E9chapper
1129
unescape_html_string=Cha\u00EEne \u00E0 \u00E9chapper
1128
unescape_string=Cha\u00EEne de caract\u00E8res contenant des\u00E9chappements Java
1130
unescape_string=Cha\u00EEne de caract\u00E8res contenant des\u00E9chappements Java
1129
uniform_timer_delay=D\u00E9lai de d\u00E9calage constant (en millisecondes) \:
1131
uniform_timer_delay=D\u00E9lai de d\u00E9calage constant (en millisecondes) \:

Return to bug 42248