View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 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.request;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Component;
17  import java.awt.Dimension;
18  import java.awt.event.ActionEvent;
19  import java.awt.event.FocusAdapter;
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.beans.PropertyChangeEvent;
25  import java.beans.PropertyChangeListener;
26  import java.security.cert.Certificate;
27  
28  import javax.swing.AbstractAction;
29  import javax.swing.Action;
30  import javax.swing.BorderFactory;
31  import javax.swing.Box;
32  import javax.swing.JButton;
33  import javax.swing.JComboBox;
34  import javax.swing.JComponent;
35  import javax.swing.JEditorPane;
36  import javax.swing.JPanel;
37  import javax.swing.JPopupMenu;
38  import javax.swing.JScrollPane;
39  import javax.swing.JSeparator;
40  import javax.swing.JSplitPane;
41  import javax.swing.JTabbedPane;
42  import javax.swing.JTable;
43  import javax.swing.JToggleButton;
44  import javax.swing.JToolBar;
45  import javax.swing.SwingUtilities;
46  import javax.swing.event.ChangeEvent;
47  import javax.swing.event.ChangeListener;
48  import javax.swing.event.TableModelEvent;
49  import javax.swing.event.TableModelListener;
50  import javax.swing.text.html.HTMLEditorKit;
51  
52  import org.apache.log4j.Logger;
53  
54  import com.eviware.soapui.SoapUI;
55  import com.eviware.soapui.impl.wsdl.WsdlRequest;
56  import com.eviware.soapui.impl.wsdl.WsdlSubmitContext;
57  import com.eviware.soapui.impl.wsdl.actions.operation.AddToMockServiceAction;
58  import com.eviware.soapui.impl.wsdl.actions.request.CloneRequestAction;
59  import com.eviware.soapui.impl.wsdl.actions.request.CreateEmptyRequestAction;
60  import com.eviware.soapui.impl.wsdl.actions.request.RecreateRequestAction;
61  import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
62  import com.eviware.soapui.impl.wsdl.panels.attachments.AttachmentPanel;
63  import com.eviware.soapui.impl.wsdl.panels.request.actions.WSIValidateRequestAction;
64  import com.eviware.soapui.impl.wsdl.panels.request.components.RequestMessageXmlEditor;
65  import com.eviware.soapui.impl.wsdl.panels.request.components.RequestXmlDocument;
66  import com.eviware.soapui.impl.wsdl.panels.request.components.ResponseMessageXmlEditor;
67  import com.eviware.soapui.impl.wsdl.panels.request.components.ResponseXmlDocument;
68  import com.eviware.soapui.impl.wsdl.panels.request.components.SoapMessageXmlEditor;
69  import com.eviware.soapui.impl.wsdl.panels.request.components.editor.XmlDocument;
70  import com.eviware.soapui.impl.wsdl.panels.request.components.editor.views.source.XmlSourceEditorView;
71  import com.eviware.soapui.impl.wsdl.panels.support.EndpointsComboBoxModel;
72  import com.eviware.soapui.impl.wsdl.submit.transports.http.SSLInfo;
73  import com.eviware.soapui.impl.wsdl.submit.transports.http.WsdlResponse;
74  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
75  import com.eviware.soapui.model.ModelItem;
76  import com.eviware.soapui.model.iface.Submit;
77  import com.eviware.soapui.model.iface.SubmitContext;
78  import com.eviware.soapui.model.iface.SubmitListener;
79  import com.eviware.soapui.model.iface.Request.SubmitException;
80  import com.eviware.soapui.model.iface.Submit.Status;
81  import com.eviware.soapui.settings.UISettings;
82  import com.eviware.soapui.support.UISupport;
83  import com.eviware.soapui.support.actions.ChangeSplitPaneOrientationAction;
84  import com.eviware.soapui.support.components.JEditorStatusBarWithProgress;
85  import com.eviware.soapui.support.components.JXToolBar;
86  import com.eviware.soapui.support.swing.SoapUISplitPaneUI;
87  import com.eviware.soapui.support.types.StringToStringMap;
88  import com.eviware.soapui.support.xml.JXEditTextArea;
89  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
90  import com.jgoodies.forms.builder.ButtonBarBuilder;
91  
92  /***
93   * DesktopPanel for WsdlRequests
94   * 
95   * @author Ole.Matzura
96   */
97  
98  public class AbstractWsdlRequestDesktopPanel<T extends ModelItem, T2 extends WsdlRequest> extends ModelItemDesktopPanel<T>
99  {
100 	private final static Logger log = Logger.getLogger(AbstractWsdlRequestDesktopPanel.class);
101 
102 	private JComboBox endpointCombo;
103 	private JButton submitButton;
104 	private JButton cancelButton;
105 	private EndpointsComboBoxModel endpointsModel;
106 	private JEditorStatusBarWithProgress statusBar;
107 	private JButton splitButton;
108 	private Submit submit;
109 	private JButton recreateButton;
110 	private JButton cloneButton;
111 	private JButton createEmptyButton;
112 	private InternalSubmitListener internalSubmitListener;
113 	private JSplitPane requestSplitPane;
114 	private MoveFocusAction moveFocusAction;
115 	private ClosePanelAction closePanelAction = new ClosePanelAction();
116 	private T2 request;
117 
118 	private SoapMessageXmlEditor requestEditor;
119 	private SoapMessageXmlEditor responseEditor;
120 
121 	//public WSIValidateRequestAction wsiValidateAction;
122 
123 	private JTabbedPane requestTabs;
124 	private JPanel requestTabPanel;
125 	private JToggleButton tabsButton;
126 
127 	public boolean responseHasFocus;
128 
129 	private JTabbedPane requestEditorTabs;
130 	private JTabbedPane responseEditorTabs;
131 
132 	private JPanel requestEditorTabPanel;
133 	private JPanel responseEditorTabPanel;
134 	private AttachmentPropertyChangeListener attachmentsPropertyChangeListener = new AttachmentPropertyChangeListener();
135 	private StringToStringMapTableModel requestHeadersModel;
136 	private JTable requestHeadersTable;
137 	private StringToStringMapTableModel responseHeadersModel;
138 
139 	private JEditorPane sslInfoPane;
140 	private JButton addToMockServiceButton;
141 	//private JButton addAsMockResponseStepButton;
142 	
143 //	private DefaultActionList formEditorActions;
144 
145 	private WSIValidateRequestAction wsiValidateAction;
146 
147 	public AbstractWsdlRequestDesktopPanel(T modelItem)
148 	{
149 		super(modelItem);
150 	}
151 
152 	protected void init(T2 request)
153 	{
154 		this.request = request;
155 		
156 		this.endpointsModel = new EndpointsComboBoxModel(request);
157 		internalSubmitListener = createSubmitListener();
158 
159 		request.addSubmitListener(internalSubmitListener);
160 
161 		add(buildContent(), BorderLayout.CENTER);
162 		add(buildToolbar(), BorderLayout.NORTH);
163 		add(buildStatusLabel(), BorderLayout.SOUTH);
164 
165 		setPreferredSize(new Dimension(600, 500));
166 		
167 		request.addPropertyChangeListener( attachmentsPropertyChangeListener );
168 		
169 		addFocusListener( new FocusAdapter() {
170 
171 			@Override
172 			public void focusGained( FocusEvent e )
173 			{
174 				if( requestTabs.getSelectedIndex() == 1 || responseHasFocus )
175 					responseEditor.requestFocusInWindow();
176 				else
177 					requestEditor.requestFocusInWindow();
178 			}} );
179 	}
180 
181 	protected InternalSubmitListener createSubmitListener()
182 	{
183 		return new InternalSubmitListener();
184 	}
185 	
186 	public final T2 getRequest()
187 	{
188 		return request;
189 	}
190 	
191 	public final SoapMessageXmlEditor getRequestEditor()
192 	{
193 		return requestEditor;
194 	}
195 
196 	public final SoapMessageXmlEditor getResponseEditor()
197 	{
198 		return responseEditor;
199 	}
200 	
201 	public Submit getSubmit()
202 	{
203 		return submit;
204 	}
205 
206 	protected JComponent buildStatusLabel()
207 	{
208 		statusBar = new JEditorStatusBarWithProgress();
209 		statusBar.setBorder( BorderFactory.createEmptyBorder( 1, 0, 0, 0 ));
210 		
211 		return statusBar;
212 	}
213 	
214 	public JEditorStatusBarWithProgress getStatusBar()
215 	{
216 		return statusBar;
217 	}
218 
219 	protected JComponent buildContent()
220 	{
221 		requestSplitPane = UISupport.createHorizontalSplit();
222 		requestSplitPane.setResizeWeight(0.5);
223 		requestSplitPane.setBorder(null);
224 		
225 		submitButton = createActionButton(new SubmitAction(), true);
226 		cancelButton = createActionButton(new CancelAction(), false);
227 		splitButton = createActionButton(new ChangeSplitPaneOrientationAction(requestSplitPane), true);
228 		
229 		tabsButton = new JToggleButton( new ChangeToTabsAction() );
230 		tabsButton.setPreferredSize( UISupport.TOOLBAR_BUTTON_DIMENSION );
231 		
232 		recreateButton = createActionButton(new RecreateRequestAction(request), true);
233 		addToMockServiceButton = createActionButton( new AddToMockServiceAction(request), true );
234 		
235 //		addAsMockResponseStepButton = createActionButton( new AddAsMockResponseStepAction(request), true );
236 		cloneButton = createActionButton(new CloneRequestAction(request), true );
237 		
238 		createEmptyButton = createActionButton(new CreateEmptyRequestAction(request), true);
239 
240 		submitButton.setEnabled(request.getEndpoint() != null && request.getEndpoint().trim().length() > 0);
241 		wsiValidateAction = new WSIValidateRequestAction( request );
242 		
243 		moveFocusAction = new MoveFocusAction();
244 
245 		requestEditor = buildRequestEditor();
246 		responseEditor = buildResponseEditor();
247 		
248 		requestEditorTabs = new JTabbedPane( JTabbedPane.BOTTOM );
249 		requestEditorTabs.setTabLayoutPolicy( JTabbedPane.SCROLL_TAB_LAYOUT );
250 		requestEditorTabs.addTab( "SOAP Request", requestEditor );
251 		requestEditorTabs.addTab( "Request Attachments (" + request.getAttachmentCount() + ")"
252 				, new AttachmentPanel( request, true ));
253 		requestEditorTabs.addTab( "HTTP Headers (" + request.getRequestHeaders().size() + ")", createRequestHttpHeadersPanel() );
254 		requestEditorTabs.addChangeListener( new ChangeListener() {
255 
256 			public void stateChanged( ChangeEvent e )
257 			{
258 				SwingUtilities.invokeLater( new Runnable() {
259 
260 					public void run()
261 					{
262 						int ix = requestEditorTabs.getSelectedIndex();
263 						if( ix == 0 )
264 						  requestEditor.requestFocus(); 
265 					}}  );
266 				
267 			}} );
268 		
269 		responseEditorTabs = new JTabbedPane( JTabbedPane.BOTTOM );
270 		responseEditorTabs.setTabLayoutPolicy( JTabbedPane.SCROLL_TAB_LAYOUT );
271 		responseEditorTabs.addTab( "SOAP Response", responseEditor );
272 		responseEditorTabs.addTab( "Response Attachments (" + (request.getResponse() == null ? 0 :
273 			request.getResponse().getAttachments().length) + ")", new AttachmentPanel( request, false ));
274 		responseEditorTabs.addTab( "HTTP Headers", createResponseHttpHeadersPanel() );
275 		String sslInfoTabTitle = "SSL Info";
276 		if( request.getResponse() != null && ((WsdlResponse)request.getResponse()).getSSLInfo() != null )
277 			sslInfoTabTitle += " (" + ((WsdlResponse)request.getResponse()).getSSLInfo().getPeerCertificates().length + " certs)";
278 		else
279 			sslInfoTabTitle += " (-)";
280 		
281 		responseEditorTabs.addTab( sslInfoTabTitle, createSSLInfoPanel() );
282 		responseEditorTabs.addChangeListener( new ChangeListener() {
283 
284 			public void stateChanged( ChangeEvent e )
285 			{
286 				SwingUtilities.invokeLater( new Runnable() {
287 
288 					public void run()
289 					{
290 						int ix = responseEditorTabs.getSelectedIndex();
291 						if( ix == 0 )
292 							responseEditor.requestFocus(); 
293 					}}  );
294 				
295 			}} );
296 		
297 		requestTabs = new JTabbedPane();
298 		requestTabs.addChangeListener( new ChangeListener() {
299 
300 			public void stateChanged( ChangeEvent e )
301 			{
302 				SwingUtilities.invokeLater( new Runnable() {
303 
304 					public void run()
305 					{
306 						int ix = requestTabs.getSelectedIndex();
307 						if( ix == 0 && requestEditorTabs.getSelectedIndex() == 0 )
308 							requestEditor.requestFocus(); 
309 						else if( ix == 1 && responseEditorTabs.getSelectedIndex() == 0 )
310 							responseEditor.requestFocus(); 
311 					}} );
312 			}} );
313 		
314 	   requestTabPanel = UISupport.createTabPanel( requestTabs, true );
315 	   
316 	   requestEditorTabPanel = UISupport.createTabPanel(requestEditorTabs, false);
317 		responseEditorTabPanel = UISupport.createTabPanel(responseEditorTabs, false);
318 
319 		if( request.getSettings().getBoolean( UISettings.START_WITH_REQUEST_TABS ))
320 	   {
321 	   	requestTabs.addTab( "Request", requestEditorTabPanel );
322 	   	requestTabs.addTab( "Response", responseEditorTabPanel );
323 	   	splitButton.setEnabled( false );
324 	   	tabsButton.setSelected( true );
325 	   	
326 	   	return requestTabPanel;
327 	   }
328 	   else
329 	   {
330 	   	requestSplitPane.setTopComponent(requestEditorTabPanel);
331 	   	requestSplitPane.setBottomComponent(responseEditorTabPanel);
332 	   	requestSplitPane.setDividerLocation(0.5);
333 	   	return requestSplitPane;
334 	   }
335 	}
336 
337 	private Component createSSLInfoPanel()
338 	{
339 		JPanel panel = new JPanel( new BorderLayout());
340 
341 		sslInfoPane = new JEditorPane();
342 		sslInfoPane.setEditorKit( new HTMLEditorKit() );
343 		panel.add( new JScrollPane( sslInfoPane ));
344 		
345 		return panel;
346 	}
347 
348 	private void updateSSLInfo( SSLInfo sslInfo )
349 	{
350 		String sslInfoTabTitle = "SSL Info";
351 		
352 		if( sslInfo == null )
353 		{
354 			sslInfoPane.setText( "<html><body>Not an SSL connection</body></html>" );
355 			sslInfoTabTitle += " (-)";
356 		}
357 		else
358 		{
359 			StringBuffer buf = new StringBuffer( "<html><body><table cellpadding=1 cellspacing=1 border=0>" );
360 			
361 			buf.append( "<tr><td><b>CipherSuite:</b></td><td align=left valign=top>" ).
362 				append( sslInfo.getCipherSuite().toString() ).append( "</td></tr>");
363 			
364 			if( sslInfo.getLocalPrincipal() != null )
365 				buf.append( "<tr><td><b>LocalPrincipal:</b></td><td align=left valign=top>" ).
366 					append( sslInfo.getLocalPrincipal().getName() ).append( "</td></tr>");
367 			
368 			Certificate[] localCertificates = sslInfo.getLocalCertificates();
369 			
370 			if( localCertificates != null)
371 			{
372 				buf.append( "</table><table cellpadding=0 cellspacing=0 border=0>" );
373 				
374 				int cnt = 1;
375 				for( Certificate cert : localCertificates )
376 				{
377 					buf.append( "<tr><td><b>Local Certificate " ).append( cnt++ ).
378 						append( ":</b><pre><font size=-1>" ).
379 						append( cert.toString() ).append( "</font></pre></td></tr>");
380 					
381 				}
382 				
383 				buf.append( "</table><table cellpadding=1 cellspacing=1 border=0>" );
384 			}
385 			
386 			if( sslInfo.getPeerPrincipal() != null )
387 				buf.append( "<tr><td><b>PeerPrincipal:</b></td><td align=left valign=top>" ).
388 					append( sslInfo.getPeerPrincipal().toString() ).append( "</td></tr>");
389 			
390 			Certificate[] peerCertificates = sslInfo.getPeerCertificates();
391 			if( peerCertificates != null)
392 			{
393 				buf.append( "</table><table cellpadding=0 cellspacing=0 border=0>" );
394 				
395 				int cnt = 1;
396 				for( Certificate cert : peerCertificates )
397 				{
398 					buf.append( "<tr><td colspan=2><b>Peer Certificate " ).append( cnt++ ).
399 						append( ":</b><pre><font size=-1>" ).
400 						append( cert.toString() ).append( "</font></pre></td></tr>");
401 				}
402 				
403 				buf.append( "</table><table cellpadding=0 cellspacing=0 border=0>" );
404 			}
405 			
406 			buf.append(  "</table></body></html>" );
407 			sslInfoPane.setText( buf.toString() );
408 			
409 			sslInfoTabTitle += " (" + sslInfo.getPeerCertificates().length + " certs)";
410 		}
411 		
412 		responseEditorTabs.setTitleAt( 3, sslInfoTabTitle );
413 	}
414 	
415 	private Component createResponseHttpHeadersPanel()
416 	{
417 		responseHeadersModel = new StringToStringMapTableModel( 
418 							request.getResponse() == null ? new StringToStringMap() : 
419 								request.getResponse().getResponseHeaders(), "Header", "Value", false );
420 		
421 		responseHeadersModel.addTableModelListener( new TableModelListener() 
422 		{
423 			public void tableChanged( TableModelEvent arg0 )
424 			{
425 				responseEditorTabs.setTitleAt( 2, "HTTP Headers (" + responseHeadersModel.getRowCount() + ")");
426 			}} );
427 		
428 		JTable responseHeadersTable = new JTable( responseHeadersModel );
429 		return new JScrollPane( responseHeadersTable );
430 	}
431 
432 	private Component createRequestHttpHeadersPanel()
433 	{
434 		requestHeadersModel = new StringToStringMapTableModel( request.getRequestHeaders(), "Header", "Value", true );
435 		requestHeadersModel.addTableModelListener( new TableModelListener() 
436 		{
437 			public void tableChanged( TableModelEvent arg0 )
438 			{
439 				getRequest().setRequestHeaders( requestHeadersModel.getData() );
440 				requestEditorTabs.setTitleAt( 2, "HTTP Headers (" + requestHeadersModel.getRowCount() + ")");
441 			}} );
442 		
443 		requestHeadersTable = new JTable( requestHeadersModel );
444 		JPanel panel = new JPanel( new BorderLayout() );
445 
446 		panel.add( new JScrollPane( requestHeadersTable ), BorderLayout.CENTER );
447 		
448 		ButtonBarBuilder builder = new ButtonBarBuilder();
449 		builder.addFixed( new JButton( new AbstractAction( "Add" ) {
450 
451 			public void actionPerformed( ActionEvent arg0 )
452 			{
453 				Object header = UISupport.prompt( "Specify name of header to add", "Add HTTP Header", "" );
454 				if( header != null )
455 				{
456 					requestHeadersModel.add( header.toString(), "" );
457 				}
458 			}} ));
459 		builder.addRelatedGap();
460 		builder.addFixed( new JButton( new AbstractAction("Remove" ){
461 
462 			public void actionPerformed( ActionEvent arg0 )
463 			{
464 				int row = requestHeadersTable.getSelectedRow();
465 				if( row != -1 && UISupport.confirm( "Delete selected header?", "Remove Header" ) )
466 				{
467 					requestHeadersModel.remove( row );
468 				}
469 			}} ));
470 		
471 		
472 		builder.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) );
473 		panel.add( builder.getPanel(), BorderLayout.SOUTH );
474 		
475 		return panel;
476 	}
477 
478 	protected SoapMessageXmlEditor buildResponseEditor()
479 	{
480 		return new WsdlResponseMessageEditor( new ResponseXmlDocument( request ));
481 	}
482 
483 	protected SoapMessageXmlEditor buildRequestEditor()
484 	{
485 		return new WsdlRequestMessageEditor( new RequestXmlDocument( request ));
486 	}
487 
488 	protected JComponent buildToolbar()
489 	{
490 		endpointCombo = new JComboBox(endpointsModel);
491 		endpointCombo.setToolTipText(endpointsModel.getSelectedItem().toString());
492 
493 		endpointCombo.addItemListener(new ItemListener()
494 		{
495 			public void itemStateChanged(ItemEvent e)
496 			{
497 				Object item = endpointCombo.getSelectedItem();
498 				if (item == null)
499 				{
500 					endpointCombo.setToolTipText("- no endpoint set for request -");
501 				}
502 				else
503 				{
504 					String selectedItem = item.toString();
505 					endpointCombo.setToolTipText(selectedItem);
506 				}
507 
508 				submitButton.setEnabled(submit == null && request.getEndpoint() != null
509 						&& request.getEndpoint().trim().length() > 0);
510 			}
511 		});
512 
513 		JXToolBar toolbar =  UISupport.createToolbar(); 
514 		
515 		toolbar.add( submitButton );
516 		insertButtons( toolbar );
517 		
518 		toolbar.add( addToMockServiceButton);
519 //		toolbar.add( addAsMockResponseStepButton);
520 		
521 		toolbar.add(recreateButton);
522 		toolbar.add(createEmptyButton);
523 		toolbar.add(cloneButton);
524 		toolbar.add(cancelButton);
525 		toolbar.addSeparator();
526 		toolbar.add(endpointCombo);
527 		
528 		toolbar.add( Box.createHorizontalGlue() );
529 		toolbar.add( tabsButton );
530 		toolbar.add(splitButton);
531 		toolbar.add(UISupport.createToolbarButton(new ShowOnlineHelpAction(getHelpUrl())));
532 		
533 		return toolbar;
534 	}
535 
536 	protected String getHelpUrl()
537 	{
538 		return HelpUrls.REQUESTEDITOR_HELP_URL;
539 	}
540 
541 	protected void insertButtons(JToolBar toolbar)
542 	{
543 	}
544 
545 	public void setEnabled(boolean enabled)
546 	{
547 		endpointCombo.setEnabled(enabled);
548 		requestEditor.setEditable(enabled);
549 		responseEditor.setEditable(enabled);
550 
551 		submitButton.setEnabled(enabled && request.getEndpoint() != null
552 				&& request.getEndpoint().trim().length() > 0);
553 		recreateButton.setEnabled(enabled);
554 		createEmptyButton.setEnabled(enabled);
555 		cloneButton.setEnabled(enabled);
556 		
557 		statusBar.setIndeterminate( !enabled );
558 	}
559 
560 	private final class AttachmentPropertyChangeListener implements PropertyChangeListener
561 	{
562 		public void propertyChange(PropertyChangeEvent evt)
563 		{
564 			if( evt.getPropertyName().equals( WsdlRequest.ATTACHMENTS_PROPERTY ))
565 			{
566 				requestEditorTabs.setTitleAt( 1, "Request Attachments (" + request.getAttachmentCount() + ")");
567 			}
568 			else if( evt.getPropertyName().equals( WsdlRequest.RESPONSE_PROPERTY ))
569 			{
570 				responseEditorTabs.setTitleAt( 1, "Response Attachments (" + (request.getResponse() == null ? 0 :
571 					request.getResponse().getAttachments().length) + ")" );
572 			}
573 		}
574 	}
575 	
576 	public class WsdlRequestMessageEditor extends RequestMessageXmlEditor<WsdlRequest>
577 	{
578 		public WsdlRequestMessageEditor(XmlDocument document)
579 		{
580 			super(document, request );
581 			
582 			XmlSourceEditorView editor = getSourceEditor();
583 			JXEditTextArea inputArea = editor.getInputArea();
584 
585 			inputArea.getInputHandler().addKeyBinding("A+ENTER", submitButton.getAction());
586 			inputArea.getInputHandler().addKeyBinding("A+X", cancelButton.getAction());
587 			inputArea.getInputHandler().addKeyBinding("AC+TAB", moveFocusAction);
588 			inputArea.getInputHandler().addKeyBinding("F5", recreateButton.getAction());
589 			inputArea.getInputHandler().addKeyBinding("C+F4", closePanelAction);
590 			
591 			inputArea.addFocusListener( new InputAreaFocusListener());
592 		}
593 	}
594 
595 	public class WsdlResponseMessageEditor extends ResponseMessageXmlEditor<WsdlRequest>
596 	{
597 		public WsdlResponseMessageEditor(XmlDocument document)
598 		{
599 			super(document, request );
600 		
601 			XmlSourceEditorView editor = getSourceEditor();
602 			
603 			JXEditTextArea inputArea = editor.getInputArea();
604 			inputArea.addFocusListener(new ResultAreaFocusListener());
605 			
606 			inputArea.getInputHandler().addKeyBinding("A+ENTER", submitButton.getAction());
607 			inputArea.getInputHandler().addKeyBinding("A+X", cancelButton.getAction());
608 			inputArea.getInputHandler().addKeyBinding("AC+TAB", moveFocusAction);
609 			inputArea.getInputHandler().addKeyBinding("C+F4", closePanelAction);
610 			
611 			JPopupMenu inputPopup = editor.getEditorPopup();
612 			inputPopup.insert( new JSeparator(), 2 );
613 			inputPopup.insert( wsiValidateAction, 3 );
614 		}
615 	}
616 	
617 	protected final class InputAreaFocusListener implements FocusListener
618 	{
619 		public void focusGained(FocusEvent e)
620 		{
621 			responseHasFocus = false;
622 			
623 			statusBar.setTarget( requestEditor.getSourceEditor().getInputArea() );
624 			if( !splitButton.isEnabled() )
625 			{
626 				requestTabs.setSelectedIndex( 0 );
627 				return;
628 			}
629 			
630 			if (getModelItem().getSettings().getBoolean(UISettings.NO_RESIZE_REQUEST_EDITOR))
631 				return;
632 
633 			// dont resize if split has been dragged
634 			if (((SoapUISplitPaneUI) requestSplitPane.getUI()).hasBeenDragged())
635 				return;
636 
637 			int pos = requestSplitPane.getDividerLocation();
638 			if (pos >= 600)
639 				return;
640 			if (requestSplitPane.getMaximumDividerLocation() > 700)
641 				requestSplitPane.setDividerLocation(600);
642 			else
643 				requestSplitPane.setDividerLocation(0.8);
644 		}
645 
646 		public void focusLost(FocusEvent e)
647 		{
648 		}
649 	}
650 
651 	protected final class ResultAreaFocusListener implements FocusListener
652 	{
653 		public void focusGained(FocusEvent e)
654 		{
655 			responseHasFocus = true;
656 			
657 			statusBar.setTarget( responseEditor.getSourceEditor().getInputArea() );
658 			if( !splitButton.isEnabled() )
659 			{
660 				requestTabs.setSelectedIndex( 1 );
661 				return;
662 			}
663 			
664 			if (request.getSettings().getBoolean(UISettings.NO_RESIZE_REQUEST_EDITOR))
665 				return;
666 
667 			// dont resize if split has been dragged or result is empty
668 			if (((SoapUISplitPaneUI) requestSplitPane.getUI()).hasBeenDragged() || request.getResponse() == null)
669 				return;
670 
671 			int pos = requestSplitPane.getDividerLocation();
672 			int maximumDividerLocation = requestSplitPane.getMaximumDividerLocation();
673 			if (pos + 600 < maximumDividerLocation)
674 				return;
675 
676 			if (maximumDividerLocation > 700)
677 				requestSplitPane.setDividerLocation(maximumDividerLocation - 600);
678 			else
679 				requestSplitPane.setDividerLocation(0.2);
680 		}
681 
682 		public void focusLost(FocusEvent e)
683 		{
684 		}
685 	}
686 
687 	public class SubmitAction extends AbstractAction
688 	{
689 		public SubmitAction()
690 		{
691 			putValue(Action.SMALL_ICON, UISupport.createImageIcon("/submit_request.gif"));
692 			putValue(Action.SHORT_DESCRIPTION, "Submit request to specified endpoint URL");
693 			putValue(Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "alt ENTER" ));
694 		}
695 
696 		public void actionPerformed(ActionEvent e)
697 		{
698 			if (submit != null && submit.getStatus() == Submit.Status.RUNNING)
699 			{
700 				if (UISupport.confirm("Cancel current request?", "Submit Request"))
701 				{
702 					submit.cancel();
703 				}
704 				else
705 					return;
706 			}
707 
708 			try
709 			{
710 				submit = doSubmit();
711 			}
712 			catch (SubmitException e1)
713 			{
714 				e1.printStackTrace();
715 			}
716 		}
717 	}
718 	
719 	protected Submit doSubmit() throws SubmitException
720 	{
721 		return request.submit(new WsdlSubmitContext(null), true);
722 	}
723 
724 	private class CancelAction extends AbstractAction
725 	{
726 		public CancelAction()
727 		{
728 			super();
729 			putValue(Action.SMALL_ICON, UISupport.createImageIcon("/cancel_request.gif"));
730 			putValue(Action.SHORT_DESCRIPTION, "Aborts ongoing request");
731 			putValue(Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "alt X" ));
732 		}
733 
734 		public void actionPerformed(ActionEvent e)
735 		{
736 			if (submit == null)
737 				return;
738 
739 			cancelButton.setEnabled(false);
740 			submit.cancel();
741 			setEnabled(true);
742 			submit = null;
743 		}
744 	}
745 
746 	private class ClosePanelAction extends AbstractAction
747 	{
748 		public void actionPerformed(ActionEvent e)
749 		{
750 			SoapUI.getDesktop().closeDesktopPanel(getModelItem());
751 		}
752 	}
753 
754 	private class MoveFocusAction extends AbstractAction
755 	{
756 		public void actionPerformed(ActionEvent e)
757 		{
758 			if (requestEditor.hasFocus())
759 			{
760 				responseEditor.requestFocus();
761 			}
762 			else
763 			{
764 				requestEditor.requestFocus();
765 			}
766 		}
767 	}
768 
769 	protected class InternalSubmitListener implements SubmitListener
770 	{
771 		protected InternalSubmitListener()
772 		{
773 		}
774 
775 		public boolean beforeSubmit(Submit submit, SubmitContext context)
776 		{
777 			if (submit.getRequest() != request )
778 				return true;
779 			
780 			if( getModelItem().getSettings().getBoolean( UISettings.AUTO_VALIDATE_REQUEST ))
781 			{
782 				boolean result = requestEditor.saveDocument( true );
783 				if( !result &&  getModelItem().getSettings().getBoolean( UISettings.ABORT_ON_INVALID_REQUEST ))
784 				{
785 					statusBar.setInfo( "Cancelled request due to invalid content" );
786 					return false;
787 				}
788 			}
789 			else requestEditor.saveDocument( false );
790 
791 			setEnabled( false );
792 			cancelButton.setEnabled( AbstractWsdlRequestDesktopPanel.this.submit != null );
793 			wsiValidateAction.setEnabled( false );
794 			return true;
795 		}
796 
797 		public void afterSubmit(Submit submit, SubmitContext context)
798 		{
799 			if (submit.getRequest() != request )
800 				return;
801 			
802 			Status status = submit.getStatus();
803 			WsdlResponse response = (WsdlResponse) submit.getResponse();
804 			if (status != Status.CANCELED )
805 			{
806 				request.setResponse(response, context);
807 			}
808 			
809 			cancelButton.setEnabled(false);
810 			setEnabled(true);
811 
812 			String message = null;
813 			String infoMessage = null;
814 			String requestName = request.getOperation().getInterface().getName() + "."
815 					+ request.getOperation().getName() + ":" + request.getName();
816 
817 			if (status == Status.CANCELED)
818 			{
819 				message = "CANCELED";
820 				infoMessage = "[" + requestName + "] - CANCELED";
821 			}
822 			else
823 			{
824 				if (status == Status.ERROR || response == null)
825 				{
826 					message = "Error getting response; " + submit.getError();
827 					infoMessage = "Error getting response for [" + requestName + "]; " + submit.getError();
828 				}
829 				else
830 				{
831 					message = "response time: " + response.getTimeTaken() + "ms (" + response.getContentLength() + " bytes)";
832 					infoMessage = "Got response for [" + requestName + "] in " + response.getTimeTaken() + "ms ("
833 							+ response.getContentLength() + " bytes)";
834 
835 					if( !splitButton.isEnabled() )
836 						requestTabs.setSelectedIndex( 1 );
837 					
838 					responseEditor.requestFocus();
839 				}
840 				
841 				responseHeadersModel.setData( submit.getResponse() == null ? null : submit.getResponse().getResponseHeaders());
842 				
843 				updateSSLInfo( response == null ? null : response.getSSLInfo() );
844 				wsiValidateAction.setEnabled( true );
845 			}
846 
847 			logMessages(message, infoMessage);
848 			
849 			if( getModelItem().getSettings().getBoolean( UISettings.AUTO_VALIDATE_RESPONSE ))
850 				responseEditor.getSourceEditor().validate();
851 
852 			AbstractWsdlRequestDesktopPanel.this.submit = null;
853 		}
854 
855 		protected void logMessages(String message, String infoMessage)
856 		{
857 			log.info(infoMessage);
858 			statusBar.setInfo(message);
859 		}
860 	}
861 
862 	public boolean onClose(boolean canCancel)
863 	{
864 		if (canCancel)
865 		{
866 			if (submit != null && submit.getStatus() == Submit.Status.RUNNING)
867 			{
868 				Boolean retVal = UISupport.confirmOrCancel("Cancel request before closing?", "Closing window");
869 				if (retVal == null)
870 					return false;
871 
872 				if (retVal.booleanValue() && submit.getStatus() == Submit.Status.RUNNING)
873 					submit.cancel();
874 			}
875 		}
876 		else if (submit != null && submit.getStatus() == Submit.Status.RUNNING)
877 		{
878 			submit.cancel();
879 		}
880 
881 		request.removeSubmitListener( internalSubmitListener );
882 		request.removePropertyChangeListener( attachmentsPropertyChangeListener );
883 		endpointsModel.release();
884 
885 		requestEditor.saveDocument( false );
886 		
887 		return true;
888 	}
889 
890 	public boolean dependsOn(ModelItem modelItem)
891 	{
892 		return modelItem == request || modelItem == request.getOperation()
893 				|| modelItem == request.getOperation().getInterface()
894 				|| modelItem == request.getOperation().getInterface().getProject();
895 	}
896 
897 	public String getDescription()
898 	{
899 		return "Request: [" + request.getName() + "] - " + request.getOperation().getInterface().getName() + 
900 		    "#" + request.getOperation().getName();
901 	}
902 	
903 	private final class ChangeToTabsAction extends AbstractAction
904 	{
905 		public ChangeToTabsAction()
906 		{
907 			putValue(Action.SMALL_ICON, UISupport.createImageIcon("/toggle_tabs.gif"));
908 			putValue(Action.SHORT_DESCRIPTION, "Toggles to tab-based layout");
909 		}
910 		
911 		public void actionPerformed(ActionEvent e)
912 		{
913 			if( splitButton.isEnabled() )
914 			{
915 				splitButton.setEnabled( false );
916 				removeContent( requestSplitPane );
917 				setContent( requestTabPanel );
918 				requestTabs.addTab( "Request", requestEditorTabPanel );
919 				requestTabs.addTab( "Response", responseEditorTabPanel );
920 				
921 				if( responseHasFocus )
922 				{
923 					requestTabs.setSelectedIndex( 1 );
924 					requestEditorTabs.requestFocus();
925 				}
926 				else
927 				{
928 					responseEditorTabs.requestFocus();
929 				}
930 			}
931 			else
932 			{
933 				int selectedIndex = requestTabs.getSelectedIndex();
934 				
935 				splitButton.setEnabled( true );
936 				removeContent( requestTabPanel );
937 				setContent( requestSplitPane );
938 				requestSplitPane.setTopComponent(requestEditorTabPanel);
939 		   	requestSplitPane.setBottomComponent(responseEditorTabPanel);
940 		   	requestSplitPane.setDividerLocation(0.5);
941 		   	
942 		   	if( selectedIndex == 0 )
943 		   		requestEditor.requestFocus();
944 		   	else
945 		   		responseEditor.requestFocus();
946 			}
947 			
948 			revalidate();
949 		}
950 	}
951 	
952 	public void setContent(JComponent content)
953 	{
954 		add( content, BorderLayout.CENTER );
955 	}
956 
957 	public void removeContent(JComponent content)
958 	{
959 		remove( content );
960 	}
961 }