1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.panels.teststeps.support;
14
15 import java.awt.BorderLayout;
16 import java.awt.Color;
17 import java.awt.Dimension;
18 import java.awt.Font;
19 import java.awt.event.ActionEvent;
20 import java.awt.event.ActionListener;
21 import java.awt.event.FocusAdapter;
22 import java.awt.event.FocusEvent;
23 import java.beans.PropertyChangeEvent;
24 import java.beans.PropertyChangeListener;
25
26 import javax.swing.AbstractAction;
27 import javax.swing.Action;
28 import javax.swing.BorderFactory;
29 import javax.swing.JCheckBoxMenuItem;
30 import javax.swing.JPanel;
31 import javax.swing.KeyStroke;
32 import javax.swing.event.CaretListener;
33 import javax.swing.text.Document;
34
35 import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
36 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
37 import org.fife.ui.rtextarea.RTextScrollPane;
38
39 import com.eviware.soapui.impl.wsdl.WsdlProject;
40 import com.eviware.soapui.model.settings.Settings;
41 import com.eviware.soapui.model.settings.SettingsListener;
42 import com.eviware.soapui.model.support.ModelSupport;
43 import com.eviware.soapui.settings.UISettings;
44 import com.eviware.soapui.support.DocumentListenerAdapter;
45 import com.eviware.soapui.support.UISupport;
46 import com.eviware.soapui.support.actions.FindAndReplaceDialog;
47 import com.eviware.soapui.support.actions.FindAndReplaceable;
48 import com.eviware.soapui.support.components.JEditorStatusBar.JEditorStatusBarTarget;
49 import com.eviware.soapui.support.scripting.groovy.GroovyScriptEngineFactory;
50 import com.eviware.soapui.support.scripting.groovy.SoapUIGroovyScriptEngine;
51 import com.eviware.soapui.support.scripting.js.JsScriptEngineFactory;
52 import com.eviware.soapui.support.swing.RSyntaxAreaPopupMenu;
53
54 /***
55 * Groovy editor wrapper
56 *
57 * @author ole.matzura
58 */
59
60 public class GroovyEditor extends JPanel implements JEditorStatusBarTarget, PropertyChangeListener
61 {
62 private RSyntaxTextArea editArea;
63 private GroovyEditorModel model;
64 private InternalSettingsListener settingsListener;
65 private GroovyDocumentListener groovyDocumentListener;
66 private RTextScrollPane scrollPane;
67 private JCheckBoxMenuItem toggleLineNumbersMenuItem;
68 private boolean updating;
69
70
71
72 public GroovyEditor( GroovyEditorModel model )
73 {
74 super( new BorderLayout() );
75 this.model = model;
76
77 model.addPropertyChangeListener( this );
78
79 Settings settings = model.getSettings();
80 Font editorFont = UISupport.getEditorFont( settings );
81
82 editArea = new RSyntaxTextArea();
83 editArea.restoreDefaultSyntaxScheme();
84
85 String defaultScriptLanguage = ((WsdlProject)ModelSupport.getModelItemProject( model.getModelItem() )).getDefaultScriptLanguage();
86 if( defaultScriptLanguage.equals( GroovyScriptEngineFactory.ID ))
87 editArea.setSyntaxEditingStyle( SyntaxConstants.SYNTAX_STYLE_GROOVY );
88 else if( defaultScriptLanguage.equals( JsScriptEngineFactory.ID ))
89 editArea.setSyntaxEditingStyle( SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT );
90
91 editArea.setBorder( BorderFactory.createMatteBorder( 0, 2, 0, 0, Color.WHITE ) );
92
93 editArea.setText( model.getScript() );
94 editArea.setCaretPosition( 0 );
95 editArea.setHighlightCurrentLine( false );
96 Action runAction = model.getRunAction();
97 if( runAction != null )
98 {
99 editArea.getInputMap().put( KeyStroke.getKeyStroke( "alt ENTER" ), "run-action" );
100 editArea.getActionMap().put( "run-action", runAction );
101 }
102
103 editArea.getInputMap().put( KeyStroke.getKeyStroke( "F3" ), "find-action" );
104 editArea.getInputMap().put( KeyStroke.getKeyStroke( "ctrl F" ), "find-action" );
105 RSyntaxTextAreaFindAndReplaceable findAndReplaceable = new RSyntaxTextAreaFindAndReplaceable();
106 editArea.getActionMap().put( "find-action", new FindAndReplaceDialog( findAndReplaceable ) );
107
108 groovyDocumentListener = new GroovyDocumentListener();
109 editArea.getDocument().addDocumentListener( groovyDocumentListener );
110
111 settingsListener = new InternalSettingsListener();
112 settings.addSettingsListener( settingsListener );
113
114
115 scrollPane = new RTextScrollPane( editArea, true );
116 scrollPane.setPreferredSize(new Dimension(500, 300));
117 add( scrollPane );
118
119 UISupport.addPreviewCorner( scrollPane, true );
120
121 addFocusListener( new FocusAdapter()
122 {
123 public void focusGained( FocusEvent e )
124 {
125 editArea.requestFocusInWindow();
126 }
127 } );
128
129 RSyntaxAreaPopupMenu popup = RSyntaxAreaPopupMenu.add( editArea );
130 popup.add( new FindAndReplaceDialog( findAndReplaceable ) );
131 popup.addSeparator();
132 popup.add( new GoToLineAction() );
133
134 toggleLineNumbersMenuItem = new JCheckBoxMenuItem( "Show Line Numbers", scrollPane.getLineNumbersEnabled() );
135 toggleLineNumbersMenuItem.setAccelerator( UISupport.getKeyStroke( "alt L" ) );
136 toggleLineNumbersMenuItem.addActionListener( new ActionListener()
137 {
138 public void actionPerformed( ActionEvent e )
139 {
140 enableLineNumbers( toggleLineNumbersMenuItem.isSelected() );
141 }
142 } );
143
144 editArea.getInputMap().put( KeyStroke.getKeyStroke( "alt L" ), new AbstractAction()
145 {
146 public void actionPerformed( ActionEvent e )
147 {
148 enableLineNumbers( !scrollPane.getLineNumbersEnabled() );
149 }
150 } );
151
152 popup.add( toggleLineNumbersMenuItem );
153 editArea.setPopupMenu( popup );
154
155 enableLineNumbers( settings.getBoolean( UISettings.SHOW_GROOVY_LINE_NUMBERS ) );
156 }
157
158 @Override
159 public void setEnabled( boolean enabled )
160 {
161 super.setEnabled( enabled );
162
163 editArea.setEnabled( enabled );
164 }
165
166 public void enableLineNumbers( boolean enable )
167 {
168 scrollPane.setLineNumbersEnabled( enable );
169 try
170 {
171
172
173
174 }
175 catch( Exception e )
176 {
177 e.printStackTrace();
178 }
179
180 toggleLineNumbersMenuItem.setSelected( enable );
181 }
182
183 public RSyntaxTextArea getEditArea()
184 {
185 return editArea;
186 }
187
188 public void release()
189 {
190 if( model != null )
191 {
192 model.getSettings().removeSettingsListener( settingsListener );
193 model.removePropertyChangeListener( this );
194 }
195
196 model = null;
197 editArea.getDocument().removeDocumentListener( groovyDocumentListener );
198 }
199
200 public void selectError( String message )
201 {
202 int ix = message == null ? -1 : message.indexOf( "@ line " );
203 if( ix >= 0 )
204 {
205 try
206 {
207 int ix2 = message.indexOf( ',', ix );
208 int line = ix2 == -1 ? Integer.parseInt( message.substring( ix + 6 ).trim() ) : Integer.parseInt( message
209 .substring( ix + 6, ix2 ).trim() );
210 int column = 0;
211 if( ix2 != -1 )
212 {
213 ix = message.indexOf( "column ", ix2 );
214 if( ix >= 0 )
215 {
216 ix2 = message.indexOf( '.', ix );
217 column = ix2 == -1 ? Integer.parseInt( message.substring( ix + 7 ).trim() ) : Integer
218 .parseInt( message.substring( ix + 7, ix2 ).trim() );
219 }
220 }
221
222 editArea.setCaretPosition( editArea.getLineStartOffset( line - 1 ) + column - 1 );
223 }
224 catch( Exception ex )
225 {
226 }
227
228 editArea.requestFocus();
229 }
230 }
231
232 private final class GroovyDocumentListener extends DocumentListenerAdapter
233 {
234 public void update( Document document )
235 {
236 if( !updating )
237 {
238 GroovyEditor.this.model.setScript( editArea.getText() );
239 }
240 }
241 }
242
243 private final class InternalSettingsListener implements SettingsListener
244 {
245 public void settingChanged( String name, String newValue, String oldValue )
246 {
247 if( name.equals( UISettings.EDITOR_FONT ) )
248 {
249 Font newFont = Font.decode( newValue );
250 setEditorFont( newFont );
251 invalidate();
252 }
253 }
254
255 @Override
256 public void settingsReloaded()
257 {
258
259
260 }
261 }
262
263 public void setEditorFont( Font newFont )
264 {
265 editArea.setFont( newFont );
266 }
267
268 public void addCaretListener( CaretListener listener )
269 {
270 editArea.addCaretListener( listener );
271 }
272
273 public int getCaretPosition()
274 {
275 return editArea.getCaretPosition();
276 }
277
278 public int getLineOfOffset( int offset ) throws Exception
279 {
280 return editArea.getLineOfOffset( offset );
281 }
282
283 public int getLineStartOffset( int line ) throws Exception
284 {
285 return editArea.getLineStartOffset( line );
286 }
287
288 public void removeCaretListener( CaretListener listener )
289 {
290 editArea.removeCaretListener( listener );
291 }
292
293 private final class GoToLineAction extends AbstractAction
294 {
295 public GoToLineAction()
296 {
297 super( "Go To Line" );
298 putValue( Action.SHORT_DESCRIPTION, "Moves the caret to the specified line" );
299 putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "menu alt L" ) );
300 }
301
302 public void actionPerformed( ActionEvent e )
303 {
304 String line = UISupport.prompt( "Enter line-number to (1.." + ( editArea.getLineCount() ) + ")", "Go To Line",
305 String.valueOf( editArea.getCaretLineNumber() + 1 ) );
306
307 if( line != null )
308 {
309 try
310 {
311 int ln = Integer.parseInt( line ) - 1;
312 if( ln >= 0 && ln < editArea.getLineCount() )
313 {
314 editArea.scrollRectToVisible( editArea.modelToView( editArea.getLineStartOffset( ln ) ) );
315 editArea.setCaretPosition( getLineStartOffset( ln ) );
316 }
317 }
318 catch( Exception e1 )
319 {
320 }
321 }
322 }
323 }
324
325 private class RSyntaxTextAreaFindAndReplaceable implements FindAndReplaceable
326 {
327 public boolean isEditable()
328 {
329 return editArea.isEditable();
330 }
331
332 public int getCaretPosition()
333 {
334 return editArea.getCaretPosition();
335 }
336
337 public String getText()
338 {
339 return editArea.getText();
340 }
341
342 public void select( int start, int end )
343 {
344 editArea.select( start, end );
345 }
346
347 public int getSelectionStart()
348 {
349 return editArea.getSelectionStart();
350 }
351
352 public int getSelectionEnd()
353 {
354 return editArea.getSelectionEnd();
355 }
356
357 public void setSelectedText( String txt )
358 {
359 editArea.replaceSelection( txt );
360 }
361
362 public String getSelectedText()
363 {
364 return editArea.getSelectedText();
365 }
366 }
367
368 public void propertyChange( PropertyChangeEvent evt )
369 {
370 if( evt.getPropertyName().equals( "script" ))
371 {
372 updating = true;
373 editArea.setText( String.valueOf( evt.getNewValue() ));
374 updating = false;
375 }
376 }
377 }