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, WITHOUT
013: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014: * License for the specific language governing permissions and limitations
015: * under the License.
016: *
017: */
018:
019: package org.apache.jmeter.config.gui;
020:
021: import java.awt.BorderLayout;
022: import java.awt.Component;
023: import java.awt.event.ActionEvent;
024: import java.awt.event.ActionListener;
025:
026: import javax.swing.Box;
027: import javax.swing.JButton;
028: import javax.swing.JPanel;
029: import javax.swing.JTable;
030: import javax.swing.ListSelectionModel;
031: import javax.swing.table.TableCellEditor;
032:
033: import org.apache.jmeter.config.ConfigTestElement;
034: import org.apache.jmeter.gui.util.PowerTableModel;
035: import org.apache.jmeter.testelement.TestElement;
036: import org.apache.jmeter.testelement.property.JMeterProperty;
037: import org.apache.jmeter.testelement.property.PropertyIterator;
038: import org.apache.jmeter.testelement.property.StringProperty;
039: import org.apache.jmeter.util.JMeterUtils;
040: import org.apache.jorphan.collections.Data;
041:
042: /**
043: * Default config gui for Configuration Element.
044: */
045: public class SimpleConfigGui extends AbstractConfigGui implements
046: ActionListener {
047: /* This class created for enhancement Bug ID 9101. */
048:
049: // TODO: This class looks a lot like ArgumentsPanel. What exactly is the
050: // difference? Could they be combined?
051: /** The table of configuration parameters. */
052: private JTable table;
053:
054: /** The model for the parameter table. */
055: private PowerTableModel tableModel;
056:
057: /** A button for adding new parameters to the table. */
058: private JButton add;
059:
060: /** A button for removing parameters from the table. */
061: private JButton delete;
062:
063: /** Command for adding a row to the table. */
064: private static final String ADD = "add";
065:
066: /** Command for removing a row from the table. */
067: private static final String DELETE = "delete";
068:
069: /**
070: * Boolean indicating whether or not this component should display its name.
071: * If true, this is a standalone component. If false, this component is
072: * intended to be used as a subpanel for another component.
073: */
074: private boolean displayName = true;
075:
076: /** The names of the columns in the table. */
077: private static final String COLUMN_NAMES_0 = JMeterUtils
078: .getResString("name"); // $NON-NLS-1$
079:
080: private static final String COLUMN_NAMES_1 = JMeterUtils
081: .getResString("value"); // $NON-NLS-1$
082:
083: // NOTUSED private static final String COLUMN_NAMES_2 =
084: // JMeterUtils.getResString("metadata");
085:
086: /**
087: * Create a new standalone SimpleConfigGui.
088: */
089: public SimpleConfigGui() {
090: this (true);
091: }
092:
093: /**
094: * Create a new SimpleConfigGui as either a standalone or an embedded
095: * component.
096: *
097: * @param displayName
098: * indicates whether or not this component should display its
099: * name. If true, this is a standalone component. If false, this
100: * component is intended to be used as a subpanel for another
101: * component.
102: */
103: public SimpleConfigGui(boolean displayName) {
104: this .displayName = displayName;
105: init();
106: }
107:
108: public String getLabelResource() {
109: return "simple_config_element"; // $NON-NLS-1$
110: }
111:
112: /**
113: * A newly created component can be initialized with the contents of a Test
114: * Element object by calling this method. The component is responsible for
115: * querying the Test Element object for the relevant information to display
116: * in its GUI.
117: * <p>
118: * This implementation retrieves all key/value pairs from the TestElement
119: * object and sets these values in the GUI.
120: *
121: * @param el
122: * the TestElement to configure
123: */
124: public void configure(TestElement el) {
125: super .configure(el);
126: tableModel.clearData();
127: PropertyIterator iter = el.propertyIterator();
128: while (iter.hasNext()) {
129: JMeterProperty prop = iter.next();
130: tableModel.addRow(new Object[] { prop.getName(),
131: prop.getStringValue() });
132: }
133: checkDeleteStatus();
134: }
135:
136: /* Implements JMeterGUIComponent.createTestElement() */
137: public TestElement createTestElement() {
138: TestElement el = new ConfigTestElement();
139: modifyTestElement(el);
140: return el;
141: }
142:
143: /**
144: * Get all of the values from the GUI component and set them in the
145: * TestElement.
146: *
147: * @param el
148: * the TestElement to modify
149: */
150: public void modifyTestElement(TestElement el) {
151: if (table.isEditing()) {
152: table.getCellEditor().stopCellEditing();
153: }
154: Data model = tableModel.getData();
155: model.reset();
156: while (model.next()) {
157: el.setProperty(new StringProperty((String) model
158: .getColumnValue(COLUMN_NAMES_0), (String) model
159: .getColumnValue(COLUMN_NAMES_1)));
160: }
161: super .configureTestElement(el);
162: }
163:
164: /**
165: * Initialize the components and layout of this component.
166: */
167: private void init() {
168: setLayout(new BorderLayout(0, 10));
169:
170: if (displayName) {
171: setBorder(makeBorder());
172: add(makeTitlePanel(), BorderLayout.NORTH);
173: }
174:
175: add(createTablePanel(), BorderLayout.CENTER);
176: // Force the table to be at least 70 pixels high
177: add(Box.createVerticalStrut(70), BorderLayout.WEST);
178: add(createButtonPanel(), BorderLayout.SOUTH);
179: }
180:
181: /**
182: * Invoked when an action occurs. This implementation supports the add and
183: * delete buttons.
184: *
185: * @param e
186: * the event that has occurred
187: */
188: public void actionPerformed(ActionEvent e) {
189: String action = e.getActionCommand();
190: if (action.equals(DELETE)) {
191: deleteArgument();
192: } else if (action.equals(ADD)) {
193: addArgument();
194: }
195: }
196:
197: /**
198: * Create a GUI panel containing the table of configuration parameters.
199: *
200: * @return a GUI panel containing the parameter table
201: */
202: private Component createTablePanel() {
203: tableModel = new PowerTableModel(new String[] { COLUMN_NAMES_0,
204: COLUMN_NAMES_1 }, new Class[] { String.class,
205: String.class });
206:
207: table = new JTable(tableModel);
208: table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
209: return makeScrollPane(table);
210: }
211:
212: /**
213: * Create a panel containing the add and delete buttons.
214: *
215: * @return a GUI panel containing the buttons
216: */
217: private JPanel createButtonPanel() {
218: add = new JButton(JMeterUtils.getResString("add")); //$NON-NLS-1$
219: add.setActionCommand(ADD);
220: add.addActionListener(this );
221: add.setEnabled(true);
222:
223: delete = new JButton(JMeterUtils.getResString("delete")); // $NON-NLS-1$
224: delete.setActionCommand(DELETE);
225: delete.addActionListener(this );
226:
227: checkDeleteStatus();
228:
229: JPanel buttonPanel = new JPanel();
230: buttonPanel.add(add);
231: buttonPanel.add(delete);
232: return buttonPanel;
233: }
234:
235: /**
236: * Enable or disable the delete button depending on whether or not there is
237: * a row to be deleted.
238: */
239: protected void checkDeleteStatus() {
240: // Disable DELETE if there are no rows in the table to delete.
241: if (tableModel.getRowCount() == 0) {
242: delete.setEnabled(false);
243: } else {
244: delete.setEnabled(true);
245: }
246: }
247:
248: /**
249: * Add a new argument row to the table.
250: */
251: protected void addArgument() {
252: // If a table cell is being edited, we should accept the current value
253: // and stop the editing before adding a new row.
254: stopTableEditing();
255:
256: tableModel.addNewRow();
257: tableModel.fireTableDataChanged();
258:
259: // Enable DELETE (which may already be enabled, but it won't hurt)
260: delete.setEnabled(true);
261:
262: // Highlight (select) the appropriate row.
263: int rowToSelect = tableModel.getRowCount() - 1;
264: table.setRowSelectionInterval(rowToSelect, rowToSelect);
265: }
266:
267: /**
268: * Stop any editing that is currently being done on the table. This will
269: * save any changes that have already been made.
270: */
271: protected void stopTableEditing() {
272: if (table.isEditing()) {
273: TableCellEditor cellEditor = table.getCellEditor(table
274: .getEditingRow(), table.getEditingColumn());
275: cellEditor.stopCellEditing();
276: }
277: }
278:
279: /**
280: * Remove the currently selected argument from the table.
281: */
282: protected void deleteArgument() {
283: // If a table cell is being edited, we must cancel the editing before
284: // deleting the row
285: if (table.isEditing()) {
286: TableCellEditor cellEditor = table.getCellEditor(table
287: .getEditingRow(), table.getEditingColumn());
288: cellEditor.cancelCellEditing();
289: }
290:
291: int rowSelected = table.getSelectedRow();
292:
293: if (rowSelected >= 0) {
294:
295: // removeProperty(tableModel.getValueAt (
296: // table.getSelectedRow(),0).toString());
297: tableModel.removeRow(rowSelected);
298: tableModel.fireTableDataChanged();
299:
300: // Disable DELETE if there are no rows in the table to delete.
301: if (tableModel.getRowCount() == 0) {
302: delete.setEnabled(false);
303: } else {
304: // Table still contains one or more rows, so highlight (select)
305: // the appropriate one.
306: int rowToSelect = rowSelected;
307:
308: if (rowSelected >= tableModel.getRowCount()) {
309: rowToSelect = rowSelected - 1;
310: }
311:
312: table.setRowSelectionInterval(rowToSelect, rowToSelect);
313: }
314: }
315: }
316: }
|