View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2008 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl.panels.loadtest;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Component;
17  import java.awt.event.ActionEvent;
18  import java.awt.event.ItemEvent;
19  import java.awt.event.ItemListener;
20  import java.awt.event.MouseAdapter;
21  import java.awt.event.MouseEvent;
22  import java.text.SimpleDateFormat;
23  import java.util.ArrayList;
24  import java.util.Date;
25  import java.util.List;
26  
27  import javax.swing.AbstractAction;
28  import javax.swing.Action;
29  import javax.swing.BorderFactory;
30  import javax.swing.Icon;
31  import javax.swing.ImageIcon;
32  import javax.swing.JButton;
33  import javax.swing.JComboBox;
34  import javax.swing.JComponent;
35  import javax.swing.JLabel;
36  import javax.swing.JPanel;
37  import javax.swing.JPopupMenu;
38  import javax.swing.JScrollPane;
39  import javax.swing.JTable;
40  import javax.swing.event.ListDataEvent;
41  import javax.swing.event.ListDataListener;
42  import javax.swing.event.TableModelEvent;
43  import javax.swing.event.TableModelListener;
44  import javax.swing.table.AbstractTableModel;
45  import javax.swing.table.DefaultTableCellRenderer;
46  import javax.swing.table.TableColumnModel;
47  
48  import org.jdesktop.swingx.JXTable;
49  import org.jdesktop.swingx.decorator.Filter;
50  import org.jdesktop.swingx.decorator.FilterPipeline;
51  import org.jdesktop.swingx.decorator.PatternFilter;
52  import org.jdesktop.swingx.decorator.SortOrder;
53  
54  import com.eviware.soapui.impl.wsdl.loadtest.LoadTestAssertion;
55  import com.eviware.soapui.impl.wsdl.loadtest.data.actions.ExportLoadTestLogAction;
56  import com.eviware.soapui.impl.wsdl.loadtest.log.LoadTestLog;
57  import com.eviware.soapui.impl.wsdl.loadtest.log.LoadTestLogEntry;
58  import com.eviware.soapui.model.testsuite.TestStep;
59  import com.eviware.soapui.support.UISupport;
60  import com.eviware.soapui.support.action.swing.ActionList;
61  import com.eviware.soapui.support.action.swing.ActionSupport;
62  import com.eviware.soapui.support.components.JXToolBar;
63  import com.jgoodies.forms.builder.ButtonBarBuilder;
64  
65  /***
66   * Compound component for showing a LoadTestLog
67   * 
68   * @author Ole.Matzura
69   */
70  
71  public class JLoadTestLogTable extends JPanel
72  {
73  	private final LoadTestLog loadTestLog;
74  	private JXTable logTable;
75  	private PatternFilter stepFilter;
76  	private PatternFilter typeFilter;
77  	private JComboBox typesFilterComboBox;
78  	private JComboBox stepsFilterComboBox;
79  	private JButton clearErrorsButton;
80  	private JLabel rowCountLabel;
81  	@SuppressWarnings("unused")
82  	private JPopupMenu popup;
83  	private LoadTestLogTableModel logTableModel;
84  	private JButton exportButton;
85  	private LogTableModelListener logTableModelListener;
86  
87  	public JLoadTestLogTable( LoadTestLog log )
88  	{
89  		super( new BorderLayout() );
90  
91  		loadTestLog = log;
92  		
93  		logTableModel = new LoadTestLogTableModel();
94  		logTable = new JXTable( logTableModel );
95  		logTable.setHorizontalScrollEnabled( true );
96  		logTable.setColumnControlVisible( true );
97  		logTable.addMouseListener( new LoadTestLogTableMouseListener() );
98  		
99  		TableColumnModel columnModel = logTable.getColumnModel();
100 		columnModel.getColumn( 0 ).setMaxWidth( 5 );
101 		columnModel.getColumn( 0 ).setCellRenderer( new IconTableCellRenderer() );
102 		
103 		columnModel.getColumn( 1 ).setPreferredWidth( 120 );
104 		columnModel.getColumn( 1 ).setCellRenderer( new TimestampTableCellRenderer() );
105 		
106 		columnModel.getColumn( 2 ).setPreferredWidth( 110 );
107 		columnModel.getColumn( 3 ).setPreferredWidth( 110 );
108 		columnModel.getColumn( 4 ).setPreferredWidth( 250 );
109 		
110 		typeFilter = new PatternFilter(".*", 0, 2);
111 		typeFilter.setAcceptNull( true );
112 		stepFilter = new PatternFilter(".*", 0, 3);
113 		stepFilter.setAcceptNull( true );
114 
115 		Filter[]   filters = new Filter[] {
116 		      typeFilter,    // regex, matchflags, column
117 		      stepFilter    // regex, matchflags, column
118 		  };
119 		
120 		FilterPipeline pipeline = new FilterPipeline(filters);
121 	 	logTable.setFilters( pipeline );
122 		
123 		JScrollPane scrollPane = new JScrollPane(logTable);
124 		add( scrollPane, BorderLayout.CENTER );
125 		add( buildToolbar(), BorderLayout.NORTH );
126 		add( buildStatus(), BorderLayout.SOUTH );
127 		
128 		logTableModelListener = new LogTableModelListener();
129 		logTable.getModel().addTableModelListener( logTableModelListener );
130 		
131 		logTable.setSortOrder( 1, SortOrder.ASCENDING );
132 	}
133 	
134 	public void addNotify()
135 	{
136 		super.addNotify();
137 		if( logTableModelListener != null )
138 			logTableModel.addTableModelListener( logTableModelListener );
139 		
140 		loadTestLog.addListDataListener( logTableModel );
141 	}
142 	
143 	public void removeNotify()
144 	{
145 		super.removeNotify();
146 		logTableModel.removeTableModelListener( logTableModelListener );
147 		loadTestLog.removeListDataListener( logTableModel );
148 	}
149 	
150 	private JComponent buildStatus()
151 	{
152 		ButtonBarBuilder builder = new ButtonBarBuilder();
153 		rowCountLabel = new JLabel( "0 entries" );
154 		builder.addFixed( rowCountLabel );
155 		builder.addGlue();
156 		builder.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ));
157 		return builder.getPanel();
158 	}
159 
160 	protected void updateRowCountLabel()
161 	{
162 		int c = logTableModel.getRowCount();
163 		rowCountLabel.setText( c == 1 ? "1 entry" : c + " entries" );
164 	}
165 
166 	private JComponent buildToolbar()
167 	{
168 		JXToolBar toolbar = UISupport.createToolbar();
169 		
170 		clearErrorsButton =  UISupport.createToolbarButton( new ClearErrorsAction() );
171       exportButton = UISupport.createToolbarButton( new ExportLoadTestLogAction( loadTestLog, logTable ) );
172       
173       toolbar.add( clearErrorsButton );
174       toolbar.add( exportButton );
175       toolbar.addGlue();
176       
177       List<Object> steps = new ArrayList<Object>();
178 		steps.add( "- All -" );
179 		steps.add( "Message" );
180 		for( LoadTestAssertion assertion : loadTestLog.getLoadTest().getAssertionList() )
181 		{
182 			steps.add( assertion.getName() );
183 		}
184 		
185 		toolbar.add( new JLabel( "Show Types:"));
186 		toolbar.addSeparator();
187 		typesFilterComboBox = new JComboBox( steps.toArray() );
188 		typesFilterComboBox.addItemListener( new ItemListener()  {
189 
190 			public void itemStateChanged(ItemEvent e)
191 			{
192 				int ix = typesFilterComboBox.getSelectedIndex();
193 				if( ix == -1 )
194 					return;
195 				
196 				typeFilter.setAcceptNull( ix == 0 );
197 				
198 				if( ix == 0 )
199 					typeFilter.setPattern( ".*", 0 );
200 				else
201 					typeFilter.setPattern( typesFilterComboBox.getSelectedItem().toString(), 0 );
202 				
203 				updateRowCountLabel();
204 			}} );
205 		
206 		toolbar.add( typesFilterComboBox );
207 		toolbar.addSeparator();
208 		
209 		List<Object> types = new ArrayList<Object>();
210 		types.add( "- All -" );
211 		for( TestStep testStep : loadTestLog.getLoadTest().getTestCase().getTestStepList() )
212 		{
213 			types.add( testStep.getName() );
214 		}
215 		
216 		toolbar.addFixed( new JLabel( "Show Steps:"));
217 		toolbar.addSeparator();
218 		stepsFilterComboBox = new JComboBox( types.toArray() );
219 		stepsFilterComboBox.addItemListener( new ItemListener()  {
220 
221 			public void itemStateChanged(ItemEvent e)
222 			{
223 				int ix = stepsFilterComboBox.getSelectedIndex();
224 				if( ix == -1 )
225 					return;
226 				
227 				stepFilter.setAcceptNull( ix == 0 );
228 				
229 				if( ix == 0 )
230 					stepFilter.setPattern( ".*", 0 );
231 				else
232 					stepFilter.setPattern( stepsFilterComboBox.getSelectedItem().toString(), 0 );
233 				
234 				updateRowCountLabel();
235 			}} );
236 		
237 		toolbar.addFixed( stepsFilterComboBox );
238 //		toolbar.setBorder( BorderFactory.createEmptyBorder( 0, 0, 2, 0 ));
239 		
240 		return toolbar; //builder.getPanel();
241 	}
242 
243 	private final class LogTableModelListener implements TableModelListener
244 	{
245 		public void tableChanged(TableModelEvent e)
246 		{
247 			updateRowCountLabel();
248 		}
249 	}
250 	
251 	/*
252 
253 	private class SelectStepFilterAction extends AbstractAction
254 	{
255 		private final String filter;
256 
257 		public SelectStepFilterAction(String name, String filter)
258 		{
259 			super(name);
260 			this.filter = filter;
261 		}
262 
263 		public void actionPerformed(ActionEvent e)
264 		{
265 			stepFilter.setPattern( filter, 0 );
266 		}
267 	}
268 	
269 	private class SelectTypeFilterAction extends AbstractAction
270 	{
271 		private final String filter;
272 
273 		public SelectTypeFilterAction(String name, String filter)
274 		{
275 			super(name);
276 			this.filter = filter;
277 		}
278 
279 		public void actionPerformed(ActionEvent e)
280 		{
281 			typeFilter.setPattern( filter, 0 );
282 		}
283 	}
284 	*/
285 	
286 	private class LoadTestLogTableModel extends AbstractTableModel implements ListDataListener
287 	{
288 		public LoadTestLogTableModel()
289 		{
290 		}
291 		
292 		public int getRowCount()
293 		{
294 			return loadTestLog.getSize();
295 		}
296 
297 		public int getColumnCount()
298 		{
299 			return 5;
300 		}
301 		
302 		public Class<?> getColumnClass(int columnIndex)
303 		{
304 			switch( columnIndex )
305 			{
306 			case 0 : return ImageIcon.class;
307 			case 1 : return Date.class;
308 			default : return String.class;
309 			}
310 		}
311 
312 		public String getColumnName(int column)
313 		{
314 			switch( column )
315 			{
316 			case 0 : return " ";
317 			case 1 : return "time"; 
318 			case 2 : return "type";
319 			case 3 : return "step";
320 			case 4 : return "message";
321 			}
322 			
323 			return null;
324 		}
325 
326 		public Object getValueAt(int rowIndex, int columnIndex)
327 		{
328 			if( rowIndex == -1 )
329 				return null;
330 			
331 			LoadTestLogEntry entry = (LoadTestLogEntry) loadTestLog.getElementAt( rowIndex );
332 			
333 			switch( columnIndex )
334 			{
335 				case 0 : return entry.getIcon();
336 				case 1 : return entry.getTimeStamp();
337 				case 2 : return entry.getType();
338 				case 3 : return entry.getTargetStepName();
339 				case 4 : return entry.getMessage();
340 			}
341 
342 			return null;
343 		}
344 
345 		public void intervalAdded(ListDataEvent e)
346 		{
347 			fireTableRowsInserted( e.getIndex0(), e.getIndex1() );
348 		}
349 
350 		public void intervalRemoved(ListDataEvent e)
351 		{
352 			fireTableRowsDeleted( e.getIndex0(), e.getIndex1() );
353 		}
354 
355 		public void contentsChanged(ListDataEvent e)
356 		{
357 			fireTableDataChanged();
358 		}}
359 
360 	private static final class IconTableCellRenderer extends DefaultTableCellRenderer
361 	{
362 		public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
363 		{
364 			if( value != null )
365 				setIcon( (Icon) value );
366 			
367 			if (isSelected) 
368          {
369             setBackground(table.getSelectionBackground());
370             setForeground(table.getSelectionForeground());
371          }
372          else 
373          {
374             setBackground(table.getBackground());
375             setForeground(table.getForeground());
376          }
377 			
378 			return this;
379 		}
380 	}
381 	
382 	private static final class TimestampTableCellRenderer extends DefaultTableCellRenderer
383 	{
384 		private SimpleDateFormat sdf;
385 
386       private TimestampTableCellRenderer()
387       {
388          sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
389       }
390 		
391 		public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
392 		{
393 			if( value != null )
394 				setText( sdf.format( new Date( (Long)value ))); 
395 			
396 			if (isSelected) 
397          {
398             setBackground(table.getSelectionBackground());
399             setForeground(table.getSelectionForeground());
400          }
401          else 
402          {
403             setBackground(table.getBackground());
404             setForeground(table.getForeground());
405          }
406 			
407 			return this;
408 		}
409 	}
410 	
411    public class ClearErrorsAction extends AbstractAction
412    {
413 		public ClearErrorsAction()
414       {
415          putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clear_errors.gif"));
416          putValue( Action.SHORT_DESCRIPTION, "Removes all errors from the LoadTest log" );
417       }
418 
419 		public void actionPerformed(ActionEvent e)
420 		{
421 			loadTestLog.clearErrors();
422 		}
423    }
424    
425    private final class LoadTestLogTableMouseListener extends MouseAdapter
426 	{
427    	public void mouseClicked(MouseEvent e)
428 		{
429 			if( e.getClickCount() > 1 )
430 			{
431 				int selectedRow = logTable.getSelectedRow();
432 				if( selectedRow < 0 )
433 					return;
434 				
435 				int row = logTable.convertRowIndexToModel( selectedRow );
436 				if( row < 0 )
437 					return;
438 				
439 				LoadTestLogEntry entry = (LoadTestLogEntry) loadTestLog.getElementAt( row );
440 				ActionList actions = entry.getActions();
441 				if( actions != null )
442 					actions.performDefaultAction( new ActionEvent( logTable, 0, null ));
443 			}
444 		}
445    	
446 		public void mousePressed(MouseEvent e)
447 		{
448 			if( e.isPopupTrigger() )
449 			{
450 				showPopup( e );
451 			}
452 		}
453 
454 		public void mouseReleased(MouseEvent e)
455 		{
456 			if( e.isPopupTrigger() )
457 			{
458 				showPopup( e );
459 			}
460 		}
461 	}
462    
463    public void showPopup(MouseEvent e)
464 	{
465 		int selectedRow = logTable.rowAtPoint( e.getPoint() );
466 		if( selectedRow == -1 )
467 			return;
468 		
469 		if( logTable.getSelectedRow() != selectedRow )
470 		{
471 			logTable.getSelectionModel().setSelectionInterval( selectedRow, selectedRow );
472 		}
473 		
474 		int row = logTable.convertRowIndexToModel( selectedRow );
475 		if( row < 0 )
476 			return;
477 		
478 		LoadTestLogEntry entry = (LoadTestLogEntry) loadTestLog.getElementAt( row );
479 		ActionList actions = entry.getActions();
480 		
481 		if( actions == null || actions.getActionCount() == 0 )
482 			return;
483 		
484 		JPopupMenu popup = ActionSupport.buildPopup( actions );
485 		popup.setInvoker( logTable );
486 		
487 		popup.setLocation( (int)(logTable.getLocationOnScreen().getX() + e.getPoint().getX()), 
488 				(int)(logTable.getLocationOnScreen().getY() + e.getPoint().getY()));
489 		popup.setVisible( true );
490 	}
491 }