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.config.gui;
020:
021: import java.awt.BorderLayout;
022: import java.awt.Color;
023: import java.awt.Component;
024: import java.awt.FlowLayout;
025: import java.awt.event.ActionEvent;
026: import java.awt.event.ActionListener;
027: import java.util.Collection;
028: import java.util.Iterator;
029:
030: import javax.swing.BorderFactory;
031: import javax.swing.Box;
032: import javax.swing.JButton;
033: import javax.swing.JLabel;
034: import javax.swing.JPanel;
035: import javax.swing.JTable;
036: import javax.swing.ListSelectionModel;
037: import javax.swing.table.TableCellEditor;
038:
039: import org.apache.jmeter.config.Argument;
040: import org.apache.jmeter.config.Arguments;
041: import org.apache.jmeter.testelement.TestElement;
042: import org.apache.jmeter.testelement.property.PropertyIterator;
043: import org.apache.jmeter.util.JMeterUtils;
044: import org.apache.jorphan.gui.ObjectTableModel;
045: import org.apache.jorphan.reflect.Functor;
046:
047: /**
048: * A GUI panel allowing the user to enter name-value argument pairs. These
049: * arguments (or parameters) are usually used to provide configuration values
050: * for some other component.
051: *
052: */
053: public class ArgumentsPanel extends AbstractConfigGui implements
054: ActionListener {
055:
056: /** The title label for this component. */
057: private JLabel tableLabel;
058:
059: /** The table containing the list of arguments. */
060: private transient JTable table;
061:
062: /** The model for the arguments table. */
063: protected transient ObjectTableModel tableModel;
064:
065: /** A button for adding new arguments to the table. */
066: private JButton add;
067:
068: /** A button for removing arguments from the table. */
069: private JButton delete;
070:
071: /**
072: * Added background support for reporting tool
073: */
074: private Color background;
075:
076: /**
077: * Boolean indicating whether this component is a standalong component or it
078: * is intended to be used as a subpanel for another component.
079: */
080: private boolean standalone = true;
081:
082: /** Command for adding a row to the table. */
083: private static final String ADD = "add"; // $NON-NLS-1$
084:
085: /** Command for removing a row from the table. */
086: private static final String DELETE = "delete"; // $NON-NLS-1$
087:
088: public static final String COLUMN_NAMES_0 = JMeterUtils
089: .getResString("name"); // $NON-NLS-1$
090:
091: public static final String COLUMN_NAMES_1 = JMeterUtils
092: .getResString("value"); // $NON-NLS-1$
093:
094: // NOTUSED private static final String COLUMN_NAMES_2 =
095: // JMeterUtils.getResString("metadata");
096:
097: /**
098: * Create a new ArgumentsPanel as a standalone component.
099: */
100: public ArgumentsPanel() {
101: tableLabel = new JLabel(JMeterUtils
102: .getResString("user_defined_variables")); // $NON-NLS-1$
103: standalone = true;
104: init();
105: }
106:
107: /**
108: * Create a new ArgumentsPanel as an embedded component, using the specified
109: * title.
110: *
111: * @param label
112: * the title for the component.
113: */
114: public ArgumentsPanel(String label) {
115: tableLabel = new JLabel(label);
116: standalone = false;
117: init();
118: }
119:
120: /**
121: * Create a new ArgumentsPanel with a border and color background
122: * @param label text for label
123: * @param bkg background colour
124: */
125: public ArgumentsPanel(String label, Color bkg) {
126: tableLabel = new JLabel(label);
127: this .background = bkg;
128: standalone = false;
129: init();
130: }
131:
132: /**
133: * This is the list of menu categories this gui component will be available
134: * under.
135: *
136: * @return a Collection of Strings, where each element is one of the
137: * constants defined in MenuFactory
138: */
139: public Collection getMenuCategories() {
140: if (standalone) {
141: return super .getMenuCategories();
142: }
143: return null;
144: }
145:
146: public String getLabelResource() {
147: return "user_defined_variables"; // $NON-NLS-1$
148: }
149:
150: /* Implements JMeterGUIComponent.createTestElement() */
151: public TestElement createTestElement() {
152: Arguments args = new Arguments();
153: modifyTestElement(args);
154: return args;
155: }
156:
157: /* Implements JMeterGUIComponent.modifyTestElement(TestElement) */
158: public void modifyTestElement(TestElement args) {
159: stopTableEditing();
160: Iterator modelData = tableModel.iterator();
161: Arguments arguments = null;
162: if (args instanceof Arguments) {
163: arguments = (Arguments) args;
164: arguments.clear();
165: while (modelData.hasNext()) {
166: Argument arg = (Argument) modelData.next();
167: arg.setMetaData("="); // $NON-NLS-1$
168: arguments.addArgument(arg);
169: }
170: }
171: this .configureTestElement(args);
172: }
173:
174: /**
175: * A newly created component can be initialized with the contents of a Test
176: * Element object by calling this method. The component is responsible for
177: * querying the Test Element object for the relevant information to display
178: * in its GUI.
179: *
180: * @param el
181: * the TestElement to configure
182: */
183: public void configure(TestElement el) {
184: super .configure(el);
185: if (el instanceof Arguments) {
186: tableModel.clearData();
187: PropertyIterator iter = ((Arguments) el).iterator();
188: while (iter.hasNext()) {
189: Argument arg = (Argument) iter.next().getObjectValue();
190: tableModel.addRow(arg);
191: }
192: }
193: checkDeleteStatus();
194: }
195:
196: /**
197: * Get the table used to enter arguments.
198: *
199: * @return the table used to enter arguments
200: */
201: protected JTable getTable() {
202: return table;
203: }
204:
205: /**
206: * Get the title label for this component.
207: *
208: * @return the title label displayed with the table
209: */
210: protected JLabel getTableLabel() {
211: return tableLabel;
212: }
213:
214: /**
215: * Get the button used to delete rows from the table.
216: *
217: * @return the button used to delete rows from the table
218: */
219: protected JButton getDeleteButton() {
220: return delete;
221: }
222:
223: /**
224: * Get the button used to add rows to the table.
225: *
226: * @return the button used to add rows to the table
227: */
228: protected JButton getAddButton() {
229: return add;
230: }
231:
232: /**
233: * Enable or disable the delete button depending on whether or not there is
234: * a row to be deleted.
235: */
236: protected void checkDeleteStatus() {
237: // Disable DELETE if there are no rows in the table to delete.
238: if (tableModel.getRowCount() == 0) {
239: delete.setEnabled(false);
240: } else {
241: delete.setEnabled(true);
242: }
243: }
244:
245: public void clearGui() {
246: super .clearGui();
247: clear();
248: }
249:
250: /**
251: * Clear all rows from the table. T.Elanjchezhiyan(chezhiyan@siptech.co.in)
252: */
253: public void clear() {
254: stopTableEditing();
255: tableModel.clearData();
256: }
257:
258: /**
259: * Invoked when an action occurs. This implementation supports the add and
260: * delete buttons.
261: *
262: * @param e
263: * the event that has occurred
264: */
265: public void actionPerformed(ActionEvent e) {
266: String action = e.getActionCommand();
267: if (action.equals(DELETE)) {
268: deleteArgument();
269: } else if (action.equals(ADD)) {
270: addArgument();
271: }
272: }
273:
274: /**
275: * Remove the currently selected argument from the table.
276: */
277: protected void deleteArgument() {
278: // If a table cell is being edited, we must cancel the editing before
279: // deleting the row
280: if (table.isEditing()) {
281: TableCellEditor cellEditor = table.getCellEditor(table
282: .getEditingRow(), table.getEditingColumn());
283: cellEditor.cancelCellEditing();
284: }
285:
286: int rowSelected = table.getSelectedRow();
287: if (rowSelected >= 0) {
288: tableModel.removeRow(rowSelected);
289: tableModel.fireTableDataChanged();
290:
291: // Disable DELETE if there are no rows in the table to delete.
292: if (tableModel.getRowCount() == 0) {
293: delete.setEnabled(false);
294: }
295:
296: // Table still contains one or more rows, so highlight (select)
297: // the appropriate one.
298: else {
299: int rowToSelect = rowSelected;
300:
301: if (rowSelected >= tableModel.getRowCount()) {
302: rowToSelect = rowSelected - 1;
303: }
304:
305: table.setRowSelectionInterval(rowToSelect, rowToSelect);
306: }
307: }
308: }
309:
310: /**
311: * Add a new argument row to the table.
312: */
313: protected void addArgument() {
314: // If a table cell is being edited, we should accept the current value
315: // and stop the editing before adding a new row.
316: stopTableEditing();
317:
318: tableModel.addRow(makeNewArgument());
319:
320: // Enable DELETE (which may already be enabled, but it won't hurt)
321: delete.setEnabled(true);
322:
323: // Highlight (select) the appropriate row.
324: int rowToSelect = tableModel.getRowCount() - 1;
325: table.setRowSelectionInterval(rowToSelect, rowToSelect);
326: }
327:
328: /**
329: * Create a new Argument object.
330: *
331: * @return a new Argument object
332: */
333: protected Object makeNewArgument() {
334: return new Argument("", ""); // $NON-NLS-1$ // $NON-NLS-2$
335: }
336:
337: /**
338: * Stop any editing that is currently being done on the table. This will
339: * save any changes that have already been made.
340: */
341: protected void stopTableEditing() {
342: if (table.isEditing()) {
343: TableCellEditor cellEditor = table.getCellEditor(table
344: .getEditingRow(), table.getEditingColumn());
345: cellEditor.stopCellEditing();
346: }
347: }
348:
349: /**
350: * Initialize the table model used for the arguments table.
351: */
352: protected void initializeTableModel() {
353: tableModel = new ObjectTableModel(new String[] {
354: COLUMN_NAMES_0, COLUMN_NAMES_1 }, Argument.class,
355: new Functor[] { new Functor("getName"), // $NON-NLS-1$
356: new Functor("getValue") }, // $NON-NLS-1$
357: new Functor[] { new Functor("setName"), // $NON-NLS-1$
358: new Functor("setValue") }, // $NON-NLS-1$
359: new Class[] { String.class, String.class });
360: }
361:
362: public static boolean testFunctors() {
363: ArgumentsPanel instance = new ArgumentsPanel();
364: instance.initializeTableModel();
365: return instance.tableModel.checkFunctors(null, instance
366: .getClass());
367: }
368:
369: /**
370: * Resize the table columns to appropriate widths.
371: *
372: * @param _table
373: * the table to resize columns for
374: */
375: protected void sizeColumns(JTable _table) {
376: }
377:
378: /**
379: * Create the main GUI panel which contains the argument table.
380: *
381: * @return the main GUI panel
382: */
383: private Component makeMainPanel() {
384: initializeTableModel();
385: table = new JTable(tableModel);
386: table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
387: if (this .background != null) {
388: table.setBackground(this .background);
389: }
390: return makeScrollPane(table);
391: }
392:
393: /**
394: * Create a panel containing the title label for the table.
395: *
396: * @return a panel containing the title label
397: */
398: protected Component makeLabelPanel() {
399: JPanel labelPanel = new JPanel(
400: new FlowLayout(FlowLayout.CENTER));
401: labelPanel.add(tableLabel);
402: if (this .background != null) {
403: labelPanel.setBackground(this .background);
404: }
405: return labelPanel;
406: }
407:
408: /**
409: * Create a panel containing the add and delete buttons.
410: *
411: * @return a GUI panel containing the buttons
412: */
413: private JPanel makeButtonPanel() {
414: add = new JButton(JMeterUtils.getResString("add")); // $NON-NLS-1$
415: add.setActionCommand(ADD);
416: add.setEnabled(true);
417:
418: delete = new JButton(JMeterUtils.getResString("delete")); // $NON-NLS-1$
419: delete.setActionCommand(DELETE);
420:
421: checkDeleteStatus();
422:
423: JPanel buttonPanel = new JPanel();
424: buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0,
425: 10));
426: if (this .background != null) {
427: buttonPanel.setBackground(this .background);
428: }
429: add.addActionListener(this );
430: delete.addActionListener(this );
431: buttonPanel.add(add);
432: buttonPanel.add(delete);
433: return buttonPanel;
434: }
435:
436: /**
437: * Initialize the components and layout of this component.
438: */
439: private void init() {
440: JPanel p = this ;
441:
442: if (standalone) {
443: setLayout(new BorderLayout(0, 5));
444: setBorder(makeBorder());
445: add(makeTitlePanel(), BorderLayout.NORTH);
446: p = new JPanel();
447: }
448:
449: p.setLayout(new BorderLayout());
450:
451: p.add(makeLabelPanel(), BorderLayout.NORTH);
452: p.add(makeMainPanel(), BorderLayout.CENTER);
453: // Force a minimum table height of 70 pixels
454: p.add(Box.createVerticalStrut(70), BorderLayout.WEST);
455: p.add(makeButtonPanel(), BorderLayout.SOUTH);
456:
457: if (standalone) {
458: add(p, BorderLayout.CENTER);
459: }
460:
461: table.revalidate();
462: sizeColumns(table);
463: }
464: }
|