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

(-)src/core/org/apache/jmeter/gui/GuiPackage.java (+27 lines)
Lines 32-37 Link Here
32
import javax.swing.JOptionPane;
32
import javax.swing.JOptionPane;
33
import javax.swing.JPopupMenu;
33
import javax.swing.JPopupMenu;
34
import javax.swing.SwingUtilities;
34
import javax.swing.SwingUtilities;
35
import javax.swing.tree.TreePath;
35
36
36
import org.apache.jmeter.engine.util.ValueReplacer;
37
import org.apache.jmeter.engine.util.ValueReplacer;
37
import org.apache.jmeter.exceptions.IllegalUserActionException;
38
import org.apache.jmeter.exceptions.IllegalUserActionException;
Lines 43-48 Link Here
43
import org.apache.jmeter.testbeans.gui.TestBeanGUI;
44
import org.apache.jmeter.testbeans.gui.TestBeanGUI;
44
import org.apache.jmeter.testelement.TestElement;
45
import org.apache.jmeter.testelement.TestElement;
45
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;
46
import org.apache.jmeter.util.JMeterUtils;
50
import org.apache.jmeter.util.JMeterUtils;
47
import org.apache.jmeter.util.LocaleChangeEvent;
51
import org.apache.jmeter.util.LocaleChangeEvent;
48
import org.apache.jmeter.util.LocaleChangeListener;
52
import org.apache.jmeter.util.LocaleChangeListener;
Lines 394-400 Link Here
394
                log.debug("Updating current node " + currentNode.getName());
398
                log.debug("Updating current node " + currentNode.getName());
395
                JMeterGUIComponent comp = getGui(currentNode.getTestElement());
399
                JMeterGUIComponent comp = getGui(currentNode.getTestElement());
396
                TestElement el = currentNode.getTestElement();
400
                TestElement el = currentNode.getTestElement();
401
                int before=getTestElementCheckSum(el);
397
                comp.modifyTestElement(el);
402
                comp.modifyTestElement(el);
403
                int after=getTestElementCheckSum(el);
404
                if (before!=after) {
405
                    treeModel.saveUndoPoint(new TreePath(currentNode.getPath()), "Properties Changed");
406
                }
398
                currentNode.nameChanged(); // Bug 50221 - ensure label is updated
407
                currentNode.nameChanged(); // Bug 50221 - ensure label is updated
399
            }
408
            }
400
            // The current node is now updated
409
            // The current node is now updated
Lines 684-687 Link Here
684
        list.addAll(stoppables);
693
        list.addAll(stoppables);
685
        return list;
694
        return list;
686
    }
695
    }
696
    
697
    // better would override hashCode for TestElement, but I decided to not touch it
698
    // the method calculates properties checksum to detect testelement modifications
699
    private int getTestElementCheckSum(TestElement el) {
700
        int ret = el.getClass().hashCode();
701
        PropertyIterator it = el.propertyIterator();
702
        while (it.hasNext()) {
703
            JMeterProperty obj = it.next();
704
            if (obj instanceof TestElementProperty) {
705
                ret ^= getTestElementCheckSum(((TestElementProperty) obj).getElement());
706
            } else {
707
                ret ^= obj.getName().hashCode();
708
                ret ^= obj.getStringValue().hashCode();
687
}
709
}
710
        }
711
712
        return ret;
713
    }
714
}
(-)src/core/org/apache/jmeter/gui/action/ActionNames.java (+2 lines)
Lines 83-88 Link Here
83
    public static final String SUB_TREE_SAVED   = "sub_tree_saved"; // $NON-NLS-1$
83
    public static final String SUB_TREE_SAVED   = "sub_tree_saved"; // $NON-NLS-1$
84
    public static final String TOGGLE           = "toggle"; // $NON-NLS-1$ enable/disable
84
    public static final String TOGGLE           = "toggle"; // $NON-NLS-1$ enable/disable
85
    public static final String WHAT_CLASS       = "what_class"; // $NON-NLS-1$
85
    public static final String WHAT_CLASS       = "what_class"; // $NON-NLS-1$
86
    public static final String UNDO             = "undo"; // $NON-NLS-1$
87
    public static final String REDO             = "redo"; // $NON-NLS-1$
