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