001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.jmeter.gui.action;
020:
021: import java.awt.event.ActionEvent;
022: import java.awt.event.ActionListener;
023: import java.util.HashMap;
024: import java.util.HashSet;
025: import java.util.Map;
026: import java.util.Set;
027:
028: import org.apache.jmeter.gui.GuiPackage;
029: import org.apache.jmeter.gui.tree.JMeterTreeNode;
030: import org.apache.jorphan.collections.HashTree;
031: import org.apache.jorphan.collections.HashTreeTraverser;
032: import org.apache.jorphan.collections.ListedHashTree;
033: import org.apache.jorphan.logging.LoggingManager;
034: import org.apache.log.Logger;
035:
036: /**
037: * Check if the TestPlan has been changed since it was last saved
038: *
039: */
040: public class CheckDirty extends AbstractAction implements
041: HashTreeTraverser, ActionListener {
042: private static final Logger log = LoggingManager
043: .getLoggerForClass();
044:
045: private Map previousGuiItems;
046:
047: private boolean checkMode = false;
048:
049: private boolean removeMode = false;
050:
051: private boolean dirty = false;
052:
053: private static Set commands = new HashSet();
054: static {
055: commands.add(ActionNames.CHECK_DIRTY);
056: commands.add(ActionNames.SUB_TREE_SAVED);
057: commands.add(ActionNames.SUB_TREE_MERGED);
058: commands.add(ActionNames.SUB_TREE_LOADED);
059: commands.add(ActionNames.ADD_ALL);
060: commands.add(ActionNames.CHECK_REMOVE);
061: }
062:
063: public CheckDirty() {
064: previousGuiItems = new HashMap();
065: ActionRouter.getInstance().addPreActionListener(
066: ExitCommand.class, this );
067: }
068:
069: public void actionPerformed(ActionEvent e) {
070: if (e.getActionCommand().equals(ActionNames.EXIT)) {
071: doAction(e);
072: }
073: }
074:
075: /**
076: * @see Command#doAction(ActionEvent)
077: */
078: public void doAction(ActionEvent e) {
079: String action = e.getActionCommand();
080: if (action.equals(ActionNames.SUB_TREE_SAVED)) {
081: HashTree subTree = (HashTree) e.getSource();
082: subTree.traverse(this );
083: } else if (action.equals(ActionNames.SUB_TREE_LOADED)) {
084: ListedHashTree addTree = (ListedHashTree) e.getSource();
085: addTree.traverse(this );
086: } else if (action.equals(ActionNames.ADD_ALL)) {
087: previousGuiItems.clear();
088: GuiPackage.getInstance().getTreeModel().getTestPlan()
089: .traverse(this );
090: } else if (action.equals(ActionNames.CHECK_REMOVE)) {
091: GuiPackage guiPackage = GuiPackage.getInstance();
092: JMeterTreeNode[] nodes = guiPackage.getTreeListener()
093: .getSelectedNodes();
094: removeMode = true;
095: for (int i = nodes.length - 1; i >= 0; i--) {
096: guiPackage.getTreeModel().getCurrentSubTree(nodes[i])
097: .traverse(this );
098: }
099: removeMode = false;
100: }
101: // If we are merging in another test plan, we know the test plan is dirty now
102: if (action.equals(ActionNames.SUB_TREE_MERGED)) {
103: dirty = true;
104: } else {
105: dirty = false;
106: checkMode = true;
107: HashTree wholeTree = GuiPackage.getInstance()
108: .getTreeModel().getTestPlan();
109: wholeTree.traverse(this );
110: checkMode = false;
111: }
112: GuiPackage.getInstance().setDirty(dirty);
113: }
114:
115: /**
116: * The tree traverses itself depth-first, calling processNode for each
117: * object it encounters as it goes.
118: */
119: public void addNode(Object node, HashTree subTree) {
120: log.debug("Node is class:" + node.getClass());
121: JMeterTreeNode treeNode = (JMeterTreeNode) node;
122: if (checkMode) {
123: // Only check if we have not found any differences so far
124: if (!dirty) {
125: if (previousGuiItems.containsKey(treeNode)) {
126: if (!previousGuiItems.get(treeNode).equals(
127: treeNode.getTestElement())) {
128: dirty = true;
129: }
130: } else {
131: dirty = true;
132: }
133: }
134: } else if (removeMode) {
135: previousGuiItems.remove(treeNode);
136: } else {
137: previousGuiItems.put(treeNode, treeNode.getTestElement()
138: .clone());
139: }
140: }
141:
142: /**
143: * Indicates traversal has moved up a step, and the visitor should remove
144: * the top node from it's stack structure.
145: */
146: public void subtractNode() {
147: }
148:
149: /**
150: * Process path is called when a leaf is reached. If a visitor wishes to
151: * generate Lists of path elements to each leaf, it should keep a Stack data
152: * structure of nodes passed to it with addNode, and removing top items for
153: * every subtractNode() call.
154: */
155: public void processPath() {
156: }
157:
158: /**
159: * @see Command#getActionNames()
160: */
161: public Set getActionNames() {
162: return commands;
163: }
164: }
|