86
88
87
    // Prevent instantiation
89
    // Prevent instantiation
88
    private ActionNames(){
90
    private ActionNames(){
(-)src/core/org/apache/jmeter/gui/action/KeyStrokes.java (+3 lines)
Lines 56-61 Link Here
56
    public static final KeyStroke PASTE             = KeyStroke.getKeyStroke(KeyEvent.VK_V, CONTROL_MASK);
56
    public static final KeyStroke PASTE             = KeyStroke.getKeyStroke(KeyEvent.VK_V, CONTROL_MASK);
57
    public static final KeyStroke WHAT_CLASS        = KeyStroke.getKeyStroke(KeyEvent.VK_W, CONTROL_MASK);
57
    public static final KeyStroke WHAT_CLASS        = KeyStroke.getKeyStroke(KeyEvent.VK_W, CONTROL_MASK);
58
    public static final KeyStroke CUT               = KeyStroke.getKeyStroke(KeyEvent.VK_X, CONTROL_MASK);
58
    public static final KeyStroke CUT               = KeyStroke.getKeyStroke(KeyEvent.VK_X, CONTROL_MASK);
59
    public static final KeyStroke UNDO               = KeyStroke.getKeyStroke(KeyEvent.VK_Z, CONTROL_MASK);
60
    // does Ctrl+Shift+Z right standard for redo?
61
    public static final KeyStroke REDO               = KeyStroke.getKeyStroke(KeyEvent.VK_Z, CONTROL_MASK | KeyEvent.SHIFT_DOWN_MASK);
59
    public static final KeyStroke REMOTE_STOP_ALL   = KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.ALT_DOWN_MASK);
62
    public static final KeyStroke REMOTE_STOP_ALL   = KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.ALT_DOWN_MASK);
60
    public static final KeyStroke REMOTE_SHUT_ALL   = KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.ALT_DOWN_MASK);
63
    public static final KeyStroke REMOTE_SHUT_ALL   = KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.ALT_DOWN_MASK);
61
64
(-)src/core/org/apache/jmeter/gui/action/UndoCommand.java (+61 lines)
Line 0 Link Here
1
package org.apache.jmeter.gui.action;
2
3
import java.awt.event.ActionEvent;
4
import java.util.HashSet;
5
import java.util.Set;
6
import javax.swing.JTree;
7
import javax.swing.tree.TreePath;
8
import org.apache.jmeter.exceptions.IllegalUserActionException;
9
import org.apache.jmeter.gui.GuiPackage;
10
import org.apache.jorphan.collections.HashTree;
11
import org.apache.jorphan.logging.LoggingManager;
12
import org.apache.log.Logger;
13
14
/**
15
 *
16
 * @author apc@apc.kg
17
 */
