View Javadoc

1   /*
2    *  soapui, copyright (C) 2005 Ole Matzura / eviware.com 
3    *
4    *  SoapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of the GNU Lesser General Public License as published by the Free Software Foundation; 
6    *  either version 2.1 of the License, or (at your option) any later version.
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.request;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Component;
17  import java.awt.Dimension;
18  import java.awt.Toolkit;
19  import java.awt.event.ActionEvent;
20  import java.awt.event.FocusEvent;
21  import java.awt.event.FocusListener;
22  import java.awt.event.ItemEvent;
23  import java.awt.event.ItemListener;
24  import java.awt.event.KeyEvent;
25  import java.awt.event.MouseAdapter;
26  import java.awt.event.MouseEvent;
27  import java.beans.PropertyChangeEvent;
28  import java.beans.PropertyChangeListener;
29  import java.text.SimpleDateFormat;
30  import java.util.ArrayList;
31  import java.util.Date;
32  import java.util.List;
33  
34  import javax.swing.AbstractAction;
35  import javax.swing.AbstractListModel;
36  import javax.swing.Action;
37  import javax.swing.BorderFactory;
38  import javax.swing.DefaultComboBoxModel;
39  import javax.swing.DefaultListModel;
40  import javax.swing.JButton;
41  import javax.swing.JComboBox;
42  import javax.swing.JComponent;
43  import javax.swing.JLabel;
44  import javax.swing.JList;
45  import javax.swing.JOptionPane;
46  import javax.swing.JPanel;
47  import javax.swing.JPopupMenu;
48  import javax.swing.JScrollPane;
49  import javax.swing.JSplitPane;
50  import javax.swing.JTabbedPane;
51  import javax.swing.JTextArea;
52  import javax.swing.KeyStroke;
53  import javax.swing.ListCellRenderer;
54  import javax.swing.event.DocumentEvent;
55  import javax.swing.event.DocumentListener;
56  import javax.swing.event.PopupMenuEvent;
57  import javax.swing.event.PopupMenuListener;
58  
59  import org.apache.commons.logging.Log;
60  import org.apache.commons.logging.LogFactory;
61  
62  import com.eviware.soapui.SoapUI;
63  import com.eviware.soapui.impl.wsdl.WsdlInterface;
64  import com.eviware.soapui.impl.wsdl.WsdlRequest;
65  import com.eviware.soapui.impl.wsdl.actions.request.CreateEmptyRequestAction;
66  import com.eviware.soapui.impl.wsdl.actions.request.RecreateRequestAction;
67  import com.eviware.soapui.impl.wsdl.panels.request.actions.ValidateRequestXmlAction;
68  import com.eviware.soapui.impl.wsdl.panels.request.actions.ValidateResponseXmlAction;
69  import com.eviware.soapui.impl.wsdl.teststeps.WsdlAssertion;
70  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequest;
71  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep;
72  import com.eviware.soapui.impl.wsdl.teststeps.actions.AddAssertionAction;
73  import com.eviware.soapui.impl.wsdl.teststeps.actions.CloneTestRequestStepAction;
74  import com.eviware.soapui.impl.wsdl.teststeps.assertions.AssertionError;
75  import com.eviware.soapui.model.DesktopPanel;
76  import com.eviware.soapui.model.ModelItem;
77  import com.eviware.soapui.model.iface.Submit;
78  import com.eviware.soapui.model.iface.SubmitListener;
79  import com.eviware.soapui.model.iface.Submit.Status;
80  import com.eviware.soapui.support.JXmlTextArea;
81  import com.eviware.soapui.support.UISupport;
82  import com.eviware.soapui.support.actions.ChangeSplitPaneOrientationAction;
83  import com.eviware.soapui.support.actions.FormatXmlAction;
84  import com.eviware.soapui.support.actions.SaveXmlTextAreaAction;
85  import com.jgoodies.forms.builder.ButtonBarBuilder;
86  
87  /***
88   * DesktopPanel for WsdlTestRequest. Essentially a copy of WsdlRequestDesktopPanel with assertions.
89   * 
90   * @author Ole.Matzura
91   */
92  
93  public class WsdlTestRequestDesktopPanel extends JPanel implements DesktopPanel
94  {
95     private JXmlTextArea resultArea;
96     private JXmlTextArea inputArea;
97     private JComboBox soapEndpoint;
98     private JButton submitButton;
99     private JButton recreateButton;
100    private JButton cancelButton;
101    private JComboBox encodingCombo;
102    private WsdlTestRequest request;
103    private DefaultComboBoxModel endpointsModel;
104    
105    private final static Log log = LogFactory.getLog( WsdlTestRequestDesktopPanel.class );
106    private JTextArea logArea;
107    private JButton createEmptyButton;
108    private JList assertionList;
109    private JLabel statusLabel;
110    private JPopupMenu assertionListPopup;
111    private AssertionListModel assertionListModel;
112    private InternalPropertyChangeListener internalPropertyChangeListener;
113    private JButton cloneButton;
114    private JButton splitButton;
115    private WsdlTestRequestStep requestStep;
116 	public Submit submit;
117 	private InternalSubmitListener internalSubmitListener;
118 	private JSplitPane requestSplitPane;
119 	private MoveFocusAction moveFocusAction;
120 	private JButton addAssertionButton;
121 
122    public WsdlTestRequestDesktopPanel( WsdlTestRequestStep requestStep )
123    {
124       super( new BorderLayout() );
125       this.requestStep = requestStep;
126       this.request = requestStep.getTestRequest();
127       this.endpointsModel = new DefaultComboBoxModel( request.getOperation().getInterface().getEndpoints() );
128 
129       internalSubmitListener = new InternalSubmitListener();
130 		request.addSubmitListener( internalSubmitListener );
131       
132       internalPropertyChangeListener = new InternalPropertyChangeListener();
133       request.addPropertyChangeListener( internalPropertyChangeListener );
134       request.getOperation().getInterface().addPropertyChangeListener( internalPropertyChangeListener ); 
135       
136       add( buildUI(), BorderLayout.CENTER );
137       add( buildSearchBar(), BorderLayout.NORTH );
138       
139       statusLabel = new JLabel();
140       add( statusLabel, BorderLayout.PAGE_END );
141       
142       setPreferredSize( new Dimension( 600, 500 ));
143    }
144 
145    private Component buildLogPanel()
146    {
147       JTabbedPane tabbedPane = new JTabbedPane( JTabbedPane.BOTTOM );
148       
149       logArea = new JTextArea();
150       logArea.setEditable(false);
151       logArea.setToolTipText("Request Log");
152       
153       JPanel panel = new JPanel(new BorderLayout());
154       panel.add(new JScrollPane(logArea), BorderLayout.CENTER);
155       
156       tabbedPane.addTab( "Assertions", buildAssertionsPanel() );
157       tabbedPane.addTab( "Request Log", panel );
158       return tabbedPane;
159    }
160    
161    private Component buildAssertionsPanel()
162    {
163       assertionListModel = new AssertionListModel();
164       assertionList = new JList( assertionListModel );
165       assertionList.setToolTipText( "Assertions for this request" );
166       assertionList.setCellRenderer( new AssertionCellRenderer() );
167       
168       assertionListPopup = new JPopupMenu();
169       assertionListPopup.add( new AddAssertionAction( requestStep.getTestRequest() ));
170       
171       assertionListPopup.addPopupMenuListener( new PopupMenuListener(){
172 
173          public void popupMenuWillBecomeVisible(PopupMenuEvent e)
174          {
175             while( assertionListPopup.getComponentCount() > 1 ) 
176                assertionListPopup.remove( 1 );
177             
178             if( assertionListModel.getSize() == 0 ) return;
179             int ix = assertionList.getSelectedIndex();
180             if( ix == -1 ) return;
181             
182             WsdlAssertion assertion = assertionListModel.getAssertionAt( ix );
183             Action[] actions = assertion.getActions();
184             
185             for (int i = 0; i < actions.length; i++)
186             {
187                assertionListPopup.add( actions[i] );
188             }
189          }
190 
191          public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
192          {
193          }
194 
195          public void popupMenuCanceled(PopupMenuEvent e)
196          {
197          }});
198       
199       assertionList.setComponentPopupMenu( assertionListPopup );
200       
201       assertionList.addMouseListener( new MouseAdapter() {
202 
203 			public void mouseClicked(MouseEvent e)
204          {
205          	
206             if( e.getClickCount() < 2 ) return;
207 
208             int ix = assertionList.getSelectedIndex();
209             if( ix == -1 ) return;
210             
211             Object obj = assertionList.getModel().getElementAt( ix );
212             if( obj instanceof WsdlAssertion )
213             {
214 	            WsdlAssertion assertion = (WsdlAssertion) obj;
215 	            if( assertion.isConfigurable() )
216 	               assertion.configure();
217             }
218    		   if( obj instanceof AssertionError )
219    		   {
220    		   	AssertionError error = (AssertionError) obj;
221    		   	if( error.getLineNumber() >= 0 )
222    		   	{
223    		   		resultArea.setCaretPosition( resultArea.getLineStartOffset( error.getLineNumber()-1 ) );
224    		   		resultArea.requestFocus();
225    		   	}
226    		   	else Toolkit.getDefaultToolkit().beep();
227    		   }
228    		   else Toolkit.getDefaultToolkit().beep();
229          }});
230       
231       return new JScrollPane( assertionList );
232    }
233 
234    class AssertionCellRenderer extends JLabel implements ListCellRenderer 
235    {
236       public Component getListCellRendererComponent(
237         JList list,
238         Object value,           
239         int index,               
240         boolean isSelected,      
241         boolean cellHasFocus)    
242       {
243       	if( value instanceof WsdlAssertion )
244       	{
245       		WsdlAssertion assertion = (WsdlAssertion) value;
246       		setText( assertion.getName() + " - " + assertion.getStatus().toString() );
247             setIcon( assertion.getIcon() );
248       	}
249       	else if( value instanceof AssertionError )
250       	{
251             AssertionError assertion = (AssertionError) value;
252             setText( " -> " + assertion.toString() );
253             setIcon( null );
254       	}
255       	
256           if (isSelected) 
257           {
258              setBackground(list.getSelectionBackground());
259              setForeground(list.getSelectionForeground());
260           }
261           else 
262           {
263              setBackground(list.getBackground());
264              setForeground(list.getForeground());
265           }
266           
267           setEnabled(list.isEnabled());
268           setFont(list.getFont());
269           setOpaque(true);
270           
271           return this;
272       }
273   }
274    
275    private class AssertionListModel extends AbstractListModel implements PropertyChangeListener, 
276        WsdlTestRequest.WsdlTestRequestListener
277    {
278    	private List<Object> items = new ArrayList<Object>();
279    	
280       public AssertionListModel()
281       {
282       	init();
283       }
284       
285       public int getSize()
286       {
287       	return items.size();
288       }
289 
290       public Object getElementAt(int index)
291       {
292       	return items.get( index );
293       }
294 
295       public WsdlAssertion getAssertionAt( int index )
296       {
297       	Object object = items.get( index );
298       	while( object instanceof AssertionError && index > 0 )
299       	{
300       		object = items.get( --index );
301       	}
302       	
303       	return (WsdlAssertion) object;
304       }
305       
306       public void refresh()
307       {
308 			release();
309       	init();
310          fireContentsChanged( this, 0, getSize() );
311       }
312 
313 		private void init()
314 		{
315       	request.addWsdlTestRequestListener( this );
316 			
317          for( int c = 0; c < request.getAssertionCount(); c++ )
318          {
319          	WsdlAssertion assertion = request.getAssertionAt( c );
320          	addAssertion(assertion);
321          }
322 		}
323 		
324 		public void release()
325 		{
326          items.clear();
327 
328          for( int c = 0; c < request.getAssertionCount(); c++ )
329          {
330          	WsdlAssertion assertion = request.getAssertionAt( c );
331          	assertion.removePropertyChangeListener( this );
332          }
333          
334          request.removeWsdlTestRequestListener( this );
335 		}
336 
337 		public void propertyChange(PropertyChangeEvent evt)
338 		{
339 			refresh();
340 		}
341 
342 		public void assertionAdded(WsdlAssertion assertion)
343 		{
344 			int sz = getSize();
345       	addAssertion(assertion);
346       	
347       	fireIntervalAdded( this, sz, items.size()-1 );
348 		}
349 
350 		private void addAssertion(WsdlAssertion assertion)
351 		{
352 			assertion.addPropertyChangeListener( this );
353       	items.add( assertion );
354       	
355       	AssertionError[] errors = assertion.getErrors();
356       	if( errors != null)
357       	{
358       		for( int i = 0; i < errors.length; i++ )
359       		items.add( errors[i] );
360       	}
361 		}
362 
363 		public void assertionRemoved(WsdlAssertion assertion)
364 		{
365 			int ix = items.indexOf( assertion );
366 			if( ix == -1 ) return;
367 
368 			assertion.removePropertyChangeListener( this );
369 			items.remove( ix );
370 			fireIntervalRemoved( this, ix, ix );
371 			
372 			// remove associated errors
373 			while( ix < items.size() && items.get( ix ) instanceof AssertionError )
374 			{
375 				items.remove( ix );
376 				fireIntervalRemoved( this, ix, ix );
377 			}
378 		}
379    }
380    
381    private JComponent buildUI()
382    {
383    	requestSplitPane = UISupport.createHorizontalSplit();
384 		submitButton = createActionButton( new SubmitAction(), true );
385       cancelButton = createActionButton( new CancelAction(), false );
386       addAssertionButton = createActionButton( new AddAssertionAction( request ), true );
387       splitButton = createActionButton( new ChangeSplitPaneOrientationAction( requestSplitPane ), true );
388       recreateButton = createActionButton( new RecreateRequestAction(request), true );
389       cloneButton = createActionButton( new CloneTestRequestStepAction( requestStep ), true );
390       createEmptyButton = createActionButton( new CreateEmptyRequestAction(request), true );
391       
392       submitButton.setEnabled( request.getEndpoint() != null && request.getEndpoint().trim().length() > 0 );
393       moveFocusAction = new MoveFocusAction();
394       
395       requestSplitPane.setTopComponent( buildInputUI() );
396       requestSplitPane.setBottomComponent( buildOutputUI() );
397       requestSplitPane.setDividerLocation( 0.5 );
398       requestSplitPane.setResizeWeight( 0.5 );
399       requestSplitPane.setBorder( null );
400       
401       JSplitPane outerSplit = UISupport.createVerticalSplit();
402       outerSplit.setTopComponent( requestSplitPane );
403       outerSplit.setBottomComponent( buildLogPanel() );
404       outerSplit.setDividerLocation( 350 );
405       outerSplit.setResizeWeight( 0.9 );
406       outerSplit.setBorder( null );
407 
408       return outerSplit;
409    }
410    
411    private JButton createActionButton( Action action, boolean enabled )
412    {
413    	JButton button = new JButton( action );
414    	action.putValue( Action.NAME, null );
415    	button.setPreferredSize( new Dimension(24, 24 ));
416    	button.setEnabled( enabled );
417    	return button;
418    }
419 
420    private Component buildOutputUI()
421    {
422    	resultArea = new JXmlTextArea();
423       resultArea.setMinimumSize( new Dimension( 50, 100 ));
424       resultArea.setToolTipText( "Response Area" );
425       if( request.getResponseContent() != null )
426       {
427    		resultArea.setText( request.getResponseContent() );
428    		resultArea.setCaretPosition( 0 );
429       }
430       resultArea.addFocusListener( new ResultAreaFocusListener() );
431       
432       DefaultListModel listModel = new DefaultListModel();
433       JList list = new JList( listModel );
434       list.setToolTipText( "Response Validation Errors" );
435       list.addMouseListener( new ValidationListMouseAdapter( list, resultArea ));
436 		JScrollPane scrollPane = new JScrollPane( list );
437 		scrollPane.setVisible( false );
438 		
439 		JSplitPane resultAreaSplit = UISupport.createVerticalSplit();
440 
441 		JPopupMenu popup = new JPopupMenu();
442       ValidateResponseXmlAction validateResponseXmlAction = new ValidateResponseXmlAction( request, scrollPane, listModel, resultAreaSplit, resultArea );
443       popup.add( validateResponseXmlAction );
444       FormatXmlAction formatXmlAction = new FormatXmlAction(resultArea);
445 		popup.add( formatXmlAction);
446       popup.addSeparator();
447       popup.add( resultArea.getUndoAction() );
448       popup.add( resultArea.getRedoAction() );
449       popup.add( resultArea.getCopyAction() );
450       popup.add( resultArea.getCutAction() );
451       popup.add( resultArea.getPasteAction() );
452       popup.addSeparator();
453       popup.add( resultArea.getFindAndReplaceAction() );
454       popup.addSeparator();
455       SaveXmlTextAreaAction saveXmlTextAreaAction = new SaveXmlTextAreaAction(resultArea, "Save Response");
456 		popup.add( saveXmlTextAreaAction);
457       
458       resultArea.setRightClickPopup( popup );
459       resultArea.getInputHandler().addKeyBinding( "A+ENTER", submitButton.getAction() );
460       resultArea.getInputHandler().addKeyBinding( "A+X", cancelButton.getAction() );
461       resultArea.getInputHandler().addKeyBinding( "A+V", validateResponseXmlAction );
462       resultArea.getInputHandler().addKeyBinding( "A+F", formatXmlAction );
463       resultArea.getInputHandler().addKeyBinding( "A+S", saveXmlTextAreaAction );
464       resultArea.getInputHandler().addKeyBinding( "S+TAB", moveFocusAction );
465       
466       resultAreaSplit.setTopComponent( resultArea );
467 		resultAreaSplit.setBottomComponent( scrollPane);
468       resultAreaSplit.setDividerLocation( 1.0 );
469       
470       return resultAreaSplit;
471    }
472 
473    private Component buildInputUI()
474    {
475       inputArea = new JXmlTextArea();
476       inputArea.setMinimumSize( new Dimension( 50, 100 ));
477       inputArea.setToolTipText( "Request Area" );
478       inputArea.setText( request.getRequestContent() );
479       inputArea.setCaretPosition( 0 );
480       inputArea.setDiscardEditsOnSet( false );
481       inputArea.addFocusListener( new InputAreaFocusListener());
482       
483       DefaultListModel listModel = new DefaultListModel();
484       JList list = new JList( listModel );
485       list.setToolTipText( "Request Validation Errors" );
486       list.addMouseListener( new ValidationListMouseAdapter( list, inputArea ));
487 		JScrollPane scrollPane = new JScrollPane( list );
488 		scrollPane.setVisible( false );
489 		
490 		JSplitPane inputAreaSplit = UISupport.createVerticalSplit();
491       
492       JPopupMenu inputPopup = new JPopupMenu();
493       ValidateRequestXmlAction validateRequestXmlAction = new ValidateRequestXmlAction( request, scrollPane, listModel, inputAreaSplit, inputArea );
494 		inputPopup.add( validateRequestXmlAction);
495       FormatXmlAction formatXmlAction = new FormatXmlAction(inputArea);
496 		inputPopup.add( formatXmlAction);
497       inputPopup.addSeparator();
498       inputPopup.add( inputArea.getUndoAction() );
499       inputPopup.add( inputArea.getRedoAction() );
500       inputPopup.add( inputArea.getCopyAction() );
501       inputPopup.add( inputArea.getCutAction() );
502       inputPopup.add( inputArea.getPasteAction() );
503       inputPopup.addSeparator();
504       inputPopup.add( inputArea.getFindAndReplaceAction() );
505       inputPopup.addSeparator();
506       SaveXmlTextAreaAction saveXmlTextAreaAction = new SaveXmlTextAreaAction(inputArea, "Save Request");
507 		inputPopup.add( saveXmlTextAreaAction);
508 		
509       inputArea.setRightClickPopup( inputPopup );
510       
511       inputArea.getDocument().addDocumentListener( new DocumentListener() {
512 
513          public void insertUpdate(DocumentEvent e)
514          {
515             request.setRequest( inputArea.getText() );
516          }
517 
518          public void removeUpdate(DocumentEvent e)
519          {
520             request.setRequest( inputArea.getText() );
521          }
522 
523          public void changedUpdate(DocumentEvent e)
524          {
525             
526          }} );
527       
528       inputArea.getInputHandler().addKeyBinding( "A+ENTER", submitButton.getAction() );
529       inputArea.getInputHandler().addKeyBinding( "A+X", cancelButton.getAction() );
530       inputArea.getInputHandler().addKeyBinding( "A+V", validateRequestXmlAction );
531       inputArea.getInputHandler().addKeyBinding( "A+F", formatXmlAction );
532       inputArea.getInputHandler().addKeyBinding( "A+S", saveXmlTextAreaAction );
533       inputArea.getInputHandler().addKeyBinding( "S+TAB", moveFocusAction );
534      
535       inputAreaSplit.setTopComponent( inputArea );
536 		inputAreaSplit.setBottomComponent( scrollPane);
537       inputAreaSplit.setDividerLocation( 1.0 );
538       
539       return inputAreaSplit;
540    }
541 
542 
543    private JComponent buildSearchBar()
544    {
545       soapEndpoint = new JComboBox( endpointsModel);
546       soapEndpoint.setToolTipText( "Select the endpoint of the SOAP service" );
547       soapEndpoint.setPreferredSize( new Dimension( 300, 20 ));
548       
549       endpointsModel.setSelectedItem( request.getEndpoint());
550       
551       soapEndpoint.addItemListener( new ItemListener() {
552 
553          public void itemStateChanged(ItemEvent e)
554          {
555             Object selectedItem = soapEndpoint.getSelectedItem();
556             if( selectedItem != null && !selectedItem.equals(request.getEndpoint()))
557                request.setEndpoint( selectedItem.toString() );
558          }});
559       
560       encodingCombo = new JComboBox();
561       encodingCombo.setEditable( true );
562       encodingCombo.addItem( "UTF-8" );
563       encodingCombo.addItem( "iso-8859-1" );
564       encodingCombo.setSelectedItem( request.getEncoding() );
565       encodingCombo.setToolTipText( "Sets the encoding to use for the request" );
566       
567       encodingCombo.addItemListener( new ItemListener() {
568 
569          public void itemStateChanged(ItemEvent e)
570          {
571             request.setEncoding( encodingCombo.getSelectedItem().toString() );
572          }});
573       
574       ButtonBarBuilder builder = new ButtonBarBuilder();
575       builder.addFixed( submitButton );
576       builder.addRelatedGap();
577       builder.addFixed( addAssertionButton );
578       builder.addRelatedGap();
579       builder.addFixed( recreateButton );
580       builder.addRelatedGap();
581       builder.addFixed( createEmptyButton );
582       builder.addRelatedGap();
583       builder.addFixed( cloneButton );
584       builder.addRelatedGap();
585       builder.addFixed( cancelButton );
586       builder.addUnrelatedGap();
587       builder.addFixed( soapEndpoint );
588       builder.addRelatedGap();
589       builder.addFixed( encodingCombo );
590       builder.addRelatedGap();
591       builder.addFixed( splitButton );
592 
593 
594       builder.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
595       return builder.getPanel();
596    }
597 
598    public void setEnabled( boolean enabled )
599    {
600       soapEndpoint.setEnabled( enabled );
601       inputArea.setEditable( enabled );
602       resultArea.setEditable( enabled );
603       addAssertionButton.setEnabled( enabled );
604       submitButton.setEnabled( enabled && request.getEndpoint() != null && request.getEndpoint().trim().length() > 0);
605       recreateButton.setEnabled( enabled );
606       createEmptyButton.setEnabled( enabled );
607       cloneButton.setEnabled( enabled );
608       encodingCombo.setEnabled( enabled );
609    }
610    
611    public class ValidateAction extends AbstractAction
612    {
613       public ValidateAction()
614       {
615          putValue( Action.SMALL_ICON, SoapUI.createImageIcon( "/validate_request.gif"));
616          putValue( Action.SHORT_DESCRIPTION, "Validates the current response with the current assertions" );
617       }
618 
619       public void actionPerformed( ActionEvent e )
620       {
621          request.setResponse( resultArea.getText() );
622       }
623    }
624    
625    public class SubmitAction extends AbstractAction
626    {
627       public SubmitAction()
628       {
629          putValue( Action.SMALL_ICON, SoapUI.createImageIcon( "/submit_request.gif"));
630          putValue( Action.SHORT_DESCRIPTION, "Submit request to specified endpoint URL" );
631          putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, KeyEvent.ALT_MASK ));
632       }
633 
634       public void actionPerformed( ActionEvent e )
635       {
636       	if( submit != null && submit.getStatus() == Submit.Status.RUNNING )
637       	{
638       		if( UISupport.confirm( "Cancel current request?", "Submit Request" ))
639       		{
640       			submit.cancel();
641       		}
642       		else return;
643       	}
644       	
645       	submit = request.submit();
646       }
647    }
648 
649    private class CancelAction extends AbstractAction
650    {
651       public CancelAction()
652       {
653          super();
654          putValue( Action.SMALL_ICON, SoapUI.createImageIcon( "/cancel_request.gif"));
655          putValue( Action.SHORT_DESCRIPTION, "Aborts ongoing request" );
656          putValue( Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke( KeyEvent.VK_X, KeyEvent.ALT_MASK ));
657       }
658 
659       public void actionPerformed( ActionEvent e )
660       {
661       	if( submit == null ) return;
662       	
663          cancelButton.setEnabled( false );
664          WsdlTestRequestDesktopPanel.this.setEnabled( true );
665          submit.cancel();
666       }
667    }
668 
669    private class InternalSubmitListener implements SubmitListener
670    {
671       private long startTime;
672       private SimpleDateFormat sdf;
673 
674       private InternalSubmitListener()
675       {
676          sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
677       }
678 
679       public boolean onSubmit(Submit submit)
680       {
681       	if( submit.getRequest() != request ) return true;
682       	
683          setEnabled( false );
684          cancelButton.setEnabled( WsdlTestRequestDesktopPanel.this.submit != null );
685          startTime = System.currentTimeMillis();
686          return true;
687       }
688 
689       public void afterSubmit(Submit submit)
690       {
691       	if( submit.getRequest() != request ) return;
692       	Status status = submit.getStatus();
693       	
694          if( status != Status.CANCELED )
695          {
696             cancelButton.setEnabled( false );
697             setEnabled( true );
698             
699             request.setResponse( submit.getResponse( false ).getContentAsString() );
700          }
701          
702          String message = null;
703          String infoMessage = null;
704          String requestName = request.getOperation().getInterface().getName() + "." + 
705             request.getOperation().getName() + ":" + request.getName();
706 
707          if( status == Status.CANCELED ) 
708          {
709             message = "CANCELED";
710             infoMessage = "[" + requestName + "] - CANCELED";
711          }
712          else
713          {
714             if( status == Status.ERROR )
715             {
716                message = "Error getting response; " + submit.getError().getMessage();
717                infoMessage = "Error getting response for [" + requestName + "]; " + submit.getError().getMessage();
718             }
719             else
720             {
721                message = "request time: " + submit.getTimeTaken() + "ms (" + 
722                   submit.getResponse( false ).getContentLength() + " bytes)";   
723                infoMessage = "Got response for [" + requestName + "] in " + submit.getTimeTaken() + "ms (" + 
724                   submit.getResponse( false ).getContentLength() + " bytes)";   
725                
726                resultArea.requestFocus();
727             }
728          }
729          
730          log.info( infoMessage );
731          
732          String logText = logArea.getText() + sdf.format( new Date( startTime )) + " - " + message + "\r\n";
733          logArea.setText( logText );
734          logArea.setCaretPosition( logText.length() );
735          statusLabel.setText( message  );
736          
737          WsdlTestRequestDesktopPanel.this.submit = null;
738       }
739    }
740    
741    private class InternalPropertyChangeListener implements PropertyChangeListener
742    {
743       public void propertyChange(PropertyChangeEvent evt)
744       {
745          String propertyName = evt.getPropertyName();
746          if( propertyName.equals( WsdlRequest.RESPONSE_PROPERTY ))
747          {
748             resultArea.setText( request.getResponseContent() );
749             resultArea.setCaretPosition( 0 );
750          }
751          else if( propertyName.equals( WsdlRequest.ENCODING_PROPERTY ))
752          {
753             encodingCombo.setSelectedItem( request.getEncoding() );
754          }
755          else if( propertyName.equals( WsdlRequest.ENDPOINT_PROPERTY ))
756          {
757             endpointsModel.setSelectedItem( request.getEndpoint() );
758             submitButton.setEnabled( request.getEndpoint() != null && request.getEndpoint().trim().length() > 0 );
759          }
760          else if( propertyName.equals( WsdlInterface.ENDPOINTS_PROPERTY ))
761          {
762             endpointsModel.removeAllElements();
763             String[] endpoints = request.getOperation().getInterface().getEndpoints();
764             for (int i = 0; i < endpoints.length; i++)
765             {
766                endpointsModel.addElement( endpoints[i] );
767             }
768             
769             endpointsModel.setSelectedItem( request.getEndpoint() );
770             submitButton.setEnabled( request.getEndpoint() != null && request.getEndpoint().trim().length() > 0 );
771          }
772          else if( propertyName.equals( WsdlTestRequest.STATUS_PROPERTY ))
773          {
774             assertionListModel.refresh(); 
775          }
776          else if( propertyName.equals( WsdlRequest.REQUEST_PROPERTY ))
777          {
778          	String requestContent = request.getRequestContent();
779             if( !requestContent.equals( inputArea.getText()))
780             	inputArea.setText( requestContent );
781          }
782       }
783    }
784    
785    private class MoveFocusAction extends AbstractAction
786    {
787 		public void actionPerformed(ActionEvent e)
788 		{
789 			if( inputArea.hasFocus() )
790 				resultArea.requestFocus();
791 			else 
792 			   inputArea.requestFocus();
793 		}
794    }
795    
796    private final class InputAreaFocusListener implements FocusListener
797 	{
798 		public void focusGained(FocusEvent e)
799 		{
800 			int pos = requestSplitPane.getDividerLocation();
801 			if( pos >= 600 ) return;
802 			if( requestSplitPane.getMaximumDividerLocation() > 700 )
803 				requestSplitPane.setDividerLocation( 600 );
804 			else
805 			   requestSplitPane.setDividerLocation( 0.8 );
806 		}
807 
808 		public void focusLost(FocusEvent e)
809 		{
810 		}
811 	}
812    
813    private final class ResultAreaFocusListener implements FocusListener
814 	{
815 		public void focusGained(FocusEvent e)
816 		{
817 			if( resultArea.getText().trim().length() == 0 ) 
818 				return;
819 			
820 			int pos = requestSplitPane.getDividerLocation();
821 			int maximumDividerLocation = requestSplitPane.getMaximumDividerLocation();
822 			if( pos + 600 < maximumDividerLocation ) return;
823 			
824 			if( maximumDividerLocation > 700 )
825 				requestSplitPane.setDividerLocation( maximumDividerLocation-600 );
826 			else
827 				requestSplitPane.setDividerLocation( 0.2 );
828 		}
829 
830 		public void focusLost(FocusEvent e)
831 		{
832 		}
833 	}
834 
835 
836    public ModelItem getModelItem()
837 	{
838 		return requestStep;
839 	}
840 
841 	public boolean onClose()
842 	{
843 		if( submit != null && submit.getStatus() == Submit.Status.RUNNING )
844 		{
845 			int retVal = JOptionPane.showConfirmDialog( SoapUI.getInstance().getFrame(), "Cancel request before closing?",
846 					 "Closing window", JOptionPane.YES_NO_CANCEL_OPTION);
847 			if( retVal == JOptionPane.CANCEL_OPTION ) return false;
848 			
849 			if( retVal == JOptionPane.YES_OPTION && submit.getStatus() == Submit.Status.RUNNING )
850 				submit.cancel();
851 		}
852 		
853       request.removeSubmitListener( internalSubmitListener );
854       request.removePropertyChangeListener( internalPropertyChangeListener );
855       request.getOperation().getInterface().removePropertyChangeListener( internalPropertyChangeListener );
856       assertionListModel.release();
857       
858       return true;
859 	}
860 
861 	public JComponent getComponent()
862 	{
863 		return this;
864 	}
865 	
866    private final class ValidationListMouseAdapter extends MouseAdapter
867 	{
868 		private final JList list;
869 		private final JXmlTextArea textArea;
870 
871 		public ValidationListMouseAdapter(JList list, JXmlTextArea textArea)
872 		{
873 			this.list = list;
874 			this.textArea = textArea;
875 		}
876 
877 		public void mouseClicked(MouseEvent e)
878 		{
879 		   if( e.getClickCount() < 2 ) return;
880 		
881 		   int ix = list.getSelectedIndex();
882 		   if( ix == -1 ) return;
883 		   
884 		   Object obj = list.getModel().getElementAt( ix );
885 		   if( obj instanceof AssertionError )
886 		   {
887 		   	AssertionError error = (AssertionError) obj;
888 		   	if( error.getLineNumber() >= 0 )
889 		   	{
890 		   		textArea.setCaretPosition( textArea.getLineStartOffset( error.getLineNumber()-1 ) );
891 		   		textArea.requestFocus();
892 		   	}
893 		   	else Toolkit.getDefaultToolkit().beep();
894 		   }
895 		   else Toolkit.getDefaultToolkit().beep();
896 		}
897 	}
898 }