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
256 public void setEditorFont( Font newFont )
257 {
258 editArea.setFont( newFont );
259 }
260
261 public void addCaretListener( CaretListener listener )
262 {
263 editArea.addCaretListener( listener );
264 }
265
266 public int getCaretPosition()
267 {
268 return editArea.getCaretPosition();
269 }
270
271 public int getLineOfOffset( int offset ) throws Exception
272 {
273 return editArea.getLineOfOffset( offset );
274 }
275
276 public int getLineStartOffset( int line ) throws Exception
277 {
278 return editArea.getLineStartOffset( line );
279 }
280
281 public void removeCaretListener( CaretListener listener )
282 {
283 editArea.removeCaretListener( listener );
284 }
285
286 private final class GoToLineAction extends AbstractAction
287 {
288 public GoToLineAction()
289 {
290 super( "Go To Line" );
291 putValue( Action.SHORT_DESCRIPTION, "Moves the caret to the specified line" );
292 putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "menu alt L" ) );
293 }
294
295 public void actionPerformed( ActionEvent e )
296 {
297 String line = UISupport.prompt( "Enter line-number to (1.." + ( editArea.getLineCount() ) + ")", "Go To Line",
298 String.valueOf( editArea.getCaretLineNumber() + 1 ) );
299
300 if( line != null )
301 {
302 try
303 {
304 int ln = Integer.parseInt( line ) - 1;
305 if( ln >= 0 && ln < editArea.getLineCount() )
306 {
307 editArea.scrollRectToVisible( editArea.modelToView( editArea.getLineStartOffset( ln ) ) );
308 editArea.setCaretPosition( getLineStartOffset( ln ) );
309 }
310 }
311 catch( Exception e1 )
312 {
313 }
314 }
315 }
316 }
317
318 private class RSyntaxTextAreaFindAndReplaceable implements FindAndReplaceable
319 {
320 public boolean isEditable()
321 {
322 return editArea.isEditable();
323 }
324
325 public int getCaretPosition()
326 {
327 return editArea.getCaretPosition();
328 }
329
330 public String getText()
331 {
332 return editArea.getText();
333 }
334
335 public void select( int start, int end )
336 {
337 editArea.select( start, end );
338 }
339
340 public int getSelectionStart()
341 {
342 return editArea.getSelectionStart();
343 }
344
345 public int getSelectionEnd()
346 {
347 return editArea.getSelectionEnd();
348 }
349
350 public void setSelectedText( String txt )
351 {
352 editArea.replaceSelection( txt );
353 }
354
355 public String getSelectedText()
356 {
357 return editArea.getSelectedText();
358 }
359 }
360
361 public void propertyChange( PropertyChangeEvent evt )
362 {
363 if( evt.getPropertyName().equals( "script" ))
364 {
365 updating = true;
366 editArea.setText( String.valueOf( evt.getNewValue() ));
367 updating = false;
368 }
369 }
370 }