18
public class UndoCommand implements Command {
19
20
    private static final Logger log = LoggingManager.getLoggerForClass();
21
    private static final Set<String> commands = new HashSet<String>();
22
23
    static {
24
        commands.add(ActionNames.UNDO);
25
        commands.add(ActionNames.REDO);
26
    }
27
28
    @Override
29
    public void doAction(ActionEvent e) throws IllegalUserActionException {
30
        GuiPackage guiPackage = GuiPackage.getInstance();
31
        final String command = e.getActionCommand();
32
33
        TreePath path;
34
        if (command.equals(ActionNames.UNDO)) {
35
            path = guiPackage.getTreeModel().goInHistory(-1);
36
        } else if (command.equals(ActionNames.REDO)) {
37
            path = guiPackage.getTreeModel().goInHistory(1);
38
        } else {
39
            throw new IllegalArgumentException("Wrong action called: " + command);
40
        }
41
42
        // we need to go to recorded tree path
43
        // fixme: we have a problem with unselected tree item then
44
        // also the GUI reflects old GUI properties
45
        //final JTree tree = GuiPackage.getInstance().getMainFrame().getTree();
46
        //tree.setSelectionPath(path);
47
        guiPackage.updateCurrentGui();
48
        guiPackage.getMainFrame().repaint();
49
    }
50
51
    @Override
52
    public Set<String> getActionNames() {
53
        return commands;
54
    }
55
56
    // wrapper to use package-visible method
57
    public static void convertSubTree(HashTree tree) {
58
        Save executor = new Save();
59
        executor.convertSubTree(tree);
60
    }
61
}
(-)src/core/org/apache/jmeter/gui/tree/JMeterTreeModel.java (-1 / +27 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.TreeNode;
28
import javax.swing.tree.TreePath;
27
29
28
import org.apache.jmeter.config.gui.AbstractConfigGui;
30
import org.apache.jmeter.config.gui.AbstractConfigGui;
29
import org.apache.jmeter.control.gui.TestPlanGui;
31
import org.apache.jmeter.control.gui.TestPlanGui;
Lines 42-51 Link Here
42
public class JMeterTreeModel extends DefaultTreeModel {
44
public class JMeterTreeModel extends DefaultTreeModel {
43
45
44
    private static final long serialVersionUID = 240L;
46
    private static final long serialVersionUID = 240L;
47
    private UndoHistory undoHistory = new UndoHistory();
45
48
46
    public JMeterTreeModel(TestElement tp, TestElement wb) {
49
    public JMeterTreeModel(TestElement tp, TestElement wb) {
47
        super(new JMeterTreeNode(wb, null));
50
        super(new JMeterTreeNode(wb, null));
48
        initTree(tp,wb);
51
        addTreeModelListener(undoHistory);
52
        initTree(tp, wb);
49
    }
53
    }
50
54
51
    public JMeterTreeModel() {
55
    public JMeterTreeModel() {
Lines 242-246 Link Here
242
        // This should not be necessary, but without it, nodes are not shown when the user
246
        // This should not be necessary, but without it, nodes are not shown when the user
243
        // uses the Close menu item
247
        // uses the Close menu item
244
        nodeStructureChanged((JMeterTreeNode)getRoot());
248
        nodeStructureChanged((JMeterTreeNode)getRoot());
249
        undoHistory.clear();
250
        saveUndoPoint(new TreePath(((JMeterTreeNode)getRoot()).getPath()), "Initial Tree");
245
    }
251
    }
252
253
    public TreePath goInHistory(int offset) {
254
        return undoHistory.getRelativeState(offset, this);
246
}
255
}
256
257
    public void saveUndoPoint(TreePath path, String comment) {
258
        undoHistory.add(this, path, comment);
259
    }
260
261
    public void clearUndo() {
262
        undoHistory.clear();
263
    }
264
265
    public boolean canRedo() {
266
        return undoHistory.canRedo();
267
    }
268
269
    public boolean canUndo() {
270
        return undoHistory.canUndo();
271
    }
272
}
(-)src/core/org/apache/jmeter/gui/tree/UndoHistory.java (+192 lines)
Line 0 Link Here
1
package org.apache.jmeter.gui.tree;
2
3
import java.awt.event.ActionEvent;
4
import java.util.ArrayList;
5
import java.util.Map.Entry;
6
import javax.swing.event.TreeModelEvent;
7
import javax.swing.event.TreeModelListener;
8
import javax.swing.tree.TreePath;
9
import org.apache.jmeter.engine.TreeCloner;
10
import org.apache.jmeter.gui.GuiPackage;
11
import org.apache.jmeter.gui.action.Load;
12
import org.apache.jmeter.gui.action.UndoCommand;
13
import org.apache.jorphan.collections.HashTree;
14
import org.apache.jorphan.logging.LoggingManager;
15
import org.apache.log.Logger;
16
17
/**
18
 * Users expected record situations: initial empty tree; before node deletion;
19
 * before node insertion; after each walk off edited node (modifyTestElement)
20
 *
21
 * @author apc@apc.kg
22
 */
23
public class UndoHistory
24
        implements TreeModelListener {
25
26
    private static final int INITIAL_POS = -1;
27
    private static final Logger log = LoggingManager.getLoggerForClass();
28
29
    private static class HistoryItem {
30
31
        private final HashTree tree;
32
        private final TreePath path;
33
        // maybe the comment should be removed since it is not used yet
34
        private final String comment;
35
36
        public HistoryItem(HashTree copy, TreePath apath, String acomment) {
37
            tree = copy;
38
            path = apath;
39
            comment = acomment;
40
        }
41
42
        public HashTree getKey() {
43
            return tree;
44
        }
45
46
        public TreePath getValue() {
47
            return path;
48
        }
49
50
        public String getComment() {
51
            return comment;
52
        }
53
    }
54
    private ArrayList<HistoryItem> history = new ArrayList<HistoryItem>();
55
    private int position = INITIAL_POS;
56
    /**
57
     * flag to prevent recursive actions
58
     */
59
    private boolean working = false;
60
61
    public UndoHistory() {
62
    }
63
64
    public void clear() {
65
        if (working) {
66
            return;
67
        }
68
        log.debug("Clearing history", new Throwable());
69
        history.clear();
70
        position = INITIAL_POS;
71
    }
72
73
    /**
74
     * this method relies on the rule that the record in history made AFTER
75
     * change has been made to test plan
76
     *
77
     * @param treeModel
78
     * @param path
79
     * @param comment
80
     */
81
    void add(JMeterTreeModel treeModel, TreePath path, String comment) {
82
        // don't add element if we are in the middle of undo/redo
83
        if (working) {
84
            return;
85
        }
86
87
        log.debug("Adding history element", new Throwable());
88
        JMeterTreeNode root = (JMeterTreeNode) ((JMeterTreeNode) treeModel.getRoot());
89
        if (root.getChildCount() < 1) {
90
            return;
91
        }
92
93
        working = true;
94
        // get test plan tree
95
        HashTree tree = treeModel.getCurrentSubTree((JMeterTreeNode) treeModel.getRoot());
96
        // first clone to not convert original tree
97
        tree = (HashTree) tree.getTree(tree.getArray()[0]).clone();
98
99
        position++;
100
        while (history.size() > position) {
101
            log.debug("Removing further record, position: " + position + ", size: " + history.size());
102
            history.remove(history.size() - 1);
103
        }
104
105
        // convert before clone!
106
        UndoCommand.convertSubTree(tree);
107
        TreeCloner cloner = new TreeCloner(false);
108
        tree.traverse(cloner);
109
        HashTree copy = cloner.getClonedTree();
110
111
112
        history.add(new HistoryItem(copy, path, comment));
113
114
        log.debug("Added history element, position: " + position + ", size: " + history.size());
115
        working = false;
116
    }
117
118
    public TreePath getRelativeState(int offset, JMeterTreeModel acceptorModel) {
119
        log.debug("Moving history from position " + position + " with step " + offset + ", size is " + history.size());
120
        if (offset < 0 && !canUndo()) {
121
            log.warn("Can't undo, we're already on the last record");
122
            return null;
123
        }
124
125
        if (offset > 0 && !canRedo()) {
126
            log.warn("Can't redo, we're already on the first record");
127
            return null;
128
        }
129
130
        position += offset;
131
132
        if (!history.isEmpty()) {
133
            HashTree newModel = history.get(position).getKey();
134
            acceptorModel.removeTreeModelListener(this);
135
            working = true;
136
            try {
137
                boolean res = Load.insertLoadedTree(ActionEvent.ACTION_PERFORMED, newModel);
138
                if (!res) {
139
                    throw new RuntimeException("Loaded data is not TestPlan");
140
                }
141
142
            } catch (Exception ex) {
143
                log.error("Failed to load from history", ex);
144
            }
145
            acceptorModel.addTreeModelListener(this);
146
            working = false;
147
        }
148
        log.debug("Current position " + position + ", size is " + history.size());
149
        // select historical path
150
        return history.get(position).getValue();
151
    }
152
153
    public boolean canRedo() {
154
        return position < history.size() - 1;
155
    }
156
157
    public boolean canUndo() {
158
        return position > INITIAL_POS + 1;
159
    }
160
161
    public void treeNodesChanged(TreeModelEvent tme) {
162
        log.debug("Nodes changed");
163
    }
164
165
    // is there better way to record test plan load events?
166
    // currently it records each node added separately
167
    public void treeNodesInserted(TreeModelEvent tme) {
168
        log.debug("Nodes inserted");
169
        final JMeterTreeModel sender = (JMeterTreeModel) tme.getSource();
170
        add(sender, getTreePathToRecord(tme), "Add");
171
    }
172
173
    public void treeNodesRemoved(TreeModelEvent tme) {
174
        log.debug("Nodes removed");
175
        add((JMeterTreeModel) tme.getSource(), getTreePathToRecord(tme), "Remove");
176
    }
177
178
    public void treeStructureChanged(TreeModelEvent tme) {
179
        log.debug("Nodes struct changed");
180
        add((JMeterTreeModel) tme.getSource(), getTreePathToRecord(tme), "Complex Change");
181
    }
182
183
    private TreePath getTreePathToRecord(TreeModelEvent tme) {
184
        TreePath path;
185
        if (GuiPackage.getInstance() != null) {
186
            path = GuiPackage.getInstance().getMainFrame().getTree().getSelectionPath();
187
        } else {
188
            path = tme.getTreePath();
189
        }
190
        return path;
191
    }
192
}
(-)src/core/org/apache/jmeter/gui/util/MenuFactory.java (+20 lines)
Lines 44-49 Link Here
44
import org.apache.jmeter.gui.action.ActionNames;
44
import org.apache.jmeter.gui.action.ActionNames;
45
import org.apache.jmeter.gui.action.ActionRouter;
45
import org.apache.jmeter.gui.action.ActionRouter;
46
import org.apache.jmeter.gui.action.KeyStrokes;
46
import org.apache.jmeter.gui.action.KeyStrokes;
47
import org.apache.jmeter.gui.action.UndoCommand;
47
import org.apache.jmeter.gui.tree.JMeterTreeNode;
48
import org.apache.jmeter.gui.tree.JMeterTreeNode;
48
import org.apache.jmeter.samplers.Sampler;
49
import org.apache.jmeter.samplers.Sampler;
49
import org.apache.jmeter.testbeans.TestBean;
50
import org.apache.jmeter.testbeans.TestBean;
Lines 194-199 Link Here
194
    }
