View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2008 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl.panels.mockoperation;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Dimension;
17  import java.awt.event.ActionEvent;
18  import java.awt.event.FocusAdapter;
19  import java.awt.event.FocusEvent;
20  import java.awt.event.FocusListener;
21  import java.beans.PropertyChangeEvent;
22  import java.beans.PropertyChangeListener;
23  
24  import javax.swing.AbstractAction;
25  import javax.swing.Action;
26  import javax.swing.BorderFactory;
27  import javax.swing.Box;
28  import javax.swing.JButton;
29  import javax.swing.JComponent;
30  import javax.swing.JPanel;
31  import javax.swing.JPopupMenu;
32  import javax.swing.JSeparator;
33  import javax.swing.JSplitPane;
34  import javax.swing.JTabbedPane;
35  import javax.swing.JToggleButton;
36  import javax.swing.JToolBar;
37  
38  import com.eviware.soapui.SoapUI;
39  import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
40  import com.eviware.soapui.impl.support.components.ModelItemXmlEditor;
41  import com.eviware.soapui.impl.support.components.RequestMessageXmlEditor;
42  import com.eviware.soapui.impl.support.components.ResponseMessageXmlEditor;
43  import com.eviware.soapui.impl.wsdl.actions.mockresponse.OpenRequestForMockResponseAction;
44  import com.eviware.soapui.impl.wsdl.mock.WsdlMockRequest;
45  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
46  import com.eviware.soapui.impl.wsdl.panels.mockoperation.actions.CreateEmptyMockResponseAction;
47  import com.eviware.soapui.impl.wsdl.panels.mockoperation.actions.CreateFaultMockResponseAction;
48  import com.eviware.soapui.impl.wsdl.panels.mockoperation.actions.RecreateMockResponseAction;
49  import com.eviware.soapui.impl.wsdl.panels.mockoperation.actions.WSIValidateResponseAction;
50  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
51  import com.eviware.soapui.model.ModelItem;
52  import com.eviware.soapui.model.mock.MockRunner;
53  import com.eviware.soapui.settings.UISettings;
54  import com.eviware.soapui.support.UISupport;
55  import com.eviware.soapui.support.action.swing.SwingActionDelegate;
56  import com.eviware.soapui.support.actions.ChangeSplitPaneOrientationAction;
57  import com.eviware.soapui.support.components.JEditorStatusBarWithProgress;
58  import com.eviware.soapui.support.components.JXToolBar;
59  import com.eviware.soapui.support.editor.views.xml.source.XmlSourceEditorView;
60  import com.eviware.soapui.support.editor.xml.XmlDocument;
61  import com.eviware.soapui.support.swing.SoapUISplitPaneUI;
62  import com.eviware.soapui.support.xml.JXEditTextArea;
63  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
64  
65  /***
66   * Abstract base DesktopPanel for WsdlMockResponses
67   * 
68   * @author Ole.Matzura
69   */
70  
71  public class AbstractWsdlMockResponseDesktopPanel<T extends ModelItem, T2 extends WsdlMockResponse> extends ModelItemDesktopPanel<T>
72  {
73  	//private final static Log log = Logger.getLogger(WsdlMockOperationDesktopPanel.class);
74  	private JEditorStatusBarWithProgress statusBar;
75  	private JButton splitButton;
76  	private MockRunner mockRunner;
77  	private JButton recreateButton;
78  	private JButton createEmptyButton;
79  	private JSplitPane requestSplitPane;
80  	private MoveFocusAction moveFocusAction;
81  	private ClosePanelAction closePanelAction = new ClosePanelAction();
82  
83  	private ModelItemXmlEditor<?,?> requestEditor;
84  	private ModelItemXmlEditor<?,?> responseEditor;
85  
86  	public AbstractAction wsiValidateAction;
87  
88  	private JTabbedPane requestTabs;
89  	private JPanel requestTabPanel;
90  	private JToggleButton tabsButton;
91  
92  	public boolean responseHasFocus;
93  
94  	private InternalPropertyChangeListener propertyChangeListener = new InternalPropertyChangeListener();
95  	private JButton createFaultButton;
96  	private T2 mockResponse;
97  	private JButton openRequestButton;
98  
99  	public AbstractWsdlMockResponseDesktopPanel(T modelItem)
100 	{
101 		super(modelItem);
102 	}
103 	
104 	protected void init( T2 mockResponse )
105 	{
106 		this.mockResponse = mockResponse;
107 		
108 		add(buildContent(), BorderLayout.CENTER);
109 		add(buildToolbar(), BorderLayout.NORTH);
110 		add(buildStatusLabel(), BorderLayout.SOUTH);
111 
112 		setPreferredSize(new Dimension(600, 500));
113 		
114 		mockResponse.addPropertyChangeListener( propertyChangeListener );
115 		
116 		addFocusListener( new FocusAdapter() {
117 
118 			@Override
119 			public void focusGained( FocusEvent e )
120 			{
121 				if( requestTabs.getSelectedIndex() == 1 || responseHasFocus )
122 					responseEditor.requestFocus();
123 				else
124 					requestEditor.requestFocus();
125 			}} );
126 	}
127 
128 	protected WsdlMockResponse getMockResponse()
129 	{
130 		return mockResponse;
131 	}
132 
133 	public final ModelItemXmlEditor<?,?> getRequestEditor()
134 	{
135 		return requestEditor;
136 	}
137 
138 	public final ModelItemXmlEditor<?,?> getResponseEditor()
139 	{
140 		return responseEditor;
141 	}
142 	
143 	public MockRunner getSubmit()
144 	{
145 		return mockRunner;
146 	}
147 
148 	protected JComponent buildStatusLabel()
149 	{
150 		statusBar = new JEditorStatusBarWithProgress();
151 		statusBar.setBorder( BorderFactory.createEmptyBorder( 1, 0, 0, 0 ));
152 		
153 		return statusBar;
154 	}
155 
156 	public JEditorStatusBarWithProgress getStatusBar()
157 	{
158 		return statusBar;
159 	}
160 
161 	@SuppressWarnings("unchecked")
162 	protected JComponent buildContent()
163 	{
164 		requestSplitPane = UISupport.createHorizontalSplit();
165 		requestSplitPane.setResizeWeight(0.5);
166 		requestSplitPane.setBorder(null);
167 		
168 		splitButton = createActionButton(new ChangeSplitPaneOrientationAction(requestSplitPane), true);
169 		
170 		tabsButton = new JToggleButton( new ChangeToTabsAction() );
171 		tabsButton.setPreferredSize( UISupport.TOOLBAR_BUTTON_DIMENSION );
172 		
173 		openRequestButton = createActionButton(
174 					SwingActionDelegate.createDelegate( OpenRequestForMockResponseAction.SOAPUI_ACTION_ID, mockResponse, null,
175 						"/open_request.gif"), true);
176 		
177 // TODO Ericsson: This was removed and replaced with "true" below.
178 		boolean bidirectional = mockResponse.getMockOperation().getOperation().isBidirectional();
179 		
180 		recreateButton = createActionButton(new RecreateMockResponseAction( mockResponse ), bidirectional);
181 		createEmptyButton = createActionButton(new CreateEmptyMockResponseAction(mockResponse), bidirectional);
182 		createFaultButton = createActionButton(new CreateFaultMockResponseAction(mockResponse), bidirectional);
183 
184 		moveFocusAction = new MoveFocusAction();
185 		wsiValidateAction = //new WSIValidateResponseAction( mockResponse );
186 			SwingActionDelegate.createDelegate( new WSIValidateResponseAction(), mockResponse, "alt W" ); 
187 
188 		requestEditor = buildRequestEditor();
189 		responseEditor = buildResponseEditor();
190 		
191 		requestTabs = new JTabbedPane();
192 	   requestTabPanel = UISupport.createTabPanel( requestTabs, true );
193 	   
194 		JComponent component = null;
195 		
196 		if( mockResponse.getSettings().getBoolean( UISettings.START_WITH_REQUEST_TABS ))
197 	   {
198 	   	requestTabs.addTab( "Last Request", requestEditor );
199 	   	requestTabs.addTab( "Mock Response", responseEditor );
200 	   	splitButton.setEnabled( false );
201 	   	tabsButton.setSelected( true );
202 	   	component = requestTabPanel;
203 	   	
204 	   	requestTabs.setSelectedIndex( 1 );
205 	   }
206 	   else
207 	   {
208 	   	requestSplitPane.setTopComponent(requestEditor);
209 	   	requestSplitPane.setBottomComponent(responseEditor);
210 	   	requestSplitPane.setDividerLocation(0.5);
211 	   	component = requestSplitPane;
212 	   }
213 		
214 		return component;
215 	}
216 
217 	protected ModelItemXmlEditor<?,?> buildResponseEditor()
218 	{
219 		return new WsdlMockResponseMessageEditor( new MockResponseXmlDocument( mockResponse ));
220 	}
221 
222 	protected ModelItemXmlEditor<?,?> buildRequestEditor()
223 	{
224 		return new WsdlMockRequestMessageEditor( new MockRequestXmlDocument( mockResponse ));
225 	}
226 
227 	protected JComponent buildToolbar()
228 	{
229 		JXToolBar toolbar =  UISupport.createToolbar(); 
230 		
231 		toolbar.add( openRequestButton);
232 		toolbar.addUnrelatedGap();
233 		toolbar.add(recreateButton);
234 		toolbar.add(createEmptyButton);
235 		toolbar.add(createFaultButton);
236 		
237 		createToolbar( toolbar );
238 		
239 		toolbar.add( Box.createHorizontalGlue() );
240 		toolbar.add( tabsButton );
241 		toolbar.add(splitButton);
242 		toolbar.add(UISupport.createToolbarButton(new ShowOnlineHelpAction(getHelpUrl())));
243 		
244 		return toolbar;
245 	}
246 
247 	protected void createToolbar( JXToolBar toolbar )
248 	{
249 	}
250 
251 	protected String getHelpUrl()
252 	{
253 		return HelpUrls.REQUESTEDITOR_HELP_URL;
254 	}
255 
256 	protected void insertButtons(JToolBar toolbar)
257 	{
258 	}
259 
260 	public void setEnabled(boolean enabled)
261 	{
262 		requestEditor.getSourceEditor().setEditable(enabled);
263 		responseEditor.getSourceEditor().setEditable(enabled);
264 		recreateButton.setEnabled(enabled);
265 		createEmptyButton.setEnabled(enabled);
266 		statusBar.setIndeterminate( !enabled );
267 	}
268 
269 	private final class InternalPropertyChangeListener implements PropertyChangeListener
270 	{
271 		public void propertyChange(PropertyChangeEvent evt)
272 		{
273 			if( evt.getPropertyName().equals( WsdlMockResponse.MOCKRESULT_PROPERTY ))
274 			{
275 				WsdlMockRequest mockRequest = mockResponse.getMockResult().getMockRequest();
276 				requestEditor.getDocument().setXml( mockRequest == null ? "" : mockRequest.getRequestContent());
277 				
278 				boolean bidirectional = mockResponse.getMockOperation().getOperation().isBidirectional();
279 				wsiValidateAction.setEnabled( bidirectional );  // TODO Ericsson: Had "true" here. Why?
280 			}
281 		}
282 	}
283 
284 	public class WsdlMockRequestMessageEditor extends RequestMessageXmlEditor<WsdlMockResponse,XmlDocument>
285 	{
286 		public WsdlMockRequestMessageEditor(XmlDocument document)
287 		{
288 			super(document, mockResponse);
289 		}
290 
291 		protected XmlSourceEditorView buildSourceEditor()
292 		{
293 			XmlSourceEditorView editor = getSourceEditor();
294 			JXEditTextArea inputArea = editor.getInputArea();
295 
296 			inputArea.addFocusListener(new InputAreaFocusListener());
297 			
298 			inputArea.getInputHandler().addKeyBinding("AC+TAB", moveFocusAction);
299 			inputArea.getInputHandler().addKeyBinding("F5", recreateButton.getAction());
300 			inputArea.getInputHandler().addKeyBinding("C+F4", closePanelAction);
301 
302 			return editor;
303 		}
304 	}
305 
306 	public class WsdlMockResponseMessageEditor extends ResponseMessageXmlEditor<WsdlMockResponse, XmlDocument>
307 	{
308 		public WsdlMockResponseMessageEditor(XmlDocument document)
309 		{
310 			super(document, mockResponse );
311 
312 			XmlSourceEditorView editor = getSourceEditor();
313 			
314 			if( getModelItem().getMockOperation().isBidirectional() )
315 			{
316 			   JXEditTextArea inputArea = editor.getInputArea();
317 			   inputArea.addFocusListener(new ResultAreaFocusListener());
318 			
319 			   inputArea.getInputHandler().addKeyBinding("AC+TAB", moveFocusAction);
320 			   inputArea.getInputHandler().addKeyBinding("C+F4", closePanelAction);
321 	
322 // TODO Ericsson: This if test was changed and moved up. Ok?		
323 //			if( !getModelItem().getMockOperation().isOneWay())
324 //			{
325 				JPopupMenu inputPopup = editor.getEditorPopup();
326 				inputPopup.insert( new JSeparator(), 2 );
327 				inputPopup.insert( wsiValidateAction, 3 );
328 			}
329 		}
330 	}
331 	
332 	protected final class InputAreaFocusListener implements FocusListener
333 	{
334 		public void focusGained(FocusEvent e)
335 		{
336 			responseHasFocus = false;
337 			
338 			statusBar.setTarget( requestEditor.getSourceEditor().getInputArea() );
339 			if( !splitButton.isEnabled() )
340 			{
341 				requestTabs.setSelectedIndex( 0 );
342 				return;
343 			}
344 			
345 			if (getModelItem().getSettings().getBoolean(UISettings.NO_RESIZE_REQUEST_EDITOR))
346 				return;
347 
348 			// dont resize if split has been dragged
349 			if (((SoapUISplitPaneUI) requestSplitPane.getUI()).hasBeenDragged())
350 				return;
351 
352 			int pos = requestSplitPane.getDividerLocation();
353 			if (pos >= 600)
354 				return;
355 			if (requestSplitPane.getMaximumDividerLocation() > 700)
356 				requestSplitPane.setDividerLocation(600);
357 			else
358 				requestSplitPane.setDividerLocation(0.8);
359 		}
360 
361 		public void focusLost(FocusEvent e)
362 		{
363 		}
364 	}
365 
366 	protected final class ResultAreaFocusListener implements FocusListener
367 	{
368 		public void focusGained(FocusEvent e)
369 		{
370 			responseHasFocus = true;
371 			
372 			statusBar.setTarget( responseEditor.getSourceEditor().getInputArea() );
373 			if( !splitButton.isEnabled() )
374 			{
375 				requestTabs.setSelectedIndex( 1 );
376 				return;
377 			}
378 			
379 			if (getModelItem().getSettings().getBoolean(UISettings.NO_RESIZE_REQUEST_EDITOR))
380 				return;
381 
382 			// dont resize if split has been dragged or result is empty
383 			if (((SoapUISplitPaneUI) requestSplitPane.getUI()).hasBeenDragged() )
384 				return;
385 
386 			int pos = requestSplitPane.getDividerLocation();
387 			int maximumDividerLocation = requestSplitPane.getMaximumDividerLocation();
388 			if (pos + 600 < maximumDividerLocation)
389 				return;
390 
391 			if (maximumDividerLocation > 700)
392 				requestSplitPane.setDividerLocation(maximumDividerLocation - 600);
393 			else
394 				requestSplitPane.setDividerLocation(0.2);
395 		}
396 
397 		public void focusLost(FocusEvent e)
398 		{
399 		}
400 	}
401 
402 	private class ClosePanelAction extends AbstractAction
403 	{
404 		public void actionPerformed(ActionEvent e)
405 		{
406 			SoapUI.getDesktop().closeDesktopPanel(getModelItem());
407 		}
408 	}
409 
410 	private class MoveFocusAction extends AbstractAction
411 	{
412 		public void actionPerformed(ActionEvent e)
413 		{
414 			if (requestEditor.hasFocus())
415 			{
416 				responseEditor.requestFocus();
417 			}
418 			else
419 			{
420 				requestEditor.requestFocus();
421 			}
422 		}
423 	}
424 
425 	public boolean dependsOn(ModelItem modelItem)
426 	{
427 		return modelItem == getModelItem() || modelItem == mockResponse.getMockOperation()
428 				|| modelItem == mockResponse.getMockOperation().getMockService()
429 				|| modelItem == mockResponse.getMockOperation().getMockService().getProject();
430 	}
431 
432 	private final class ChangeToTabsAction extends AbstractAction
433 	{
434 		public ChangeToTabsAction()
435 		{
436 			putValue(Action.SMALL_ICON, UISupport.createImageIcon("/toggle_tabs.gif"));
437 			putValue(Action.SHORT_DESCRIPTION, "Toggles to tab-based layout");
438 		}
439 		
440 		public void actionPerformed(ActionEvent e)
441 		{
442 			if( splitButton.isEnabled() )
443 			{
444 				splitButton.setEnabled( false );
445 				removeContent( requestSplitPane );
446 				setContent( requestTabPanel );
447 				requestTabs.addTab( "Last Request", requestEditor );
448 				requestTabs.addTab( "Mock Response", responseEditor );
449 			}
450 			else
451 			{
452 				int selectedIndex = requestTabs.getSelectedIndex();
453 				
454 				splitButton.setEnabled( true );
455 				removeContent( requestTabPanel );
456 				setContent( requestSplitPane );
457 				requestSplitPane.setTopComponent(requestEditor);
458 		   	requestSplitPane.setBottomComponent(responseEditor);
459 		   	requestSplitPane.setDividerLocation(0.5);
460 		   	
461 		   	if( selectedIndex == 0 )
462 		   		requestEditor.requestFocus();
463 		   	else
464 		   		responseEditor.requestFocus();
465 			}
466 			
467 			revalidate();
468 		}
469 	}
470 
471 	public void setContent(JComponent content)
472 	{
473 		add( content, BorderLayout.CENTER );
474 	}
475 
476 	public void removeContent(JComponent content)
477 	{
478 		remove( content );
479 	}
480 	
481 	public boolean onClose( boolean canCancel )
482 	{
483 		mockResponse.removePropertyChangeListener( propertyChangeListener );
484 		
485 		requestEditor.release();
486 		responseEditor.release();
487 		
488 		responseEditor.getParent().remove( responseEditor );
489 		responseEditor = null;
490 		requestEditor.getParent().remove( requestEditor );
491 		requestEditor = null;
492 		
493 		return release();
494 	}
495 }