1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.support.editor.views.xml.source;
14
15 import com.eviware.soapui.SoapUI;
16 import com.eviware.soapui.impl.wsdl.panels.teststeps.support.LineNumbersPanel;
17 import com.eviware.soapui.settings.UISettings;
18 import com.eviware.soapui.support.DocumentListenerAdapter;
19 import com.eviware.soapui.support.UISupport;
20 import com.eviware.soapui.support.components.PreviewCorner;
21 import com.eviware.soapui.support.editor.views.AbstractXmlEditorView;
22 import com.eviware.soapui.support.editor.xml.XmlDocument;
23 import com.eviware.soapui.support.editor.xml.XmlEditor;
24 import com.eviware.soapui.support.editor.xml.XmlLocation;
25 import com.eviware.soapui.support.editor.xml.support.ValidationError;
26 import com.eviware.soapui.support.swing.SoapUISplitPaneUI;
27 import com.eviware.soapui.support.xml.JXEditTextArea;
28 import com.eviware.soapui.support.xml.actions.FormatXmlAction;
29 import com.eviware.soapui.support.xml.actions.LoadXmlTextAreaAction;
30 import com.eviware.soapui.support.xml.actions.SaveXmlTextAreaAction;
31 import org.apache.xmlbeans.XmlError;
32 import org.apache.xmlbeans.XmlException;
33 import org.apache.xmlbeans.XmlObject;
34 import org.apache.xmlbeans.XmlOptions;
35
36 import javax.swing.*;
37 import javax.swing.text.Document;
38 import java.awt.*;
39 import java.awt.event.ActionEvent;
40 import java.awt.event.ActionListener;
41 import java.awt.event.MouseAdapter;
42 import java.awt.event.MouseEvent;
43 import java.beans.PropertyChangeListener;
44 import java.util.ArrayList;
45 import java.util.List;
46
47 /***
48 * Default "XML" source editor view in soapUI
49 *
50 * @author ole.matzura
51 */
52
53 public class XmlSourceEditorView extends AbstractXmlEditorView<XmlDocument> implements PropertyChangeListener
54 {
55 private JXEditTextArea editArea;
56 private ValidateMessageXmlAction validateXmlAction;
57 private JSplitPane splitter;
58 private JScrollPane errorScrollPane;
59 private DefaultListModel errorListModel;
60 private FormatXmlAction formatXmlAction;
61 private SaveXmlTextAreaAction saveXmlTextAreaAction;
62 private boolean updating;
63 private JPopupMenu editorPopup;
64 public boolean isLocating;
65 private JScrollPane editorScrollPane;
66 private LoadXmlTextAreaAction loadXmlTextAreaAction;
67 private JPopupMenu inputPopup;
68 private LineNumbersPanel lineNumbersPanel;
69 private JCheckBoxMenuItem toggleLineNumbersMenuItem;
70 private PreviewCorner previewCorner;
71
72 public XmlSourceEditorView( XmlEditor<XmlDocument> xmlEditor )
73 {
74 super( "XML", xmlEditor, XmlSourceEditorViewFactory.VIEW_ID );
75 }
76
77 protected void buildUI()
78 {
79 editArea = JXEditTextArea.createXmlEditor( false );
80 editArea.setMinimumSize(new Dimension(50, 50));
81 editArea.setCaretPosition(0);
82 editArea.setDiscardEditsOnSet(false);
83 editArea.setEnabled( false );
84 editArea.setBorder( BorderFactory.createMatteBorder( 0, 2, 0, 0, Color.WHITE) );
85
86 errorListModel = new DefaultListModel();
87 JList list = new JList(errorListModel);
88 list.addMouseListener(new ValidationListMouseAdapter(list, editArea));
89 errorScrollPane = new JScrollPane(list);
90 errorScrollPane.setVisible(false);
91
92 splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT)
93 {
94 public void requestFocus()
95 {
96 SwingUtilities.invokeLater( new Runnable() {
97
98 public void run()
99 {
100 editArea.requestFocusInWindow();
101 }} );
102 }
103
104 public boolean hasFocus()
105 {
106 return editArea.hasFocus();
107 }
108 };
109
110 splitter.setUI( new SoapUISplitPaneUI() );
111 splitter.setDividerSize( 0 );
112 splitter.setOneTouchExpandable( true );
113
114 lineNumbersPanel = new LineNumbersPanel( editArea );
115 lineNumbersPanel.setVisible( SoapUI.getSettings().getBoolean( UISettings.SHOW_XML_LINE_NUMBERS ) );
116
117 editorPopup = new JPopupMenu();
118 buildPopup( editorPopup, editArea );
119
120 editArea.setRightClickPopup(editorPopup);
121 editArea.getDocument().addDocumentListener(
122 new DocumentListenerAdapter() {
123
124 public void update(Document document)
125 {
126 if( !updating && getDocument() != null )
127 {
128 updating = true;
129 getDocument().setXml( editArea.getText());
130 updating = false;
131 }
132 }
133 });
134
135 editArea.getInputHandler().addKeyBinding("A+V", validateXmlAction);
136 editArea.getInputHandler().addKeyBinding("A+F", formatXmlAction);
137 editArea.getInputHandler().addKeyBinding("C+S", saveXmlTextAreaAction);
138 editArea.getInputHandler().addKeyBinding( "ALT+L", new ActionListener() {
139
140 public void actionPerformed( ActionEvent e )
141 {
142 lineNumbersPanel.setVisible( !lineNumbersPanel.isVisible() );
143 toggleLineNumbersMenuItem.setSelected( lineNumbersPanel.isVisible() );
144 }} );
145
146 JPanel p = new JPanel( new BorderLayout() );
147 p.add( editArea, BorderLayout.CENTER );
148 p.add( lineNumbersPanel, BorderLayout.WEST );
149
150 editorScrollPane = new JScrollPane(p);
151 splitter.setTopComponent(editorScrollPane);
152 splitter.setBottomComponent(errorScrollPane);
153 splitter.setDividerLocation(1.0);
154 splitter.setBorder(null);
155
156 previewCorner = UISupport.addPreviewCorner( getEditorScrollPane(), true );
157 }
158
159 public JScrollPane getEditorScrollPane()
160 {
161 return editorScrollPane;
162 }
163
164 protected void buildPopup(JPopupMenu inputPopup, JXEditTextArea editArea )
165 {
166 this.inputPopup = inputPopup;
167 validateXmlAction = new ValidateMessageXmlAction( );
168 formatXmlAction = new FormatXmlAction(editArea);
169 saveXmlTextAreaAction = new SaveXmlTextAreaAction( editArea, "Save" );
170 loadXmlTextAreaAction = new LoadXmlTextAreaAction( editArea, "Load" );
171
172 toggleLineNumbersMenuItem = new JCheckBoxMenuItem( "Show Line Numbers", lineNumbersPanel.isVisible());
173 toggleLineNumbersMenuItem.setAccelerator( UISupport.getKeyStroke( "alt L" ) );
174 toggleLineNumbersMenuItem.addActionListener( new ActionListener() {
175
176 public void actionPerformed( ActionEvent e )
177 {
178 lineNumbersPanel.setVisible( toggleLineNumbersMenuItem.isSelected() );
179 }} );
180
181 inputPopup.add(validateXmlAction);
182 inputPopup.add(formatXmlAction);
183 inputPopup.addSeparator();
184 inputPopup.add(editArea.getUndoAction());
185 inputPopup.add(editArea.getRedoAction());
186 inputPopup.add(editArea.createCopyAction());
187 inputPopup.add(editArea.createCutAction());
188 inputPopup.add(editArea.createPasteAction());
189 inputPopup.addSeparator();
190 inputPopup.add(editArea.getFindAndReplaceAction());
191 inputPopup.addSeparator();
192 inputPopup.add(editArea.getGoToLineAction());
193 inputPopup.add( toggleLineNumbersMenuItem );
194
195 inputPopup.addSeparator();
196 inputPopup.add(saveXmlTextAreaAction);
197 inputPopup.add(loadXmlTextAreaAction);
198 }
199
200 @Override
201 public void release()
202 {
203 super.release();
204 inputPopup.removeAll();
205 previewCorner.release();
206 }
207
208 private final static class ValidationListMouseAdapter extends MouseAdapter
209 {
210 private final JList list;
211
212 private final JXEditTextArea textArea;
213
214 public ValidationListMouseAdapter(JList list, JXEditTextArea textArea)
215 {
216 this.list = list;
217 this.textArea = textArea;
218 }
219
220 public void mouseClicked(MouseEvent e)
221 {
222 if (e.getClickCount() < 2)
223 return;
224
225 int ix = list.getSelectedIndex();
226 if (ix == -1)
227 return;
228
229 Object obj = list.getModel().getElementAt(ix);
230 if (obj instanceof ValidationError)
231 {
232 ValidationError error = (ValidationError) obj;
233 if (error.getLineNumber() >= 0)
234 {
235 textArea.setCaretPosition(textArea.getLineStartOffset(error
236 .getLineNumber() - 1));
237 textArea.requestFocus();
238 }
239 else
240 Toolkit.getDefaultToolkit().beep();
241 }
242 else
243 Toolkit.getDefaultToolkit().beep();
244 }
245 }
246
247 public JXEditTextArea getInputArea()
248 {
249 getComponent();
250 return editArea;
251 }
252
253 public void setEditable(boolean enabled)
254 {
255 getComponent();
256 editArea.setEditable( enabled );
257 }
258
259 protected ValidationError[] validateXml( String xml )
260 {
261 try
262 {
263 XmlObject.Factory.parse( xml, new XmlOptions().setLoadLineNumbers() );
264 }
265 catch( XmlException e )
266 {
267 List<ValidationError> result = new ArrayList<ValidationError>();
268
269 if( e.getErrors() != null )
270 {
271 for( Object error : e.getErrors())
272 {
273 if( error instanceof XmlError )
274 result.add( new com.eviware.soapui.model.testsuite.AssertionError( (XmlError) error ));
275 else
276 result.add( new com.eviware.soapui.model.testsuite.AssertionError( error.toString() ));
277 }
278 }
279
280 if( result.isEmpty())
281 result.add( new com.eviware.soapui.model.testsuite.AssertionError( e.toString() ));
282
283 return result.toArray( new ValidationError[result.size()] );
284 }
285
286 return null;
287 }
288
289 public class ValidateMessageXmlAction extends AbstractAction
290 {
291 public ValidateMessageXmlAction()
292 {
293 super( "Validate" );
294 putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "alt V" ));
295 }
296
297 public void actionPerformed(ActionEvent e)
298 {
299 if( validate())
300 UISupport.showInfoMessage( "Validation OK" );
301 }
302 }
303
304 public boolean activate(XmlLocation location)
305 {
306 super.activate( location );
307
308 if( location != null )
309 setLocation( location );
310
311 editArea.requestFocus();
312
313 return true;
314 }
315
316 public JComponent getComponent()
317 {
318 if( splitter == null )
319 buildUI();
320
321 return splitter;
322 }
323
324 public XmlLocation getEditorLocation()
325 {
326 return new XmlLocation( getCurrentLine()+1, getCurrentColumn() );
327 }
328
329 public void setLocation(XmlLocation location)
330 {
331 int line = location.getLine()-1;
332 if( location != null && line >= 0 )
333 {
334 int caretLine = editArea.getCaretLine();
335 int offset = editArea.getLineStartOffset( line );
336
337 try
338 {
339 editArea.setCaretPosition( offset + location.getColumn() );
340 int scrollLine = line + (line > caretLine ? 3 : -3);
341 if( scrollLine >= editArea.getLineCount() )
342 scrollLine = editArea.getLineCount()-1;
343 else if( scrollLine < 0 )
344 scrollLine = 0;
345
346 editArea.scrollTo( scrollLine, location.getColumn() );
347 }
348 catch( RuntimeException e )
349 {
350 }
351 }
352 }
353
354 public int getCurrentLine()
355 {
356 if( editArea == null )
357 return -1;
358 return editArea.getCaretLine();
359 }
360
361 public int getCurrentColumn()
362 {
363 if( editArea == null )
364 return -1;
365 return editArea.getCaretColumn();
366 }
367
368 public String getText()
369 {
370 if( editArea == null )
371 return null;
372 return editArea.getText();
373 }
374
375 public boolean validate()
376 {
377 ValidationError[] errors = validateXml( editArea.getText() );
378
379 errorListModel.clear();
380 if( errors == null || errors.length == 0 )
381 {
382 splitter.setDividerLocation( 1.0 );
383 splitter.setDividerSize( 0 );
384 errorScrollPane.setVisible( false );
385 return true;
386 }
387 else
388 {
389 Toolkit.getDefaultToolkit().beep();
390 for( int c = 0; c < errors.length; c++ )
391 {
392 errorListModel.addElement( errors[c] );
393 }
394 errorScrollPane.setVisible( true );
395 splitter.setDividerLocation( 0.8 );
396 splitter.setDividerSize( 10 );
397 return false;
398 }
399 }
400
401 public void setXml(String xml)
402 {
403 if( !updating )
404 {
405 updating = true;
406
407 if( xml == null )
408 {
409 editArea.setText( "" );
410 editArea.setEnabled( false );
411 }
412 else
413 {
414 int caretPosition = editArea.getCaretPosition();
415
416 editArea.setEnabled( true );
417 editArea.setText( xml );
418
419 editArea.setCaretPosition( caretPosition < xml.length() ? caretPosition : 0 );
420 }
421
422 updating = false;
423 }
424 }
425
426 public boolean saveDocument( boolean validate )
427 {
428 return validate ? validate() : true;
429 }
430
431 public void locationChanged(XmlLocation location)
432 {
433 isLocating = true;
434 setLocation( location );
435 isLocating = false;
436 }
437
438 public JPopupMenu getEditorPopup()
439 {
440 return editorPopup;
441 }
442
443 public boolean hasFocus()
444 {
445 return editArea.hasFocus();
446 }
447
448 public boolean isInspectable()
449 {
450 return true;
451 }
452
453 public ValidateMessageXmlAction getValidateXmlAction()
454 {
455 return validateXmlAction;
456 }
457 }