195
    }
195
196
196
    public static void addFileMenu(JPopupMenu menu) {
197
    public static void addFileMenu(JPopupMenu menu) {
198
        // the undo/redo as a standard goes first in Edit menus
199
        // maybe there's better place for them in JMeter?
200
        addUndoItems(menu); 
201
        
197
        addSeparator(menu);
202
        addSeparator(menu);
198
        menu.add(makeMenuItemRes("open", ActionNames.OPEN));// $NON-NLS-1$
203
        menu.add(makeMenuItemRes("open", ActionNames.OPEN));// $NON-NLS-1$
199
        menu.add(makeMenuItemRes("menu_merge", ActionNames.MERGE));// $NON-NLS-1$
204
        menu.add(makeMenuItemRes("menu_merge", ActionNames.MERGE));// $NON-NLS-1$
Lines 679-682 Link Here
679
          Collections.sort(menuToSort, new MenuInfoComparator());
684
          Collections.sort(menuToSort, new MenuInfoComparator());
680
       }
685
       }
681
    }
686
    }
687
688
   private static void addUndoItems(JPopupMenu menu) {
689
        addSeparator(menu);
690
        
691
        JMenuItem redo = makeMenuItemRes("redo", ActionNames.REDO); //$NON-NLS-1$    
692
        redo.setAccelerator(KeyStrokes.REDO);
693
        // we could even show some hints on action being undone here
694
        // if this will be required (by passing those hints into history records)
695
        redo.setEnabled(GuiPackage.getInstance().getTreeModel().canRedo());
696
        menu.add(redo); 
697
        JMenuItem undo = makeMenuItemRes("undo", ActionNames.UNDO); //$NON-NLS-1$    
698
        undo.setAccelerator(KeyStrokes.UNDO);
699
        undo.setEnabled(GuiPackage.getInstance().getTreeModel().canUndo());
700
        menu.add(undo);
682
}
701
}
702
}
(-)src/core/org/apache/jmeter/resources/messages.properties (+2 lines)
Lines 1090-1092 Link Here
1090
you_must_enter_a_valid_number=You must enter a valid number
1090
you_must_enter_a_valid_number=You must enter a valid number
1091
zh_cn=Chinese (Simplified)
1091
zh_cn=Chinese (Simplified)
1092
zh_tw=Chinese (Traditional)
1092
zh_tw=Chinese (Traditional)
1093
undo=Undo
1094
redo=Redo
(-)test/src/org/apache/jmeter/gui/tree/UndoHistoryTest.java (+90 lines)
Line 0 Link Here
1
package org.apache.jmeter.gui.tree;
2
3
import java.io.File;
4
import java.io.IOException;
5
import java.util.Locale;
6
import javax.swing.tree.TreePath;
7
import org.apache.jmeter.util.JMeterUtils;
8
9
/**
10
 *
11
 * @author apc@apc.kg
12
 */
