View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2009 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.teststeps;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Component;
17  import java.awt.Toolkit;
18  import java.awt.event.ActionEvent;
19  import java.awt.event.KeyAdapter;
20  import java.awt.event.KeyEvent;
21  import java.awt.event.MouseAdapter;
22  import java.awt.event.MouseEvent;
23  import java.beans.PropertyChangeEvent;
24  import java.beans.PropertyChangeListener;
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import javax.swing.AbstractAction;
29  import javax.swing.AbstractListModel;
30  import javax.swing.Action;
31  import javax.swing.JComponent;
32  import javax.swing.JLabel;
33  import javax.swing.JList;
34  import javax.swing.JPanel;
35  import javax.swing.JPopupMenu;
36  import javax.swing.JScrollPane;
37  import javax.swing.ListCellRenderer;
38  import javax.swing.ListSelectionModel;
39  import javax.swing.SwingUtilities;
40  import javax.swing.event.ListSelectionEvent;
41  import javax.swing.event.ListSelectionListener;
42  import javax.swing.event.PopupMenuEvent;
43  import javax.swing.event.PopupMenuListener;
44  
45  import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
46  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
47  import com.eviware.soapui.impl.wsdl.teststeps.actions.AddAssertionAction;
48  import com.eviware.soapui.model.testsuite.Assertable;
49  import com.eviware.soapui.model.testsuite.AssertionError;
50  import com.eviware.soapui.model.testsuite.AssertionsListener;
51  import com.eviware.soapui.model.testsuite.TestAssertion;
52  import com.eviware.soapui.support.UISupport;
53  import com.eviware.soapui.support.action.swing.ActionList;
54  import com.eviware.soapui.support.action.swing.ActionListBuilder;
55  import com.eviware.soapui.support.action.swing.ActionSupport;
56  import com.eviware.soapui.support.components.JXToolBar;
57  
58  /***
59   * Seperate panel for holding/managing assertions
60   * 
61   * @author ole.matzura
62   */
63  
64  public class AssertionsPanel extends JPanel
65  {
66  	private AssertionListModel assertionListModel;
67  	private JList assertionList;
68  	private JPopupMenu assertionListPopup;
69  	private final Assertable assertable;
70  	private AddAssertionAction addAssertionAction;
71  	private ConfigureAssertionAction configureAssertionAction;
72  	private RemoveAssertionAction removeAssertionAction;
73  	private MoveAssertionUpAction moveAssertionUpAction;
74  	private MoveAssertionDownAction moveAssertionDownAction;
75  
76  	public AssertionsPanel( Assertable assertable )
77  	{
78  		super( new BorderLayout() );
79  		this.assertable = assertable;
80  
81  		assertionListModel = new AssertionListModel();
82  		assertionList = new JList( assertionListModel );
83  		assertionList.setToolTipText( "Assertions for this request" );
84  		assertionList.setCellRenderer( new AssertionCellRenderer() );
85  		assertionList.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
86  
87  		assertionListPopup = new JPopupMenu();
88  		addAssertionAction = new AddAssertionAction( assertable );
89  		assertionListPopup.add( addAssertionAction );
90  
91  		assertionListPopup.addPopupMenuListener( new PopupMenuListener()
92  		{
93  
94  			public void popupMenuWillBecomeVisible( PopupMenuEvent e )
95  			{
96  				while( assertionListPopup.getComponentCount() > 1 )
97  					assertionListPopup.remove( 1 );
98  
99  				int ix = assertionList.getSelectedIndex();
100 				if( ix == -1 )
101 				{
102 					assertionListPopup.addSeparator();
103 					assertionListPopup.add( new ShowOnlineHelpAction( HelpUrls.RESPONSE_ASSERTIONS_HELP_URL ) );
104 					return;
105 				}
106 
107 				TestAssertion assertion = assertionListModel.getAssertionAt( ix );
108 				ActionSupport.addActions( ActionListBuilder.buildActions( assertion ), assertionListPopup );
109 			}
110 
111 			public void popupMenuWillBecomeInvisible( PopupMenuEvent e )
112 			{
113 			}
114 
115 			public void popupMenuCanceled( PopupMenuEvent e )
116 			{
117 			}
118 		} );
119 
120 		assertionList.setComponentPopupMenu( assertionListPopup );
121 
122 		assertionList.addMouseListener( new MouseAdapter()
123 		{
124 
125 			public void mouseClicked( MouseEvent e )
126 			{
127 				if( e.getClickCount() < 2 )
128 					return;
129 
130 				int ix = assertionList.getSelectedIndex();
131 				if( ix == -1 )
132 					return;
133 
134 				Object obj = assertionList.getModel().getElementAt( ix );
135 				if( obj instanceof TestAssertion )
136 				{
137 					TestAssertion assertion = ( TestAssertion )obj;
138 					if( assertion.isConfigurable() )
139 						assertion.configure();
140 
141 					return;
142 				}
143 
144 				if( obj instanceof AssertionError )
145 				{
146 					AssertionError error = ( AssertionError )obj;
147 					if( error.getLineNumber() >= 0 )
148 					{
149 						selectError( error );
150 					}
151 					else
152 						Toolkit.getDefaultToolkit().beep();
153 				}
154 				else
155 					Toolkit.getDefaultToolkit().beep();
156 			}
157 		} );
158 
159 		assertionList.addKeyListener( new KeyAdapter()
160 		{
161 			public void keyPressed( KeyEvent e )
162 			{
163 				int ix = assertionList.getSelectedIndex();
164 				if( ix == -1 )
165 					return;
166 
167 				TestAssertion assertion = assertionListModel.getAssertionAt( ix );
168 				if( e.getKeyChar() == KeyEvent.VK_ENTER )
169 				{
170 					if( assertion.isConfigurable() )
171 						assertion.configure();
172 				}
173 				else
174 				{
175 					ActionList actions = ActionListBuilder.buildActions( assertion );
176 					if( actions != null )
177 					{
178 						actions.dispatchKeyEvent( e );
179 					}
180 				}
181 			}
182 		} );
183 
184 		add( new JScrollPane( assertionList ), BorderLayout.CENTER );
185 		add( buildToolbar(), BorderLayout.NORTH );
186 	}
187 
188 	private JComponent buildToolbar()
189 	{
190 		configureAssertionAction = new ConfigureAssertionAction();
191 		removeAssertionAction = new RemoveAssertionAction();
192 		moveAssertionUpAction = new MoveAssertionUpAction();
193 		moveAssertionDownAction = new MoveAssertionDownAction();
194 
195 		JXToolBar toolbar = UISupport.createToolbar();
196 		addToolbarButtons( toolbar );
197 
198 		toolbar.addGlue();
199 		toolbar.add( new ShowOnlineHelpAction( HelpUrls.REQUEST_ASSERTIONS_HELP_URL ) );
200 
201 		assertionList.addListSelectionListener( new ListSelectionListener()
202 		{
203 
204 			public void valueChanged( ListSelectionEvent e )
205 			{
206 				int ix = assertionList.getSelectedIndex();
207 
208 				configureAssertionAction.setEnabled( ix >= 0 );
209 				removeAssertionAction.setEnabled( ix >= 0 );
210 				moveAssertionUpAction.setEnabled( ix >= 0 );
211 				moveAssertionDownAction.setEnabled( ix >= 0 );
212 
213 				if( ix == -1 )
214 					return;
215 				TestAssertion assertion = assertionListModel.getAssertionAt( ix );
216 				configureAssertionAction.setEnabled( assertion != null && assertion.isConfigurable() );
217 			}
218 		} );
219 
220 		return toolbar;
221 	}
222 
223 	protected void addToolbarButtons( JXToolBar toolbar )
224 	{
225 		toolbar.addFixed( UISupport.createToolbarButton( addAssertionAction ) );
226 		toolbar.addFixed( UISupport.createToolbarButton( configureAssertionAction ) );
227 		toolbar.addFixed( UISupport.createToolbarButton( removeAssertionAction ) );
228 		toolbar.addFixed( UISupport.createToolbarButton( moveAssertionUpAction ) );
229 		toolbar.addFixed( UISupport.createToolbarButton( moveAssertionDownAction ) );
230 	}
231 
232 	public void setEnabled( boolean enabled )
233 	{
234 		assertionList.setEnabled( enabled );
235 	}
236 
237 	protected void selectError( AssertionError error )
238 	{
239 	}
240 
241 	private static class AssertionCellRenderer extends JLabel implements ListCellRenderer
242 	{
243 		public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected,
244 				boolean cellHasFocus )
245 		{
246 			setEnabled( list.isEnabled() );
247 
248 			if( value instanceof TestAssertion )
249 			{
250 				TestAssertion assertion = ( TestAssertion )value;
251 				setText( assertion.getLabel() + " - " + assertion.getStatus().toString() );
252 				setIcon( assertion.getIcon() );
253 
254 				if( assertion.isDisabled() && isEnabled() )
255 					setEnabled( false );
256 			}
257 			else if( value instanceof AssertionError )
258 			{
259 				AssertionError assertion = ( AssertionError )value;
260 				setText( " -> " + assertion.toString() );
261 				setIcon( null );
262 			}
263 			else if( value instanceof String )
264 			{
265 				setText( value.toString() );
266 			}
267 
268 			if( isSelected )
269 			{
270 				setBackground( list.getSelectionBackground() );
271 				setForeground( list.getSelectionForeground() );
272 			}
273 			else
274 			{
275 				setBackground( list.getBackground() );
276 				setForeground( list.getForeground() );
277 			}
278 
279 			setFont( list.getFont() );
280 			setOpaque( true );
281 
282 			return this;
283 		}
284 	}
285 
286 	private class AssertionListModel extends AbstractListModel implements PropertyChangeListener, AssertionsListener
287 	{
288 		private List<Object> items = new ArrayList<Object>();
289 
290 		public AssertionListModel()
291 		{
292 			init();
293 		}
294 
295 		public int getSize()
296 		{
297 			return items.size();
298 		}
299 
300 		public Object getElementAt( int index )
301 		{
302 			return index >= items.size() ? null : items.get( index );
303 		}
304 
305 		public TestAssertion getAssertionAt( int index )
306 		{
307 			Object object = items.get( index );
308 			while( !( object instanceof TestAssertion ) && index > 0 )
309 			{
310 				object = items.get( --index );
311 			}
312 
313 			return ( TestAssertion )( ( object instanceof TestAssertion ) ? object : null );
314 		}
315 
316 		public void refresh()
317 		{
318 			synchronized( this )
319 			{
320 				release();
321 				init();
322 				fireContentsChanged( this, 0, getSize() - 1 );
323 			}
324 		}
325 
326 		private void init()
327 		{
328 			assertable.addAssertionsListener( this );
329 
330 			for( int c = 0; c < assertable.getAssertionCount(); c++ )
331 			{
332 				TestAssertion assertion = assertable.getAssertionAt( c );
333 				addAssertion( assertion );
334 			}
335 		}
336 
337 		public void release()
338 		{
339 			items.clear();
340 
341 			for( int c = 0; c < assertable.getAssertionCount(); c++ )
342 			{
343 				TestAssertion assertion = assertable.getAssertionAt( c );
344 				assertion.removePropertyChangeListener( this );
345 			}
346 
347 			assertable.removeAssertionsListener( this );
348 		}
349 
350 		public synchronized void propertyChange( PropertyChangeEvent evt )
351 		{
352 			if( SwingUtilities.isEventDispatchThread() )
353 				refresh();
354 			else
355 				SwingUtilities.invokeLater( new Runnable()
356 				{
357 
358 					public void run()
359 					{
360 						refresh();
361 					}
362 				} );
363 		}
364 
365 		public void assertionAdded( TestAssertion assertion )
366 		{
367 			synchronized( this )
368 			{
369 				int sz = getSize();
370 				addAssertion( assertion );
371 
372 				fireIntervalAdded( this, sz, items.size() - 1 );
373 			}
374 		}
375 
376 		private void addAssertion( TestAssertion assertion )
377 		{
378 			assertion.addPropertyChangeListener( this );
379 			items.add( assertion );
380 
381 			AssertionError[] errors = assertion.getErrors();
382 			if( errors != null )
383 			{
384 				for( int i = 0; i < errors.length; i++ )
385 					items.add( errors[i] );
386 			}
387 		}
388 
389 		public void assertionRemoved( TestAssertion assertion )
390 		{
391 			synchronized( this )
392 			{
393 				int ix = items.indexOf( assertion );
394 				if( ix == -1 )
395 					return;
396 
397 				assertion.removePropertyChangeListener( this );
398 				items.remove( ix );
399 				fireIntervalRemoved( this, ix, ix );
400 
401 				// remove associated errors
402 				while( ix < items.size() && items.get( ix ) instanceof AssertionError )
403 				{
404 					items.remove( ix );
405 					fireIntervalRemoved( this, ix, ix );
406 				}
407 			}
408 		}
409 
410 		public void assertionMoved( TestAssertion newAssertion, int ix, int offset )
411 		{
412 			synchronized( this )
413 			{
414 				// int ix = items.indexOf( assertion );
415 				TestAssertion assertion = ( TestAssertion )items.get( ix );
416 				// if first selected can't move up and if last selected can't move
417 				// down
418 				if( ( ix == 0 && offset == -1 ) || ( ix == items.size() - 1 && offset == 1 ) )
419 				{
420 					return;
421 				}
422 
423 				assertion.removePropertyChangeListener( this );
424 				items.remove( ix );
425 				fireIntervalRemoved( this, ix, ix );
426 
427 				// remove associated errors
428 				while( ix < items.size() && items.get( ix ) instanceof AssertionError )
429 				{
430 					items.remove( ix );
431 					fireIntervalRemoved( this, ix, ix );
432 				}
433 				newAssertion.addPropertyChangeListener( this );
434 				items.add( ix + offset, newAssertion );
435 				fireIntervalAdded( this, ix + offset, ix + offset );
436 				// add associated errors
437 				while( ix < items.size() && items.get( ix ) instanceof AssertionError )
438 				{
439 					items.add( newAssertion );
440 					fireIntervalAdded( this, ix + offset, ix + offset );
441 				}
442 			}
443 		}
444 
445 	}
446 
447 	public void release()
448 	{
449 		assertionListModel.release();
450 	}
451 
452 	public class ConfigureAssertionAction extends AbstractAction
453 	{
454 		ConfigureAssertionAction()
455 		{
456 			super( "Configure" );
457 			putValue( Action.SHORT_DESCRIPTION, "Configures the selection assertion" );
458 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/options.gif" ) );
459 			setEnabled( false );
460 		}
461 
462 		public void actionPerformed( ActionEvent e )
463 		{
464 			int ix = assertionList.getSelectedIndex();
465 			if( ix == -1 )
466 				return;
467 
468 			TestAssertion assertion = assertionListModel.getAssertionAt( ix );
469 			if( assertion.isConfigurable() )
470 			{
471 				assertion.configure();
472 			}
473 			else
474 				Toolkit.getDefaultToolkit().beep();
475 		}
476 	}
477 
478 	public class RemoveAssertionAction extends AbstractAction
479 	{
480 		public RemoveAssertionAction()
481 		{
482 			super( "Remove Assertion" );
483 			putValue( Action.SHORT_DESCRIPTION, "Removes the selected assertion" );
484 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/remove_assertion.gif" ) );
485 			setEnabled( false );
486 		}
487 
488 		public void actionPerformed( ActionEvent e )
489 		{
490 			int ix = assertionList.getSelectedIndex();
491 			if( ix == -1 )
492 				return;
493 
494 			TestAssertion assertion = assertionListModel.getAssertionAt( ix );
495 			if( UISupport.confirm( "Remove assertion [" + assertion.getName() + "]", "Remove Assertion" ) )
496 			{
497 				assertable.removeAssertion( assertion );
498 			}
499 		}
500 	}
501 
502 	private class MoveAssertionUpAction extends AbstractAction
503 	{
504 		public MoveAssertionUpAction()
505 		{
506 			super( "Move Assertion Up" );
507 			putValue( Action.SHORT_DESCRIPTION, "Moves selected asertion up one row" );
508 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/up_arrow.gif" ) );
509 			setEnabled( false );
510 
511 		}
512 
513 		public void actionPerformed( ActionEvent e )
514 		{
515 			int ix = assertionList.getSelectedIndex();
516 			TestAssertion assertion = assertionListModel.getAssertionAt( ix );
517 			if( ix != -1 )
518 			{
519 				assertion = assertable.moveAssertion( ix, -1 );
520 			}
521 			assertionList.setSelectedValue( assertion, true );
522 		}
523 	}
524 
525 	private class MoveAssertionDownAction extends AbstractAction
526 	{
527 		public MoveAssertionDownAction()
528 		{
529 			super( "Move Assertion Down" );
530 			putValue( Action.SHORT_DESCRIPTION, "Moves selected asertion down one row" );
531 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/down_arrow.gif" ) );
532 			setEnabled( false );
533 
534 		}
535 
536 		public void actionPerformed( ActionEvent e )
537 		{
538 			int ix = assertionList.getSelectedIndex();
539 			TestAssertion assertion = assertionListModel.getAssertionAt( ix );
540 			if( ix != -1 )
541 			{
542 				assertion = assertable.moveAssertion( ix, 1 );
543 			}
544 			assertionList.setSelectedValue( assertion, true );
545 		}
546 	}
547 }