1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.panels.testcase;
14
15 import java.awt.BorderLayout;
16 import java.awt.Color;
17 import java.awt.Component;
18 import java.awt.Font;
19 import java.awt.event.ActionEvent;
20 import java.awt.event.MouseAdapter;
21 import java.awt.event.MouseEvent;
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.PrintWriter;
25 import java.util.HashSet;
26 import java.util.Set;
27
28 import javax.swing.AbstractAction;
29 import javax.swing.Action;
30 import javax.swing.BorderFactory;
31 import javax.swing.JLabel;
32 import javax.swing.JList;
33 import javax.swing.JPanel;
34 import javax.swing.JPopupMenu;
35 import javax.swing.JScrollPane;
36 import javax.swing.ListCellRenderer;
37
38 import com.eviware.soapui.impl.wsdl.testcase.TestCaseLogItem;
39 import com.eviware.soapui.impl.wsdl.testcase.TestCaseLogModel;
40 import com.eviware.soapui.model.settings.Settings;
41 import com.eviware.soapui.model.testsuite.TestStepResult;
42 import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
43 import com.eviware.soapui.support.StringUtils;
44 import com.eviware.soapui.support.UISupport;
45 import com.eviware.soapui.support.action.swing.ActionList;
46 import com.eviware.soapui.support.action.swing.ActionSupport;
47 import com.eviware.soapui.support.components.JHyperlinkLabel;
48 import com.eviware.soapui.support.components.JXToolBar;
49 import com.eviware.x.form.XFormDialog;
50 import com.eviware.x.form.support.ADialogBuilder;
51 import com.eviware.x.form.support.AField;
52 import com.eviware.x.form.support.AForm;
53 import com.eviware.x.form.support.AField.AFieldType;
54
55 /***
56 * Panel for displaying TestStepResults
57 *
58 * @author Ole.Matzura
59 */
60
61 public class JTestRunLog extends JPanel implements TestRunLog
62 {
63 private TestCaseLogModel logListModel;
64 private JList testLogList;
65 private boolean errorsOnly = false;
66 private final Settings settings;
67 private Set<String> boldTexts = new HashSet<String>();
68 private boolean follow = true;
69 protected int selectedIndex;
70 private XFormDialog optionsDialog;
71
72 public JTestRunLog( Settings settings )
73 {
74 super( new BorderLayout() );
75 this.settings = settings;
76
77 errorsOnly = settings.getBoolean( OptionsForm.class.getName() + "@errors_only" );
78
79 buildUI();
80 }
81
82 private void buildUI()
83 {
84 logListModel = new TestCaseLogModel();
85 logListModel.setMaxSize( ( int )settings.getLong( OptionsForm.class.getName() + "@max_rows", 1000 ) );
86
87 testLogList = new JList( logListModel );
88 testLogList.setCellRenderer( new TestLogCellRenderer() );
89 testLogList.setPrototypeCellValue( "Testing 123" );
90 testLogList.setFixedCellWidth( -1 );
91 testLogList.addMouseListener( new LogListMouseListener() );
92
93 JScrollPane scrollPane = new JScrollPane( testLogList );
94 add( scrollPane, BorderLayout.CENTER );
95 add( buildToolbar(), BorderLayout.NORTH );
96 }
97
98 private Component buildToolbar()
99 {
100 JXToolBar toolbar = UISupport.createSmallToolbar();
101
102 addToolbarButtons( toolbar );
103
104 return toolbar;
105 }
106
107 protected JList getTestLogList()
108 {
109 return testLogList;
110 }
111
112 public boolean isErrorsOnly()
113 {
114 return errorsOnly;
115 }
116
117 public boolean isFollow()
118 {
119 return follow;
120 }
121
122 protected void addToolbarButtons( JXToolBar toolbar )
123 {
124 toolbar.addFixed( UISupport.createToolbarButton( new ClearLogAction() ) );
125 toolbar.addFixed( UISupport.createToolbarButton( new SetLogOptionsAction() ) );
126 toolbar.addFixed( UISupport.createToolbarButton( new ExportLogAction() ) );
127 }
128
129 private final class TestLogCellRenderer extends JLabel implements ListCellRenderer
130 {
131 private Font boldFont;
132 private Font normalFont;
133 private JHyperlinkLabel hyperlinkLabel = new JHyperlinkLabel( "" );
134
135 public TestLogCellRenderer()
136 {
137 setOpaque( true );
138 setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
139 setIcon( null );
140 boldFont = getFont().deriveFont( Font.BOLD );
141 normalFont = getFont();
142
143 hyperlinkLabel.setOpaque( true );
144 hyperlinkLabel.setForeground( Color.BLUE.darker().darker().darker() );
145 hyperlinkLabel.setUnderlineColor( Color.GRAY );
146 hyperlinkLabel.setBorder( BorderFactory.createEmptyBorder( 0, 4, 3, 3 ) );
147 }
148
149 public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected,
150 boolean cellHasFocus )
151 {
152 if( isSelected )
153 {
154 setBackground( list.getSelectionBackground() );
155 setForeground( list.getSelectionForeground() );
156 }
157 else
158 {
159 setBackground( list.getBackground() );
160 setForeground( list.getForeground() );
161 }
162
163 if( value instanceof String )
164 {
165 setText( value.toString() );
166 }
167 else if( value instanceof TestCaseLogItem )
168 {
169 TestCaseLogItem logItem = ( TestCaseLogItem )value;
170 String msg = logItem.getMsg();
171 setText( msg == null ? "" : msg );
172 }
173
174 TestStepResult result = logListModel.getResultAt( index );
175 if( result != null && !getText().startsWith( " ->" ) )
176 {
177 hyperlinkLabel.setText( getText() );
178 hyperlinkLabel.setBackground( getBackground() );
179 hyperlinkLabel.setEnabled( list.isEnabled() );
180
181 if( result.getStatus() == TestStepStatus.OK )
182 {
183 hyperlinkLabel.setIcon( UISupport.createImageIcon( "/valid_assertion.gif" ) );
184 }
185 else if( result.getStatus() == TestStepStatus.FAILED )
186 {
187 hyperlinkLabel.setIcon( UISupport.createImageIcon( "/failed_assertion.gif" ) );
188 }
189 else
190 {
191 hyperlinkLabel.setIcon( UISupport.createImageIcon( "/unknown_assertion.gif" ) );
192 }
193
194 return hyperlinkLabel;
195 }
196
197 setEnabled( list.isEnabled() );
198
199 if( boldTexts.contains( getText() ) )
200 {
201 setFont( boldFont );
202 }
203 else
204 {
205 setFont( normalFont );
206 }
207
208 return this;
209 }
210 }
211
212 /***
213 * Mouse Listener for triggering default action and showing popup for log
214 * list items
215 *
216 * @author Ole.Matzura
217 */
218
219 private final class LogListMouseListener extends MouseAdapter
220 {
221 public void mouseClicked( MouseEvent e )
222 {
223 int index = testLogList.getSelectedIndex();
224 if( index != -1 && ( index == selectedIndex || e.getClickCount() > 1 ) )
225 {
226 TestStepResult result = logListModel.getResultAt( index );
227 if( result != null && result.getActions() != null )
228 result.getActions().performDefaultAction( new ActionEvent( this, 0, null ) );
229 }
230
231 selectedIndex = index;
232 }
233
234 public void mousePressed( MouseEvent e )
235 {
236 if( e.isPopupTrigger() )
237 showPopup( e );
238 }
239
240 public void mouseReleased( MouseEvent e )
241 {
242 if( e.isPopupTrigger() )
243 showPopup( e );
244 }
245
246 public void showPopup( MouseEvent e )
247 {
248 int row = testLogList.locationToIndex( e.getPoint() );
249 if( row == -1 )
250 return;
251
252 if( testLogList.getSelectedIndex() != row )
253 {
254 testLogList.setSelectedIndex( row );
255 }
256
257 TestStepResult result = logListModel.getResultAt( row );
258 if( result == null )
259 return;
260
261 ActionList actions = result.getActions();
262
263 if( actions == null || actions.getActionCount() == 0 )
264 return;
265
266 JPopupMenu popup = ActionSupport.buildPopup( actions );
267 UISupport.showPopup( popup, testLogList, e.getPoint() );
268 }
269 }
270
271
272
273
274
275
276 public synchronized void clear()
277 {
278 logListModel.clear();
279 boldTexts.clear();
280 }
281
282
283
284
285
286
287
288
289 public synchronized void addText( String string )
290 {
291 logListModel.addText( string );
292 if( follow )
293 testLogList.ensureIndexIsVisible( logListModel.getSize() - 1 );
294 }
295
296
297
298
299
300
301
302
303 public synchronized void addTestStepResult( TestStepResult stepResult )
304 {
305 if( errorsOnly && stepResult.getStatus() != TestStepResult.TestStepStatus.FAILED )
306 return;
307
308 logListModel.addTestStepResult( stepResult );
309 if( follow )
310 {
311 try
312 {
313 testLogList.ensureIndexIsVisible( logListModel.getSize() - 1 );
314 }
315 catch( RuntimeException e )
316 {
317 }
318 }
319 }
320
321 public TestCaseLogModel getLogListModel()
322 {
323 return logListModel;
324 }
325
326 public void setLogListModel( TestCaseLogModel logListModel )
327 {
328 this.logListModel = logListModel;
329 testLogList.setModel( logListModel );
330 }
331
332 private class SetLogOptionsAction extends AbstractAction
333 {
334 public SetLogOptionsAction()
335 {
336 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/options.gif" ) );
337 putValue( Action.SHORT_DESCRIPTION, "Sets TestCase Log Options" );
338 }
339
340 public void actionPerformed( ActionEvent e )
341 {
342 if( optionsDialog == null )
343 optionsDialog = ADialogBuilder.buildDialog( OptionsForm.class );
344
345 optionsDialog.setIntValue( OptionsForm.MAXROWS, ( int )settings.getLong( OptionsForm.class.getName()
346 + "@max_rows", 1000 ) );
347 optionsDialog.setBooleanValue( OptionsForm.ERRORSONLY, settings.getBoolean( OptionsForm.class.getName()
348 + "@errors_only" ) );
349 optionsDialog.setBooleanValue( OptionsForm.FOLLOW, follow );
350
351 if( optionsDialog.show() )
352 {
353 int maxRows = optionsDialog.getIntValue( OptionsForm.MAXROWS, 1000 );
354 logListModel.setMaxSize( maxRows );
355 settings.setLong( OptionsForm.class.getName() + "@max_rows", maxRows );
356 errorsOnly = optionsDialog.getBooleanValue( OptionsForm.ERRORSONLY );
357 settings.setBoolean( OptionsForm.class.getName() + "@errors_only", errorsOnly );
358
359 follow = optionsDialog.getBooleanValue( OptionsForm.FOLLOW );
360 }
361 }
362 }
363
364 @AForm( name = "Log Options", description = "Set options for the run log below" )
365 private static interface OptionsForm
366 {
367 @AField( name = "Max Rows", description = "Sets the maximum number of rows to keep in the log", type = AFieldType.INT )
368 public static final String MAXROWS = "Max Rows";
369
370 @AField( name = "Errors Only", description = "Logs only TestStep errors in the log", type = AFieldType.BOOLEAN )
371 public static final String ERRORSONLY = "Errors Only";
372
373 @AField( name = "Follow", description = "Follow log content", type = AFieldType.BOOLEAN )
374 public static final String FOLLOW = "Follow";
375 }
376
377 private class ClearLogAction extends AbstractAction
378 {
379 public ClearLogAction()
380 {
381 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clear_loadtest.gif" ) );
382 putValue( Action.SHORT_DESCRIPTION, "Clears the log" );
383 }
384
385 public void actionPerformed( ActionEvent e )
386 {
387 logListModel.clear();
388 }
389 }
390
391 private class ExportLogAction extends AbstractAction
392 {
393 public ExportLogAction()
394 {
395 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/export.gif" ) );
396 putValue( Action.SHORT_DESCRIPTION, "Exports this log to a file" );
397 }
398
399 public void actionPerformed( ActionEvent e )
400 {
401 File file = UISupport.getFileDialogs().saveAs( this, "Save Log" );
402 if( file != null )
403 {
404 try
405 {
406 PrintWriter out = new PrintWriter( file );
407 printLog( out );
408
409 out.close();
410 }
411 catch( FileNotFoundException e1 )
412 {
413 UISupport.showErrorMessage( e1 );
414 }
415 }
416 }
417 }
418
419 public void setStepIndex( int i )
420 {
421 logListModel.setStepIndex( i );
422 }
423
424 public synchronized void addBoldText( String string )
425 {
426 boldTexts.add( string );
427 addText( string );
428 }
429
430 public void release()
431 {
432 if( optionsDialog != null )
433 {
434 optionsDialog.release();
435 optionsDialog = null;
436 }
437 }
438
439 public void printLog( PrintWriter out )
440 {
441 for( int c = 0; c < logListModel.getSize(); c++ )
442 {
443 Object value = logListModel.getElementAt( c );
444 if( value instanceof String )
445 {
446 out.println( value.toString() );
447 }
448 else if( value instanceof TestCaseLogItem )
449 {
450 TestCaseLogItem logItem = ( TestCaseLogItem )value;
451 String msg = logItem.getMsg();
452 if( StringUtils.hasContent( msg ) )
453 out.println( msg );
454 }
455 }
456 }
457 }