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.components.editor.views.source;
14  
15  import java.awt.Dimension;
16  import java.awt.Toolkit;
17  import java.awt.event.ActionEvent;
18  import java.awt.event.MouseAdapter;
19  import java.awt.event.MouseEvent;
20  import java.beans.PropertyChangeListener;
21  
22  import javax.swing.AbstractAction;
23  import javax.swing.Action;
24  import javax.swing.DefaultListModel;
25  import javax.swing.JComponent;
26  import javax.swing.JList;
27  import javax.swing.JPopupMenu;
28  import javax.swing.JScrollPane;
29  import javax.swing.JSplitPane;
30  import javax.swing.SwingUtilities;
31  import javax.swing.text.Document;
32  
33  import com.eviware.soapui.impl.wsdl.panels.request.components.editor.XmlEditor;
34  import com.eviware.soapui.impl.wsdl.panels.request.components.editor.XmlLocation;
35  import com.eviware.soapui.impl.wsdl.panels.request.components.editor.support.ValidationError;
36  import com.eviware.soapui.impl.wsdl.panels.request.components.editor.views.AbstractEditorView;
37  import com.eviware.soapui.support.DocumentListenerAdapter;
38  import com.eviware.soapui.support.UISupport;
39  import com.eviware.soapui.support.swing.SoapUISplitPaneUI;
40  import com.eviware.soapui.support.xml.JXEditTextArea;
41  import com.eviware.soapui.support.xml.actions.FormatXmlAction;
42  import com.eviware.soapui.support.xml.actions.LoadXmlTextAreaAction;
43  import com.eviware.soapui.support.xml.actions.SaveXmlTextAreaAction;
44  
45  /***
46   * Default "XML" source editor view in soapUI
47   * 
48   * @author ole.matzura
49   */
50  
51  public class XmlSourceEditorView extends AbstractEditorView implements PropertyChangeListener
52  {
53  	private JXEditTextArea editArea;
54  	private ValidateMessageXmlAction validateXmlAction;
55  	private JSplitPane splitter;
56  	private JScrollPane errorScrollPane;
57  	private DefaultListModel errorListModel;
58  	private FormatXmlAction formatXmlAction;
59  	private SaveXmlTextAreaAction saveXmlTextAreaAction;
60  	private boolean updating;
61  	private JPopupMenu editorPopup;
62  	public boolean isLocating;
63  	private JScrollPane editorScrollPane;
64  	private LoadXmlTextAreaAction loadXmlTextAreaAction;
65  	private JPopupMenu inputPopup;
66  
67  	public XmlSourceEditorView( XmlEditor xmlEditor )
68     {
69     	super( "XML", xmlEditor );
70     }
71  	
72  	protected void buildUI()
73  	{
74  		editArea = JXEditTextArea.createXmlEditor();
75  		editArea.setMinimumSize(new Dimension(50, 50));
76  		editArea.setCaretPosition(0);
77  		editArea.setDiscardEditsOnSet(false);
78  		editArea.setEnabled( false );
79  
80  		errorListModel = new DefaultListModel();
81  		JList list = new JList(errorListModel);
82  		list.addMouseListener(new ValidationListMouseAdapter(list, editArea));
83  		errorScrollPane = new JScrollPane(list);
84  		errorScrollPane.setVisible(false);
85  
86  		splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT)
87  		{
88  			public void requestFocus()
89  			{
90  				SwingUtilities.invokeLater( new Runnable() {
91  
92  					public void run()
93  					{
94  						editArea.requestFocusInWindow();
95  					}} );
96  			}
97  			
98  			public boolean hasFocus()
99  			{
100 				return editArea.hasFocus();
101 			}
102 		};
103 		
104 		splitter.setUI( new SoapUISplitPaneUI() );
105 		splitter.setDividerSize( 0 );
106 		splitter.setOneTouchExpandable( true );
107       
108 		editorPopup = new JPopupMenu();
109 		buildPopup( editorPopup, editArea );	
110 		
111 		editArea.setRightClickPopup(editorPopup);
112 		editArea.getDocument().addDocumentListener(
113 				new DocumentListenerAdapter() {
114 
115 					public void update(Document document) 
116 					{
117 						if( !updating && getXmlDocument() != null )
118 						{
119 							updating = true;
120 							getXmlDocument().setXml( editArea.getText());
121 							updating = false;
122 						}
123 					}
124 				});
125 
126 		editArea.getInputHandler().addKeyBinding("A+V", validateXmlAction);
127 		editArea.getInputHandler().addKeyBinding("A+F", formatXmlAction);
128 		editArea.getInputHandler().addKeyBinding("C+S", saveXmlTextAreaAction);
129 		
130 		editorScrollPane = new JScrollPane(editArea);
131 		splitter.setTopComponent(editorScrollPane);
132 		splitter.setBottomComponent(errorScrollPane);
133 		splitter.setDividerLocation(1.0);
134 		splitter.setBorder(null);
135 	}
136 
137 	public JScrollPane getEditorScrollPane()
138 	{
139 		return editorScrollPane;
140 	}
141 
142 	protected void buildPopup(JPopupMenu inputPopup, JXEditTextArea editArea )
143 	{
144 		this.inputPopup = inputPopup;
145 		validateXmlAction = new ValidateMessageXmlAction( );
146 		formatXmlAction = new FormatXmlAction(editArea);
147 		saveXmlTextAreaAction = new SaveXmlTextAreaAction( editArea, "Save" );
148 		loadXmlTextAreaAction = new LoadXmlTextAreaAction( editArea, "Load" );
149 		
150 		inputPopup.add(validateXmlAction);
151 		inputPopup.add(formatXmlAction);
152 		inputPopup.addSeparator();
153 		inputPopup.add(editArea.getUndoAction());
154 		inputPopup.add(editArea.getRedoAction());
155 		inputPopup.add(editArea.createCopyAction());
156 		inputPopup.add(editArea.createCutAction());
157 		inputPopup.add(editArea.createPasteAction());
158 		inputPopup.addSeparator();
159 		inputPopup.add(editArea.getFindAndReplaceAction());
160 		inputPopup.addSeparator(); 
161 		inputPopup.add(saveXmlTextAreaAction);
162 		inputPopup.add(loadXmlTextAreaAction);
163 	}
164 	
165 	@Override
166 	public void release()
167 	{
168 		super.release();
169 		inputPopup.removeAll();
170 	}
171 
172 	private final static class ValidationListMouseAdapter extends MouseAdapter 
173 	{
174 		private final JList list;
175 
176 		private final JXEditTextArea textArea;
177 
178 		public ValidationListMouseAdapter(JList list, JXEditTextArea textArea) 
179 		{
180 			this.list = list;
181 			this.textArea = textArea;
182 		}
183 
184 		public void mouseClicked(MouseEvent e) 
185 		{
186 			if (e.getClickCount() < 2)
187 				return;
188 
189 			int ix = list.getSelectedIndex();
190 			if (ix == -1)
191 				return;
192 
193 			Object obj = list.getModel().getElementAt(ix);
194 			if (obj instanceof ValidationError) 
195 			{
196 				ValidationError error = (ValidationError) obj;
197 				if (error.getLineNumber() >= 0) 
198 				{
199 					textArea.setCaretPosition(textArea.getLineStartOffset(error
200 							.getLineNumber() - 1));
201 					textArea.requestFocus();
202 				} 
203 				else
204 					Toolkit.getDefaultToolkit().beep();
205 			} 
206 			else
207 				Toolkit.getDefaultToolkit().beep();
208 		}
209 	}
210 
211 	public JXEditTextArea getInputArea()
212 	{
213 		getComponent();
214 		return editArea;
215 	}
216 
217 	public void setEditable(boolean enabled)
218 	{
219 		getComponent();
220 	   editArea.setEditable( enabled );	
221 	}
222 
223 	protected ValidationError[] validateXml( String xml )
224 	{
225 		return null;
226 	}
227 	
228 	public class ValidateMessageXmlAction extends AbstractAction
229 	{
230 		public ValidateMessageXmlAction()
231 		{
232 			super( "Validate" );
233 			putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "alt V" ));
234 		}
235 
236 		public void actionPerformed(ActionEvent e)
237 		{
238 			if( validate())
239 				UISupport.showInfoMessage( "Validation OK" ); 
240 		}
241 	}
242 
243    public boolean activate(XmlLocation location)
244 	{
245    	super.activate( location );
246    	
247    	if( location != null )
248    		setLocation( location );
249    	
250    	editArea.requestFocus();
251    	
252    	return true;
253 	}
254 
255 	public JComponent getComponent()
256 	{
257 		if( splitter == null )
258 			buildUI();
259 		
260 		return splitter;
261 	}
262 	
263 	public XmlLocation getLocation()
264 	{
265 		return new XmlLocation( getCurrentLine(), getCurrentColumn() );
266 	}
267 	
268 	public void setLocation(XmlLocation location)
269 	{
270 		if( location != null && location.getLine() >= 0 )
271 		{
272 			int offset = editArea.getLineStartOffset( location.getLine() );
273 			try
274 			{
275 				editArea.setCaretPosition( offset + location.getColumn() );
276 			}
277 			catch( RuntimeException e )
278 			{
279 			}
280 		}
281 	}
282 
283 	public int getCurrentLine()
284 	{
285 		if( editArea == null )
286 			return -1;
287 		return editArea.getCaretLine();
288 	}
289 	
290 	public int getCurrentColumn()
291 	{
292 		if( editArea == null )
293 			return -1;
294 		return editArea.getCaretColumn();
295 	}
296 
297 	public String getText()
298 	{
299 		if( editArea == null )
300 			return null;
301 		return editArea.getText();
302 	}
303 
304 	public boolean validate()
305 	{
306 		ValidationError[] errors = validateXml( editArea.getText() );
307 		
308 		errorListModel.clear();
309 		if( errors == null || errors.length == 0 )
310 		{
311 			splitter.setDividerLocation( 1.0 );
312 			splitter.setDividerSize( 0 );
313 		   errorScrollPane.setVisible( false );
314 		   return true;
315 		}
316 		else
317 		{
318 			Toolkit.getDefaultToolkit().beep();
319 		   for( int c = 0; c < errors.length; c++ )
320 		   {
321 		   	errorListModel.addElement( errors[c] );
322 		   }
323 		   errorScrollPane.setVisible( true );
324 		   splitter.setDividerLocation( 0.8 );
325 		   splitter.setDividerSize( 10 );
326 		   return false;
327 		}
328 	}
329 
330 	protected void setXml(String xml)
331 	{
332 		if( !updating )
333 		{
334 			updating = true;
335 			
336 			if( xml == null )
337 			{
338 				editArea.setText( "" );
339 				editArea.setEnabled( false );
340 			}
341 			else
342 			{
343 				editArea.setEnabled( true );
344 				editArea.setText( xml );
345 				editArea.setCaretPosition( 0 );
346 			}
347 			
348 			updating = false;
349 		}
350 	}
351 	
352 	public boolean saveDocument( boolean validate )
353 	{
354 		return validate ? validate() : true;
355 	}
356 	
357 	public void locationChanged(XmlLocation location)
358 	{
359 		isLocating = true;
360 		setLocation( location );
361 		isLocating = false;
362 	}
363 
364 	public JPopupMenu getEditorPopup()
365 	{
366 		return editorPopup;
367 	}
368 
369 	public boolean hasFocus()
370 	{
371 		return editArea.hasFocus();
372 	}
373 	
374 	public boolean isInspectable()
375 	{
376 		return true;
377 	}
378 
379 	public String getViewId()
380 	{
381 		return XmlSourceEditorFactory.VIEW_ID;
382 	}
383 }