1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package org.apache.jmeter.gui.tree; 20 21 import java.util.Enumeration; 22 import java.util.Iterator; 23 import java.util.LinkedList; 24 import java.util.List; 25 26 import javax.swing.tree.DefaultTreeModel; 27 28 import org.apache.jmeter.config.gui.AbstractConfigGui; 29 import org.apache.jmeter.control.gui.TestPlanGui; 30 import org.apache.jmeter.control.gui.WorkBenchGui; 31 import org.apache.jmeter.exceptions.IllegalUserActionException; 32 import org.apache.jmeter.gui.GuiPackage; 33 import org.apache.jmeter.gui.JMeterGUIComponent; 34 import org.apache.jmeter.testelement.TestElement; 35 import org.apache.jmeter.testelement.TestPlan; 36 import org.apache.jmeter.testelement.WorkBench; 37 import org.apache.jmeter.testelement.property.NullProperty; 38 import org.apache.jmeter.util.NameUpdater; 39 import org.apache.jorphan.collections.HashTree; 40 import org.apache.jorphan.collections.ListedHashTree; 41 42 public class JMeterTreeModel extends DefaultTreeModel { 43 44 public JMeterTreeModel(TestElement tp, TestElement wb) { 45 super(new JMeterTreeNode(wb, null)); 46 initTree(tp,wb); 47 } 48 49 public JMeterTreeModel() { 50 this(new TestPlanGui().createTestElement(),new WorkBenchGui().createTestElement()); 51 // super(new JMeterTreeNode(new WorkBenchGui().createTestElement(), null)); 52 // TestElement tp = new TestPlanGui().createTestElement(); 53 // initTree(tp); 54 } 55 56 /** 57 * Hack to allow TreeModel to be used in non-GUI and headless mode. 58 * 59 * @deprecated - only for use by JMeter class! 60 * @param o - dummy 61 */ 62 public JMeterTreeModel(Object o) { 63 this(new TestPlan(),new WorkBench()); 64 // super(new JMeterTreeNode(new WorkBench(), null)); 65 // TestElement tp = new TestPlan(); 66 // initTree(tp, new WorkBench()); 67 } 68 69 /** 70 * Returns a list of tree nodes that hold objects of the given class type. 71 * If none are found, an empty list is returned. 72 */ 73 public List getNodesOfType(Class type) { 74 List nodeList = new LinkedList(); 75 traverseAndFind(type, (JMeterTreeNode) this.getRoot(), nodeList); 76 return nodeList; 77 } 78 79 /** 80 * Get the node for a given TestElement object. 81 */ 82 public JMeterTreeNode getNodeOf(TestElement userObject) { 83 return traverseAndFind(userObject, (JMeterTreeNode) getRoot()); 84 } 85 86 /** 87 * Adds the sub tree at the given node. Returns a boolean indicating whether 88 * the added sub tree was a full test plan. 89 */ 90 public HashTree addSubTree(HashTree subTree, JMeterTreeNode current) throws IllegalUserActionException { 91 Iterator iter = subTree.list().iterator(); 92 while (iter.hasNext()) { 93 TestElement item = (TestElement) iter.next(); 94 if (item instanceof TestPlan) { 95 TestPlan tp = (TestPlan) item; 96 current = (JMeterTreeNode) ((JMeterTreeNode) getRoot()).getChildAt(0); 97 final TestPlan userObject = (TestPlan) current.getUserObject(); 98 userObject.addTestElement(item); 99 userObject.setName(item.getName()); 100 userObject.setFunctionalMode(tp.isFunctionalMode()); 101 userObject.setSerialized(tp.isSerialized()); 102 addSubTree(subTree.getTree(item), current); 103 } else if (item instanceof WorkBench) { 104 current = (JMeterTreeNode) ((JMeterTreeNode) getRoot()).getChildAt(1); 105 final TestElement testElement = ((TestElement) current.getUserObject()); 106 testElement.addTestElement(item); 107 testElement.setName(item.getName()); 108 addSubTree(subTree.getTree(item), current); 109 } else { 110 addSubTree(subTree.getTree(item), addComponent(item, current)); 111 } 112 } 113 return getCurrentSubTree(current); 114 } 115 116 public JMeterTreeNode addComponent(TestElement component, JMeterTreeNode node) throws IllegalUserActionException { 117 if (node.getUserObject() instanceof AbstractConfigGui) { 118 throw new IllegalUserActionException("This node cannot hold sub-elements"); 119 } 120 component.setProperty(TestElement.GUI_CLASS, NameUpdater.getCurrentName(component 121 .getPropertyAsString(TestElement.GUI_CLASS))); 122 123 GuiPackage guiPackage = GuiPackage.getInstance(); 124 if (guiPackage != null) { 125 // The node can be added in non GUI mode at startup 126 guiPackage.updateCurrentNode(); 127 JMeterGUIComponent guicomp = guiPackage.getGui(component); 128 guicomp.configure(component); 129 guicomp.modifyTestElement(component); 130 guiPackage.getCurrentGui(); // put the gui object back 131 // to the way it was. 132 } 133 JMeterTreeNode newNode = new JMeterTreeNode(component, this); 134 135 // This check the state of the TestElement and if returns false it 136 // disable the loaded node 137 try { 138 if (component.getProperty(TestElement.ENABLED) instanceof NullProperty 139 || component.getPropertyAsBoolean(TestElement.ENABLED)) { 140 newNode.setEnabled(true); 141 } else { 142 newNode.setEnabled(false); 143 } 144 } catch (Exception e) { 145 newNode.setEnabled(true); 146 } 147 148 this.insertNodeInto(newNode, node, node.getChildCount()); 149 return newNode; 150 } 151 152 public void removeNodeFromParent(JMeterTreeNode node) { 153 if (!(node.getUserObject() instanceof TestPlan) && !(node.getUserObject() instanceof WorkBench)) { 154 super.removeNodeFromParent(node); 155 } 156 } 157 158 private void traverseAndFind(Class type, JMeterTreeNode node, List nodeList) { 159 if (type.isInstance(node.getUserObject())) { 160 nodeList.add(node); 161 } 162 Enumeration enumNode = node.children(); 163 while (enumNode.hasMoreElements()) { 164 JMeterTreeNode child = (JMeterTreeNode) enumNode.nextElement(); 165 traverseAndFind(type, child, nodeList); 166 } 167 } 168 169 private JMeterTreeNode traverseAndFind(TestElement userObject, JMeterTreeNode node) { 170 if (userObject == node.getUserObject()) { 171 return node; 172 } 173 Enumeration enumNode = node.children(); 174 while (enumNode.hasMoreElements()) { 175 JMeterTreeNode child = (JMeterTreeNode) enumNode.nextElement(); 176 JMeterTreeNode result = traverseAndFind(userObject, child); 177 if (result != null) { 178 return result; 179 } 180 } 181 return null; 182 } 183 184 public HashTree getCurrentSubTree(JMeterTreeNode node) { 185 ListedHashTree hashTree = new ListedHashTree(node); 186 Enumeration enumNode = node.children(); 187 while (enumNode.hasMoreElements()) { 188 JMeterTreeNode child = (JMeterTreeNode) enumNode.nextElement(); 189 hashTree.add(node, getCurrentSubTree(child)); 190 } 191 return hashTree; 192 } 193 194 public HashTree getTestPlan() { 195 return getCurrentSubTree((JMeterTreeNode) ((JMeterTreeNode) this.getRoot()).getChildAt(0)); 196 } 197 198 /** 199 * Clear the test plan, and use default node for test plan and workbench. 200 * 201 * N.B. Should only be called by {@link GuiPackage#clearTestPlan()} 202 */ 203 public void clearTestPlan() { 204 TestElement tp = new TestPlanGui().createTestElement(); 205 clearTestPlan(tp); 206 } 207 208 /** 209 * Clear the test plan, and use specified node for test plan and default node for workbench 210 * 211 * N.B. Should only be called by {@link GuiPackage#clearTestPlan(TestElement)} 212 * 213 * @param testPlan the node to use as the testplan top node 214 */ 215 public void clearTestPlan(TestElement testPlan) { 216 // Remove the workbench and testplan nodes 217 int children = getChildCount(getRoot()); 218 while (children > 0) { 219 JMeterTreeNode child = (JMeterTreeNode)getChild(getRoot(), 0); 220 super.removeNodeFromParent(child); 221 children = getChildCount(getRoot()); 222 } 223 // Init the tree 224 initTree(testPlan,new WorkBenchGui().createTestElement()); // Assumes this is only called from GUI mode 225 } 226 227 /** 228 * Initialize the model with nodes for testplan and workbench. 229 * 230 * @param tp the element to use as testplan 231 * @param wb the element to use as workbench 232 */ 233 private void initTree(TestElement tp, TestElement wb) { 234 // Insert the test plan node 235 insertNodeInto(new JMeterTreeNode(tp, this), (JMeterTreeNode) getRoot(), 0); 236 // Insert the workbench node 237 insertNodeInto(new JMeterTreeNode(wb, this), (JMeterTreeNode) getRoot(), 1); 238 // Let others know that the tree content has changed. 239 // This should not be necessary, but without it, nodes are not shown when the user 240 // uses the Close menu item 241 nodeStructureChanged((JMeterTreeNode)getRoot()); 242 } 243 }