13
public class UndoHistoryTest extends junit.framework.TestCase {
14
15
    public UndoHistoryTest() {
16
        File propsFile = null;
17
        try {
18
            propsFile = File.createTempFile("jmeter-plugins", "testProps");
19
            propsFile.deleteOnExit();
20
        } catch (IOException ex) {
21
            ex.printStackTrace(System.err);
22
        }
23
24
        //propsFile=new File("/home/undera/NetBeansProjects/jmeter/trunk/bin/jmeter.properties");
25
26
        JMeterUtils.loadJMeterProperties(propsFile.getAbsolutePath());
27
        JMeterUtils.setLocale(new Locale("ignoreResources"));
28
    }
29
30
    /*
31
     * public void testGetTestElementCheckSum() {
32
     * System.out.println("getTestElementCheckSum"); TestElement el = new
33
     * TestAction(); int result = UndoHistory.getTestElementCheckSum(el);
34
     * assertTrue(result!=0); el.setProperty(new BooleanProperty());
35
     * assertTrue(result != UndoHistory.getTestElementCheckSum(el)); }
36
     *
37
     * public void testGetTestElementCheckSum_stable() {
38
     * System.out.println("getTestElementCheckSum stable"); TestElement el = new
39
     * ThreadGroup(); AbstractJMeterGuiComponent gui = new ThreadGroupGui();
40
     *
41
     * gui.modifyTestElement(el); int result1 =
42
     * UndoHistory.getTestElementCheckSum(el); gui.modifyTestElement(el); int
43
     * result2 = UndoHistory.getTestElementCheckSum(el); assertEquals(result1,
44
     * result2); el.setProperty(new BooleanProperty()); assertTrue(result1 !=
45
     * UndoHistory.getTestElementCheckSum(el)); }
46
     */
47
    public void testClear() {
48
        System.out.println("clear");
49
        UndoHistory instance = new UndoHistory();
50
        instance.clear();
51
    }
52
53
    public void testAdd() throws Exception {
54
        System.out.println("add");
55
        JMeterTreeModel treeModel = new JMeterTreeModel();
56
        UndoHistory instance = new UndoHistory();
57
        instance.add(treeModel, new TreePath(this), "");
58
    }
59
60
    public void testGetRelativeState() throws Exception {
61
        System.out.println("getRelativeState");
62
        JMeterTreeModel treeModelRecv = new JMeterTreeModel();
63
        UndoHistory instance = new UndoHistory();
64
65
        // safety check
66
        instance.getRelativeState(-1, treeModelRecv);
67
        instance.getRelativeState(1, treeModelRecv);
68
69
70
        JMeterTreeModel treeModel1 = new JMeterTreeModel();
71
        JMeterTreeModel treeModel2 = new JMeterTreeModel();
72
        JMeterTreeModel treeModel3 = new JMeterTreeModel();
73
        instance.add(treeModel1, new TreePath(this), "");
74
        instance.add(treeModel2, new TreePath(this), "");
75
        instance.add(treeModel3, new TreePath(this), "");
76
77
        // regular work check
78
        instance.getRelativeState(-1, treeModelRecv);
79
        instance.getRelativeState(-1, treeModelRecv);
80
        instance.getRelativeState(-1, treeModelRecv); // undo ignored
81
        instance.getRelativeState(1, treeModelRecv);
82
        instance.getRelativeState(1, treeModelRecv);
83
        instance.getRelativeState(1, treeModelRecv); // redo ignored
84
85
        // overwrite check
86
        instance.getRelativeState(-1, treeModelRecv);
87
        instance.getRelativeState(-1, treeModelRecv);
88
        instance.add(treeModel3, new TreePath(this), "");
89
    }
90
}

Return to bug 42248