You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2017/09/28 19:12:45 UTC
svn commit: r1810034 - in /jmeter/trunk/src/core/org/apache/jmeter/gui: ./
action/ tree/
Author: pmouawad
Date: Thu Sep 28 19:12:44 2017
New Revision: 1810034
URL: http://svn.apache.org/viewvc?rev=1810034&view=rev
Log:
Bug 57039 - Inconsistency with the undo/redo log
This closes #310
Contributed by Emilian Bold
Bugzilla Id: 57039
Added:
jmeter/trunk/src/core/org/apache/jmeter/gui/GlobalUndoableEdit.java (with props)
jmeter/trunk/src/core/org/apache/jmeter/gui/SimpleCompoundEdit.java (with props)
jmeter/trunk/src/core/org/apache/jmeter/gui/TreeState.java (with props)
Modified:
jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java
jmeter/trunk/src/core/org/apache/jmeter/gui/UndoHistory.java
jmeter/trunk/src/core/org/apache/jmeter/gui/UndoHistoryItem.java
jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionRouter.java
jmeter/trunk/src/core/org/apache/jmeter/gui/action/CheckDirty.java
jmeter/trunk/src/core/org/apache/jmeter/gui/action/ResetSearchCommand.java
jmeter/trunk/src/core/org/apache/jmeter/gui/action/SearchTreeDialog.java
jmeter/trunk/src/core/org/apache/jmeter/gui/action/UndoCommand.java
jmeter/trunk/src/core/org/apache/jmeter/gui/tree/JMeterTreeNode.java
Added: jmeter/trunk/src/core/org/apache/jmeter/gui/GlobalUndoableEdit.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/GlobalUndoableEdit.java?rev=1810034&view=auto
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/GlobalUndoableEdit.java (added)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/GlobalUndoableEdit.java Thu Sep 28 19:12:44 2017
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.jmeter.gui;
+
+import java.util.function.Consumer;
+import javax.swing.undo.AbstractUndoableEdit;
+import javax.swing.undo.CannotRedoException;
+import javax.swing.undo.CannotUndoException;
+
+public final class GlobalUndoableEdit extends AbstractUndoableEdit {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4964577622742131354L;
+ private final UndoHistoryItem item;
+ private final UndoHistoryItem previous;
+ private final Consumer<UndoHistoryItem> loader;
+
+ public GlobalUndoableEdit(UndoHistoryItem item, UndoHistoryItem previous, Consumer<UndoHistoryItem> loader) {
+ this.item = item;
+ this.previous = previous;
+ this.loader = loader;
+ }
+
+ @Override
+ public void undo() throws CannotUndoException {
+ super.undo();
+
+ loader.accept(previous);
+ }
+
+ @Override
+ public void redo() throws CannotRedoException {
+ super.redo();
+
+ loader.accept(item);
+ }
+}
Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/GlobalUndoableEdit.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/GlobalUndoableEdit.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java?rev=1810034&r1=1810033&r2=1810034&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java Thu Sep 28 19:12:44 2017
@@ -810,12 +810,17 @@ public final class GuiPackage implements
}
/**
- * Navigate back and forward through undo history
- *
- * @param offset int
+ * Navigate back through undo history
*/
- public void goInHistory(int offset) {
- undoHistory.moveInHistory(offset, this.treeModel);
+ public void undo() {
+ undoHistory.undo();
+ }
+
+ /**
+ * Navigate forward through undo history
+ */
+ public void redo() {
+ undoHistory.redo();
}
/**
@@ -901,4 +906,18 @@ public final class GuiPackage implements
public GuiLogEventBus getLogEventBus() {
return logEventBus;
}
+
+ /**
+ * Begin a group of actions modeled as 1 undo
+ */
+ public void beginUndoTransaction() {
+ undoHistory.beginUndoTransaction();
+ }
+
+ /**
+ * End a group of actions modeled as 1 undo
+ */
+ public void endUndoTransaction() {
+ undoHistory.endUndoTransaction();
+ }
}
Added: jmeter/trunk/src/core/org/apache/jmeter/gui/SimpleCompoundEdit.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/SimpleCompoundEdit.java?rev=1810034&view=auto
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/SimpleCompoundEdit.java (added)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/SimpleCompoundEdit.java Thu Sep 28 19:12:44 2017
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.jmeter.gui;
+
+import javax.swing.undo.CompoundEdit;
+
+public class SimpleCompoundEdit extends CompoundEdit {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7125085226441904495L;
+
+ /**
+ * @return boolean true if edits is empty
+ */
+ public boolean isEmpty() {
+ return edits.isEmpty();
+ }
+
+ /**
+ * @return size of edits
+ */
+ public int size() {
+ return edits.size();
+ }
+}
Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/SimpleCompoundEdit.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/SimpleCompoundEdit.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jmeter/trunk/src/core/org/apache/jmeter/gui/TreeState.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/TreeState.java?rev=1810034&view=auto
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/TreeState.java (added)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/TreeState.java Thu Sep 28 19:12:44 2017
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.jmeter.gui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JTree;
+
+public interface TreeState {
+
+ /**
+ * Restore tree expanded and selected state
+ *
+ * @param guiInstance GuiPackage to be used
+ */
+ void restore(GuiPackage guiInstance);
+
+ static final TreeState NOTHING = (GuiPackage guiInstance) -> {};
+
+ /**
+ * Save tree expanded and selected state
+ *
+ * @param guiPackage {@link GuiPackage} to be used
+ */
+ public static TreeState from(GuiPackage guiPackage) {
+ if (guiPackage == null) {
+ return NOTHING;
+ }
+
+ MainFrame mainframe = guiPackage.getMainFrame();
+ if (mainframe != null) {
+ final JTree tree = mainframe.getTree();
+ int savedSelected = tree.getMinSelectionRow();
+ ArrayList<Integer> savedExpanded = new ArrayList<>();
+
+ for (int rowN = 0; rowN < tree.getRowCount(); rowN++) {
+ if (tree.isExpanded(rowN)) {
+ savedExpanded.add(rowN);
+ }
+ }
+
+ return new TreeStateImpl(savedSelected, savedExpanded);
+ }
+
+ return NOTHING;
+ }
+
+ static final class TreeStateImpl implements TreeState {
+
+ // GUI tree expansion state
+ private final List<Integer> savedExpanded;
+
+ // GUI tree selected row
+ private final int savedSelected;
+
+ public TreeStateImpl(int savedSelected, List<Integer> savedExpanded) {
+ this.savedSelected = savedSelected;
+ this.savedExpanded = savedExpanded;
+ }
+
+ @Override
+ public void restore(GuiPackage guiInstance) {
+ MainFrame mainframe = guiInstance.getMainFrame();
+ if (mainframe == null) {
+ //log?
+ return;
+ }
+
+ final JTree tree = mainframe.getTree();
+
+ if (!savedExpanded.isEmpty()) {
+ for (int rowN : savedExpanded) {
+ tree.expandRow(rowN);
+ }
+ } else {
+ tree.expandRow(0);
+ }
+ tree.setSelectionRow(savedSelected);
+ }
+ }
+}
Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/TreeState.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/TreeState.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/UndoHistory.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/UndoHistory.java?rev=1810034&r1=1810033&r2=1810034&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/UndoHistory.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/UndoHistory.java Thu Sep 28 19:12:44 2017
@@ -21,10 +21,12 @@ package org.apache.jmeter.gui;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
+import java.util.Stack;
-import javax.swing.JTree;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
+import javax.swing.undo.UndoManager;
+import javax.swing.undo.UndoableEdit;
import org.apache.jmeter.gui.action.UndoCommand;
import org.apache.jmeter.gui.tree.JMeterTreeModel;
@@ -53,50 +55,10 @@ public class UndoHistory implements Tree
void notifyChangeInHistory(UndoHistory history);
}
- /**
- * Avoid storing too many elements
- *
- * @param <T> Class that should be held in this container
- */
- private static class LimitedArrayList<T> extends ArrayList<T> {
- /**
- *
- */
- private static final long serialVersionUID = -6574380490156356507L;
- private int limit;
-
- public LimitedArrayList(int limit) {
- this.limit = limit;
- }
-
- @Override
- public boolean add(T item) {
- if (this.size() + 1 > limit) {
- this.remove(0);
- }
- return super.add(item);
- }
- }
-
private static final Logger log = LoggerFactory.getLogger(UndoHistory.class);
- /**
- * temporary storage for GUI tree expansion state
- */
- private ArrayList<Integer> savedExpanded = new ArrayList<>();
-
- /**
- * temporary storage for GUI tree selected row
- */
- private int savedSelected = 0;
-
- private static final int INITIAL_POS = -1;
- private int position = INITIAL_POS;
-
private static final int HISTORY_SIZE = JMeterUtils.getPropDefault("undo.history.size", 0);
- private List<UndoHistoryItem> history = new LimitedArrayList<>(HISTORY_SIZE);
-
/**
* flag to prevent recursive actions
*/
@@ -107,7 +69,14 @@ public class UndoHistory implements Tree
*/
private List<HistoryListener> listeners = new ArrayList<>();
+ private final UndoManager manager = new UndoManager();
+
+ private final Stack<SimpleCompoundEdit> transactions = new Stack<>();
+
+ private UndoHistoryItem lastKnownState = null;
+
public UndoHistory() {
+ manager.setLimit(HISTORY_SIZE);
}
/**
@@ -118,8 +87,14 @@ public class UndoHistory implements Tree
return;
}
log.debug("Clearing undo history");
- history.clear();
- position = INITIAL_POS;
+ manager.discardAllEdits();
+ if (isTransaction()) {
+ if(log.isWarnEnabled()) {
+ log.warn("Clearing undo history with {} unfinished transactions", transactions.size());
+ }
+ transactions.clear();
+ }
+ lastKnownState = null;
notifyListeners();
}
@@ -160,63 +135,46 @@ public class UndoHistory implements Tree
// first clone to not convert original tree
tree = (HashTree) tree.getTree(tree.getArray()[0]).clone();
- position++;
- while (history.size() > position) {
- if (log.isDebugEnabled()) {
- log.debug("Removing further record, position: {}, size: {}", position, history.size());
- }
- history.remove(history.size() - 1);
- }
-
// cloning is required because we need to immute stored data
HashTree copy = UndoCommand.convertAndCloneSubTree(tree);
- history.add(new UndoHistoryItem(copy, comment));
+ GuiPackage guiPackage = GuiPackage.getInstance();
+ //or maybe a Boolean?
+ boolean dirty = guiPackage != null ? guiPackage.isDirty() : false;
+ addEdit(new UndoHistoryItem(copy, comment, TreeState.from(guiPackage), dirty));
- log.debug("Added history element, position: {}, size: {}", position, history.size());
working = false;
- notifyListeners();
}
- /**
- * Goes through undo history, changing GUI
- *
- * @param offset the direction to go to, usually -1 for undo or 1 for redo
- * @param acceptorModel TreeModel to accept the changes
- */
- public void moveInHistory(int offset, JMeterTreeModel acceptorModel) {
- log.debug("Moving history from position {} with step {}, size is {}", position, offset, history.size());
- if (offset < 0 && !canUndo()) {
+ public void undo() {
+ if (!canUndo()) {
log.warn("Can't undo, we're already on the last record");
return;
}
+ manager.undo();
+ }
- if (offset > 0 && !canRedo()) {
+ public void redo() {
+ if (!canRedo()) {
log.warn("Can't redo, we're already on the first record");
return;
}
+ manager.redo();
+ }
- if (history.isEmpty()) {
- log.warn("Can't proceed, the history is empty");
- return;
- }
-
- position += offset;
-
+ private void reload(UndoHistoryItem z) {
final GuiPackage guiInstance = GuiPackage.getInstance();
+ JMeterTreeModel acceptorModel = guiInstance.getTreeModel();
- // save tree expansion and selection state before changing the tree
- saveTreeState(guiInstance);
-
- // load the tree
- loadHistoricalTree(acceptorModel, guiInstance);
-
- // load tree UI state
- restoreTreeState(guiInstance);
-
- if (log.isDebugEnabled()) {
- log.debug("Current position {}, size is {}", position, history.size());
+ try {
+ // load the tree
+ loadHistoricalTree(acceptorModel, guiInstance, z.getTree());
+ } finally {
+ // load tree UI state
+ z.getTreeState().restore(guiInstance);
+ guiInstance.setDirty(z.isDirty());
}
+ setLastKnownState(z);
// refresh the all ui
guiInstance.updateCurrentGui();
@@ -230,8 +188,7 @@ public class UndoHistory implements Tree
* @param acceptorModel tree to accept the data
* @param guiInstance {@link GuiPackage} to be used
*/
- private void loadHistoricalTree(JMeterTreeModel acceptorModel, GuiPackage guiInstance) {
- HashTree newModel = history.get(position).getTree();
+ private void loadHistoricalTree(JMeterTreeModel acceptorModel, GuiPackage guiInstance, HashTree newModel) {
acceptorModel.removeTreeModelListener(this);
working = true;
try {
@@ -239,23 +196,24 @@ public class UndoHistory implements Tree
guiInstance.addSubTree(newModel);
} catch (Exception ex) {
log.error("Failed to load from history", ex);
+ } finally {
+ acceptorModel.addTreeModelListener(this);
+ working = false;
}
- acceptorModel.addTreeModelListener(this);
- working = false;
}
/**
* @return true if remaining items
*/
public boolean canRedo() {
- return position < history.size() - 1;
+ return manager.canRedo();
}
/**
* @return true if not at first element
*/
public boolean canUndo() {
- return position > INITIAL_POS + 1;
+ return manager.canUndo();
}
/**
@@ -308,45 +266,6 @@ public class UndoHistory implements Tree
}
/**
- * Save tree expanded and selected state
- *
- * @param guiPackage {@link GuiPackage} to be used
- */
- private void saveTreeState(GuiPackage guiPackage) {
- savedExpanded.clear();
-
- MainFrame mainframe = guiPackage.getMainFrame();
- if (mainframe != null) {
- final JTree tree = mainframe.getTree();
- savedSelected = tree.getMinSelectionRow();
-
- for (int rowN = 0; rowN < tree.getRowCount(); rowN++) {
- if (tree.isExpanded(rowN)) {
- savedExpanded.add(Integer.valueOf(rowN));
- }
- }
- }
- }
-
- /**
- * Restore tree expanded and selected state
- *
- * @param guiInstance GuiPackage to be used
- */
- private void restoreTreeState(GuiPackage guiInstance) {
- final JTree tree = guiInstance.getMainFrame().getTree();
-
- if (savedExpanded.size() > 0) {
- for (int rowN : savedExpanded) {
- tree.expandRow(rowN);
- }
- } else {
- tree.expandRow(0);
- }
- tree.setSelectionRow(savedSelected);
- }
-
- /**
* @return true if history is enabled
*/
public static boolean isEnabled() {
@@ -370,4 +289,48 @@ public class UndoHistory implements Tree
}
}
+ private void addEdit(UndoHistoryItem item) {
+ if (lastKnownState != null) {
+ GlobalUndoableEdit edit = new GlobalUndoableEdit(item, lastKnownState, this::reload);
+ addEdit(edit);
+ } else {
+ log.debug("Skipping undo since there is no previous known state");
+ }
+ lastKnownState = item;
+ }
+
+ private void addEdit(UndoableEdit edit) {
+ if (isTransaction()) {
+ transactions.peek().addEdit(edit);
+ //XXX: Add sanity checks for transactions depth and number of edits?
+ } else {
+ manager.addEdit(edit);
+ notifyListeners();
+ }
+ }
+
+ void endUndoTransaction() {
+ if (!isTransaction()) {
+ log.error("Undo transaction ended without beginning", new Exception());
+ return;
+ }
+ SimpleCompoundEdit edit = transactions.pop();
+ edit.end();
+ if (!edit.isEmpty()) {
+ addEdit(edit);
+ }
+ }
+
+ void beginUndoTransaction() {
+ transactions.add(new SimpleCompoundEdit());
+ }
+
+ boolean isTransaction() {
+ return !transactions.isEmpty();
+ }
+
+ private void setLastKnownState(UndoHistoryItem previous) {
+ this.lastKnownState = previous;
+ }
+
}
Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/UndoHistoryItem.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/UndoHistoryItem.java?rev=1810034&r1=1810033&r2=1810034&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/UndoHistoryItem.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/UndoHistoryItem.java Thu Sep 28 19:12:44 2017
@@ -21,6 +21,7 @@ package org.apache.jmeter.gui;
import org.apache.jorphan.collections.HashTree;
import java.io.Serializable;
+import org.apache.jmeter.engine.TreeCloner;
/**
* Undo history item
@@ -35,6 +36,8 @@ public class UndoHistoryItem implements
private final HashTree tree;
// TODO: find a way to show this comment in menu item and toolbar tooltip
private final String comment;
+ private final TreeState treeState;
+ private final boolean dirty;
/**
* This constructor is for Unit test purposes only
@@ -42,24 +45,39 @@ public class UndoHistoryItem implements
*/
@Deprecated
public UndoHistoryItem() {
- tree = null;
- comment = null;
+ this(null, null, null, false);
}
/**
* @param copy HashTree
* @param acomment String
*/
- public UndoHistoryItem(HashTree copy, String acomment) {
+ public UndoHistoryItem(HashTree copy, String acomment, TreeState treeState, boolean dirty) {
tree = copy;
comment = acomment;
+ this.treeState = treeState;
+ this.dirty = dirty;
+ }
+
+ public boolean isDirty() {
+ return dirty;
+ }
+
+ public TreeState getTreeState() {
+ return treeState;
}
/**
* @return {@link org.apache.jorphan.collections.HashTree}
*/
public HashTree getTree() {
- return tree;
+ //EMI: It's important we return a clone here and not the actual tree because
+ // the history item might still be part of some undo action and we don't
+ // want to expose (and corrupt then via edits) internal data
+ TreeCloner cloner = new TreeCloner(false);
+ tree.traverse(cloner);
+
+ return cloner.getClonedTree();
}
/**
Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionRouter.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionRouter.java?rev=1810034&r1=1810033&r2=1810034&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionRouter.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionRouter.java Thu Sep 28 19:12:44 2017
@@ -26,6 +26,7 @@ import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.CodeSource;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -57,6 +58,10 @@ public final class ActionRouter implemen
private final Map<String, Set<ActionListener>> postActionListeners =
new HashMap<>();
+ // New action will clear undo, no point in having a transaction. Same with open
+ // EMI: XXX: Commands could also have an annotation to sigal the Undo preference
+ private final List<String> NO_TRANSACTION_ACTIONS = Arrays.asList(ActionNames.CLOSE, ActionNames.OPEN, ActionNames.OPEN_RECENT);
+
private ActionRouter() {
}
@@ -67,6 +72,9 @@ public final class ActionRouter implemen
private void performAction(final ActionEvent e) {
String actionCommand = e.getActionCommand();
+ if(!NO_TRANSACTION_ACTIONS.contains(actionCommand)) {
+ GuiPackage.getInstance().beginUndoTransaction();
+ }
try {
try {
GuiPackage.getInstance().updateCurrentGui();
@@ -100,6 +108,10 @@ public final class ActionRouter implemen
} catch (NullPointerException er) {
log.error("performAction({}) {} caused", actionCommand, e, er);
JMeterUtils.reportErrorToUser("Sorry, this feature (" + actionCommand + ") not yet implemented");
+ } finally {
+ if(!NO_TRANSACTION_ACTIONS.contains(actionCommand)) {
+ GuiPackage.getInstance().endUndoTransaction();
+ }
}
}
@@ -288,7 +300,7 @@ public final class ActionRouter implemen
private void actionPerformed(Class<? extends Command> action, ActionEvent e, Map<String, Set<ActionListener>> actionListeners) {
if (action != null) {
Set<ActionListener> listenerSet = actionListeners.get(action.getName());
- if (listenerSet != null && listenerSet.size() > 0) {
+ if (listenerSet != null && !listenerSet.isEmpty()) {
ActionListener[] listeners = listenerSet.toArray(new ActionListener[listenerSet.size()]);
for (ActionListener listener : listeners) {
listener.actionPerformed(e);
Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/action/CheckDirty.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/CheckDirty.java?rev=1810034&r1=1810033&r2=1810034&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/action/CheckDirty.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/CheckDirty.java Thu Sep 28 19:12:44 2017
@@ -65,11 +65,12 @@ public class CheckDirty extends Abstract
public CheckDirty() {
previousGuiItems = new HashMap<>();
ActionRouter.getInstance().addPreActionListener(ExitCommand.class, this);
+ ActionRouter.getInstance().addPostActionListener(UndoCommand.class, this);
}
@Override
public void actionPerformed(ActionEvent e) {
- if (e.getActionCommand().equals(ActionNames.EXIT)) {
+ if (e.getActionCommand().equals(ActionNames.EXIT) || e.getActionCommand().equals(ActionNames.UNDO) || e.getActionCommand().equals(ActionNames.REDO)) {
doAction(e);
}
}
@@ -110,6 +111,16 @@ public class CheckDirty extends Abstract
// If we are merging in another test plan, we know the test plan is dirty now
if(action.equals(ActionNames.SUB_TREE_MERGED)) {
dirty = true;
+ } else if (action.equals(ActionNames.UNDO) || action.equals(ActionNames.REDO)) {
+ dirty = GuiPackage.getInstance().isDirty();
+ log.debug("Restoring dirty after undo/redo");
+
+ //remember
+ previousGuiItems.clear();
+ GuiPackage.getInstance().getTreeModel().getTestPlan().traverse(this);
+ if (isWorkbenchSaveable()) {
+ GuiPackage.getInstance().getTreeModel().getWorkBench().traverse(this);
+ }
}
else {
dirty = false;
Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/action/ResetSearchCommand.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/ResetSearchCommand.java?rev=1810034&r1=1810033&r2=1810034&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/action/ResetSearchCommand.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/ResetSearchCommand.java Thu Sep 28 19:12:44 2017
@@ -45,14 +45,19 @@ public class ResetSearchCommand extends
@Override
public void doAction(ActionEvent e) {
GuiPackage guiPackage = GuiPackage.getInstance();
- JMeterTreeModel jMeterTreeModel = guiPackage.getTreeModel();
- for (JMeterTreeNode jMeterTreeNode : jMeterTreeModel.getNodesOfType(Searchable.class)) {
- if (jMeterTreeNode.getUserObject() instanceof Searchable){
- List<JMeterTreeNode> matchingNodes = jMeterTreeNode.getPathToThreadGroup();
- for (JMeterTreeNode jMeterTreeNode2 : matchingNodes) {
- jMeterTreeNode2.setMarkedBySearch(false);
+ try{
+ guiPackage.beginUndoTransaction();
+ JMeterTreeModel jMeterTreeModel = guiPackage.getTreeModel();
+ for (JMeterTreeNode jMeterTreeNode : jMeterTreeModel.getNodesOfType(Searchable.class)) {
+ if (jMeterTreeNode.getUserObject() instanceof Searchable){
+ List<JMeterTreeNode> matchingNodes = jMeterTreeNode.getPathToThreadGroup();
+ for (JMeterTreeNode jMeterTreeNode2 : matchingNodes) {
+ jMeterTreeNode2.setMarkedBySearch(false);
+ }
}
}
+ } finally {
+ guiPackage.endUndoTransaction();
}
GuiPackage.getInstance().getMainFrame().repaint();
}
Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/action/SearchTreeDialog.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/SearchTreeDialog.java?rev=1810034&r1=1810033&r2=1810034&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/action/SearchTreeDialog.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/SearchTreeDialog.java Thu Sep 28 19:12:44 2017
@@ -96,8 +96,6 @@ public class SearchTreeDialog extends JD
private JButton searchAndExpandButton;
- private JButton replaceButton;
-
public SearchTreeDialog() {
super((JFrame) null, JMeterUtils.getResString("search_tree_title"), false); //$NON-NLS-1$
init();
@@ -170,7 +168,7 @@ public class SearchTreeDialog extends JD
searchButton.addActionListener(this);
searchAndExpandButton = new JButton(JMeterUtils.getResString("search_expand")); //$NON-NLS-1$
searchAndExpandButton.addActionListener(this);
- replaceButton = new JButton(JMeterUtils.getResString("search_replace_all")); //$NON-NLS-1$
+ JButton replaceButton = new JButton(JMeterUtils.getResString("search_replace_all")); //$NON-NLS-1$
replaceButton.addActionListener(this);
cancelButton = new JButton(JMeterUtils.getResString("cancel")); //$NON-NLS-1$
cancelButton.addActionListener(this);
@@ -232,31 +230,36 @@ public class SearchTreeDialog extends JD
searcher = new RawTextSearcher(isCaseSensitiveCB.isSelected(), searchTF.getText());
}
GuiPackage guiPackage = GuiPackage.getInstance();
- JMeterTreeModel jMeterTreeModel = guiPackage.getTreeModel();
- Set<JMeterTreeNode> nodes = new HashSet<>();
int numberOfMatches = 0;
- for (JMeterTreeNode jMeterTreeNode : jMeterTreeModel.getNodesOfType(Searchable.class)) {
- try {
- Searchable searchable = (Searchable) jMeterTreeNode.getUserObject();
- List<JMeterTreeNode> matchingNodes = jMeterTreeNode.getPathToThreadGroup();
- List<String> searchableTokens = searchable.getSearchableTokens();
- boolean result = searcher.search(searchableTokens);
- if (result) {
- numberOfMatches++;
- nodes.addAll(matchingNodes);
+ try {
+ guiPackage.beginUndoTransaction();
+ JMeterTreeModel jMeterTreeModel = guiPackage.getTreeModel();
+ Set<JMeterTreeNode> nodes = new HashSet<>();
+ for (JMeterTreeNode jMeterTreeNode : jMeterTreeModel.getNodesOfType(Searchable.class)) {
+ try {
+ Searchable searchable = (Searchable) jMeterTreeNode.getUserObject();
+ List<JMeterTreeNode> matchingNodes = jMeterTreeNode.getPathToThreadGroup();
+ List<String> searchableTokens = searchable.getSearchableTokens();
+ boolean result = searcher.search(searchableTokens);
+ if (result) {
+ numberOfMatches++;
+ nodes.addAll(matchingNodes);
+ }
+ } catch (Exception ex) {
+ logger.error("Error occurred searching for word:"+ wordToSearch+ " in node:"+jMeterTreeNode.getName(), ex);
}
- } catch (Exception ex) {
- logger.error("Error occurred searching for word:"+ wordToSearch+ " in node:"+jMeterTreeNode.getName(), ex);
}
- }
- GuiPackage guiInstance = GuiPackage.getInstance();
- JTree jTree = guiInstance.getMainFrame().getTree();
-
- for (JMeterTreeNode jMeterTreeNode : nodes) {
- jMeterTreeNode.setMarkedBySearch(true);
- if (expand) {
- jTree.expandPath(new TreePath(jMeterTreeNode.getPath()));
+ GuiPackage guiInstance = GuiPackage.getInstance();
+ JTree jTree = guiInstance.getMainFrame().getTree();
+
+ for (JMeterTreeNode jMeterTreeNode : nodes) {
+ jMeterTreeNode.setMarkedBySearch(true);
+ if (expand) {
+ jTree.expandPath(new TreePath(jMeterTreeNode.getPath()));
+ }
}
+ } finally {
+ guiPackage.endUndoTransaction();
}
GuiPackage.getInstance().getMainFrame().repaint();
searchTF.requestFocusInWindow();
Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/action/UndoCommand.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/UndoCommand.java?rev=1810034&r1=1810033&r2=1810034&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/action/UndoCommand.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/UndoCommand.java Thu Sep 28 19:12:44 2017
@@ -46,9 +46,9 @@ public class UndoCommand extends Abstrac
final String command = e.getActionCommand();
if (command.equals(ActionNames.UNDO)) {
- guiPackage.goInHistory(-1);
+ guiPackage.undo();
} else if (command.equals(ActionNames.REDO)) {
- guiPackage.goInHistory(1);
+ guiPackage.redo();
} else {
throw new IllegalArgumentException("Wrong action called: " + command);
}
Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/tree/JMeterTreeNode.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/tree/JMeterTreeNode.java?rev=1810034&r1=1810033&r2=1810034&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/tree/JMeterTreeNode.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/tree/JMeterTreeNode.java Thu Sep 28 19:12:44 2017
@@ -95,6 +95,9 @@ public class JMeterTreeNode extends Defa
* @param tagged The flag to be used for tagging
*/
public void setMarkedBySearch(boolean tagged) {
+ if(this.markedBySearch == tagged) {
+ return;
+ }
this.markedBySearch = tagged;
treeModel.nodeChanged(this);
}