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