001: /*
002: * soapUI, copyright (C) 2004-2007 eviware.com
003: *
004: * soapUI is free software; you can redistribute it and/or modify it under the
005: * terms of version 2.1 of the GNU Lesser General Public License as published by
006: * the Free Software Foundation.
007: *
008: * soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009: * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
010: * See the GNU Lesser General Public License for more details at gnu.org.
011: */
012:
013: package com.eviware.soapui.impl.wsdl.panels.loadtest;
014:
015: import java.awt.BorderLayout;
016: import java.awt.Component;
017: import java.awt.event.ActionEvent;
018: import java.awt.event.ItemEvent;
019: import java.awt.event.ItemListener;
020: import java.awt.event.MouseAdapter;
021: import java.awt.event.MouseEvent;
022: import java.text.SimpleDateFormat;
023: import java.util.ArrayList;
024: import java.util.Date;
025: import java.util.List;
026:
027: import javax.swing.AbstractAction;
028: import javax.swing.Action;
029: import javax.swing.BorderFactory;
030: import javax.swing.Icon;
031: import javax.swing.ImageIcon;
032: import javax.swing.JButton;
033: import javax.swing.JComboBox;
034: import javax.swing.JComponent;
035: import javax.swing.JLabel;
036: import javax.swing.JPanel;
037: import javax.swing.JPopupMenu;
038: import javax.swing.JScrollPane;
039: import javax.swing.JTable;
040: import javax.swing.event.ListDataEvent;
041: import javax.swing.event.ListDataListener;
042: import javax.swing.event.TableModelEvent;
043: import javax.swing.event.TableModelListener;
044: import javax.swing.table.AbstractTableModel;
045: import javax.swing.table.DefaultTableCellRenderer;
046: import javax.swing.table.TableColumnModel;
047:
048: import org.jdesktop.swingx.JXTable;
049: import org.jdesktop.swingx.decorator.Filter;
050: import org.jdesktop.swingx.decorator.FilterPipeline;
051: import org.jdesktop.swingx.decorator.PatternFilter;
052: import org.jdesktop.swingx.decorator.SortOrder;
053:
054: import com.eviware.soapui.impl.wsdl.loadtest.LoadTestAssertion;
055: import com.eviware.soapui.impl.wsdl.loadtest.data.actions.ExportLoadTestLogAction;
056: import com.eviware.soapui.impl.wsdl.loadtest.log.LoadTestLog;
057: import com.eviware.soapui.impl.wsdl.loadtest.log.LoadTestLogEntry;
058: import com.eviware.soapui.model.testsuite.TestStep;
059: import com.eviware.soapui.support.UISupport;
060: import com.eviware.soapui.support.action.swing.ActionList;
061: import com.eviware.soapui.support.action.swing.ActionSupport;
062: import com.eviware.soapui.support.components.JXToolBar;
063: import com.jgoodies.forms.builder.ButtonBarBuilder;
064:
065: /**
066: * Compound component for showing a LoadTestLog
067: *
068: * @author Ole.Matzura
069: */
070:
071: public class JLoadTestLogTable extends JPanel {
072: private final LoadTestLog loadTestLog;
073: private JXTable logTable;
074: private PatternFilter stepFilter;
075: private PatternFilter typeFilter;
076: private JComboBox typesFilterComboBox;
077: private JComboBox stepsFilterComboBox;
078: private JButton clearErrorsButton;
079: private JLabel rowCountLabel;
080: @SuppressWarnings("unused")
081: private JPopupMenu popup;
082: private LoadTestLogTableModel logTableModel;
083: private JButton exportButton;
084: private LogTableModelListener logTableModelListener;
085:
086: public JLoadTestLogTable(LoadTestLog log) {
087: super (new BorderLayout());
088:
089: loadTestLog = log;
090:
091: logTableModel = new LoadTestLogTableModel();
092: logTable = new JXTable(logTableModel);
093: logTable.setHorizontalScrollEnabled(true);
094: logTable.addMouseListener(new LoadTestLogTableMouseListener());
095:
096: TableColumnModel columnModel = logTable.getColumnModel();
097: columnModel.getColumn(0).setMaxWidth(5);
098: columnModel.getColumn(0).setCellRenderer(
099: new IconTableCellRenderer());
100:
101: columnModel.getColumn(1).setPreferredWidth(120);
102: columnModel.getColumn(1).setCellRenderer(
103: new TimestampTableCellRenderer());
104:
105: columnModel.getColumn(2).setPreferredWidth(110);
106: columnModel.getColumn(3).setPreferredWidth(110);
107: columnModel.getColumn(4).setPreferredWidth(250);
108:
109: typeFilter = new PatternFilter(".*", 0, 2);
110: typeFilter.setAcceptNull(true);
111: stepFilter = new PatternFilter(".*", 0, 3);
112: stepFilter.setAcceptNull(true);
113:
114: Filter[] filters = new Filter[] { typeFilter, // regex, matchflags, column
115: stepFilter // regex, matchflags, column
116: };
117:
118: FilterPipeline pipeline = new FilterPipeline(filters);
119: logTable.setFilters(pipeline);
120:
121: JScrollPane scrollPane = new JScrollPane(logTable);
122: add(scrollPane, BorderLayout.CENTER);
123: add(buildToolbar(), BorderLayout.NORTH);
124: add(buildStatus(), BorderLayout.SOUTH);
125:
126: logTableModelListener = new LogTableModelListener();
127: logTable.getModel()
128: .addTableModelListener(logTableModelListener);
129:
130: logTable.setSortOrder(1, SortOrder.ASCENDING);
131: }
132:
133: public void addNotify() {
134: super .addNotify();
135: if (logTableModelListener != null)
136: logTableModel.addTableModelListener(logTableModelListener);
137:
138: loadTestLog.addListDataListener(logTableModel);
139: }
140:
141: public void removeNotify() {
142: super .removeNotify();
143: logTableModel.removeTableModelListener(logTableModelListener);
144: loadTestLog.removeListDataListener(logTableModel);
145: }
146:
147: private JComponent buildStatus() {
148: ButtonBarBuilder builder = new ButtonBarBuilder();
149: rowCountLabel = new JLabel("0 entries");
150: builder.addFixed(rowCountLabel);
151: builder.addGlue();
152: builder.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
153: return builder.getPanel();
154: }
155:
156: protected void updateRowCountLabel() {
157: int c = logTableModel.getRowCount();
158: rowCountLabel.setText(c == 1 ? "1 entry" : c + " entries");
159: }
160:
161: private JComponent buildToolbar() {
162: JXToolBar toolbar = UISupport.createToolbar();
163:
164: clearErrorsButton = UISupport
165: .createToolbarButton(new ClearErrorsAction());
166: exportButton = UISupport
167: .createToolbarButton(new ExportLoadTestLogAction(
168: loadTestLog));
169:
170: toolbar.add(clearErrorsButton);
171: toolbar.add(exportButton);
172: toolbar.addGlue();
173:
174: List<Object> steps = new ArrayList<Object>();
175: steps.add("- All -");
176: steps.add("Message");
177: for (LoadTestAssertion assertion : loadTestLog.getLoadTest()
178: .getAssertionList()) {
179: steps.add(assertion.getName());
180: }
181:
182: toolbar.add(new JLabel("Show Types:"));
183: toolbar.addSeparator();
184: typesFilterComboBox = new JComboBox(steps.toArray());
185: typesFilterComboBox.addItemListener(new ItemListener() {
186:
187: public void itemStateChanged(ItemEvent e) {
188: int ix = typesFilterComboBox.getSelectedIndex();
189: if (ix == -1)
190: return;
191:
192: typeFilter.setAcceptNull(ix == 0);
193:
194: if (ix == 0)
195: typeFilter.setPattern(".*", 0);
196: else
197: typeFilter.setPattern(typesFilterComboBox
198: .getSelectedItem().toString(), 0);
199:
200: updateRowCountLabel();
201: }
202: });
203:
204: toolbar.add(typesFilterComboBox);
205: toolbar.addSeparator();
206:
207: List<Object> types = new ArrayList<Object>();
208: types.add("- All -");
209: for (TestStep testStep : loadTestLog.getLoadTest()
210: .getTestCase().getTestStepList()) {
211: types.add(testStep.getName());
212: }
213:
214: toolbar.addFixed(new JLabel("Show Steps:"));
215: toolbar.addSeparator();
216: stepsFilterComboBox = new JComboBox(types.toArray());
217: stepsFilterComboBox.addItemListener(new ItemListener() {
218:
219: public void itemStateChanged(ItemEvent e) {
220: int ix = stepsFilterComboBox.getSelectedIndex();
221: if (ix == -1)
222: return;
223:
224: stepFilter.setAcceptNull(ix == 0);
225:
226: if (ix == 0)
227: stepFilter.setPattern(".*", 0);
228: else
229: stepFilter.setPattern(stepsFilterComboBox
230: .getSelectedItem().toString(), 0);
231:
232: updateRowCountLabel();
233: }
234: });
235:
236: toolbar.addFixed(stepsFilterComboBox);
237: toolbar.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0));
238:
239: return toolbar; //builder.getPanel();
240: }
241:
242: private final class LogTableModelListener implements
243: TableModelListener {
244: public void tableChanged(TableModelEvent e) {
245: updateRowCountLabel();
246: }
247: }
248:
249: private class SelectStepFilterAction extends AbstractAction {
250: private final String filter;
251:
252: public SelectStepFilterAction(String name, String filter) {
253: super (name);
254: this .filter = filter;
255: }
256:
257: public void actionPerformed(ActionEvent e) {
258: stepFilter.setPattern(filter, 0);
259: }
260: }
261:
262: private class SelectTypeFilterAction extends AbstractAction {
263: private final String filter;
264:
265: public SelectTypeFilterAction(String name, String filter) {
266: super (name);
267: this .filter = filter;
268: }
269:
270: public void actionPerformed(ActionEvent e) {
271: typeFilter.setPattern(filter, 0);
272: }
273: }
274:
275: private class LoadTestLogTableModel extends AbstractTableModel
276: implements ListDataListener {
277: public LoadTestLogTableModel() {
278: }
279:
280: public int getRowCount() {
281: return loadTestLog.getSize();
282: }
283:
284: public int getColumnCount() {
285: return 5;
286: }
287:
288: public Class<?> getColumnClass(int columnIndex) {
289: switch (columnIndex) {
290: case 0:
291: return ImageIcon.class;
292: case 1:
293: return Date.class;
294: default:
295: return String.class;
296: }
297: }
298:
299: public String getColumnName(int column) {
300: switch (column) {
301: case 0:
302: return " ";
303: case 1:
304: return "time";
305: case 2:
306: return "type";
307: case 3:
308: return "step";
309: case 4:
310: return "message";
311: }
312:
313: return null;
314: }
315:
316: public Object getValueAt(int rowIndex, int columnIndex) {
317: if (rowIndex == -1)
318: return null;
319:
320: LoadTestLogEntry entry = (LoadTestLogEntry) loadTestLog
321: .getElementAt(rowIndex);
322:
323: switch (columnIndex) {
324: case 0:
325: return entry.getIcon();
326: case 1:
327: return entry.getTimeStamp();
328: case 2:
329: return entry.getType();
330: case 3:
331: return entry.getTargetStep() == null ? entry.isError() ? "- Total - "
332: : null
333: : entry.getTargetStep().getName();
334: case 4:
335: return entry.getMessage();
336: }
337:
338: return null;
339: }
340:
341: public void intervalAdded(ListDataEvent e) {
342: fireTableRowsInserted(e.getIndex0(), e.getIndex1());
343: }
344:
345: public void intervalRemoved(ListDataEvent e) {
346: fireTableRowsDeleted(e.getIndex0(), e.getIndex1());
347: }
348:
349: public void contentsChanged(ListDataEvent e) {
350: fireTableDataChanged();
351: }
352: }
353:
354: private static final class IconTableCellRenderer extends
355: DefaultTableCellRenderer {
356: public Component getTableCellRendererComponent(JTable table,
357: Object value, boolean isSelected, boolean hasFocus,
358: int row, int column) {
359: if (value != null)
360: setIcon((Icon) value);
361:
362: if (isSelected) {
363: setBackground(table.getSelectionBackground());
364: setForeground(table.getSelectionForeground());
365: } else {
366: setBackground(table.getBackground());
367: setForeground(table.getForeground());
368: }
369:
370: return this ;
371: }
372: }
373:
374: private static final class TimestampTableCellRenderer extends
375: DefaultTableCellRenderer {
376: private SimpleDateFormat sdf;
377:
378: private TimestampTableCellRenderer() {
379: sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
380: }
381:
382: public Component getTableCellRendererComponent(JTable table,
383: Object value, boolean isSelected, boolean hasFocus,
384: int row, int column) {
385: if (value != null)
386: setText(sdf.format(new Date((Long) value)));
387:
388: if (isSelected) {
389: setBackground(table.getSelectionBackground());
390: setForeground(table.getSelectionForeground());
391: } else {
392: setBackground(table.getBackground());
393: setForeground(table.getForeground());
394: }
395:
396: return this ;
397: }
398: }
399:
400: public class ClearErrorsAction extends AbstractAction {
401: public ClearErrorsAction() {
402: putValue(Action.SMALL_ICON, UISupport
403: .createImageIcon("/clear_errors.gif"));
404: putValue(Action.SHORT_DESCRIPTION,
405: "Removes all errors from the LoadTest log");
406: }
407:
408: public void actionPerformed(ActionEvent e) {
409: loadTestLog.clearErrors();
410: }
411: }
412:
413: private final class LoadTestLogTableMouseListener extends
414: MouseAdapter {
415: public void mouseClicked(MouseEvent e) {
416: if (e.getClickCount() > 1) {
417: int selectedRow = logTable.getSelectedRow();
418: if (selectedRow < 0)
419: return;
420:
421: int row = logTable.convertRowIndexToModel(selectedRow);
422: if (row < 0)
423: return;
424:
425: LoadTestLogEntry entry = (LoadTestLogEntry) loadTestLog
426: .getElementAt(row);
427: ActionList actions = entry.getActions();
428: if (actions != null)
429: actions.performDefaultAction(new ActionEvent(
430: logTable, 0, null));
431: }
432: }
433:
434: public void mousePressed(MouseEvent e) {
435: if (e.isPopupTrigger()) {
436: showPopup(e);
437: }
438: }
439:
440: public void mouseReleased(MouseEvent e) {
441: if (e.isPopupTrigger()) {
442: showPopup(e);
443: }
444: }
445: }
446:
447: public void showPopup(MouseEvent e) {
448: int selectedRow = logTable.rowAtPoint(e.getPoint());
449: if (selectedRow == -1)
450: return;
451:
452: if (logTable.getSelectedRow() != selectedRow) {
453: logTable.getSelectionModel().setSelectionInterval(
454: selectedRow, selectedRow);
455: }
456:
457: int row = logTable.convertRowIndexToModel(selectedRow);
458: if (row < 0)
459: return;
460:
461: LoadTestLogEntry entry = (LoadTestLogEntry) loadTestLog
462: .getElementAt(row);
463: ActionList actions = entry.getActions();
464:
465: if (actions == null || actions.getActionCount() == 0)
466: return;
467:
468: JPopupMenu popup = ActionSupport.buildPopup(actions);
469: popup.setInvoker(logTable);
470:
471: popup.setLocation(
472: (int) (logTable.getLocationOnScreen().getX() + e
473: .getPoint().getX()), (int) (logTable
474: .getLocationOnScreen().getY() + e.getPoint()
475: .getY()));
476: popup.setVisible(true);
477: }
478: }
|