View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2008 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl.panels.teststeps.support;
14  
15  import com.eviware.soapui.StandaloneSoapUICore;
16  import com.eviware.soapui.model.settings.Settings;
17  import com.eviware.soapui.model.settings.SettingsListener;
18  import com.eviware.soapui.settings.UISettings;
19  import com.eviware.soapui.support.DocumentListenerAdapter;
20  import com.eviware.soapui.support.UISupport;
21  import com.eviware.soapui.support.actions.FindAndReplaceDialog;
22  import com.eviware.soapui.support.actions.FindAndReplaceable;
23  import com.eviware.soapui.support.components.JEditorStatusBar.JEditorStatusBarTarget;
24  import com.eviware.soapui.support.swing.RSyntaxAreaPopupMenu;
25  import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
26  import org.fife.ui.rsyntaxtextarea.SyntaxScheme;
27  import org.fife.ui.rtextarea.LineNumberBorder;
28  import org.fife.ui.rtextarea.RTextScrollPane;
29  import org.syntax.jedit.KeywordMap;
30  import org.syntax.jedit.tokenmarker.GroovyTokenMarker;
31  import org.syntax.jedit.tokenmarker.Token;
32  
33  import javax.swing.*;
34  import javax.swing.event.CaretListener;
35  import javax.swing.text.Document;
36  import java.awt.*;
37  import java.awt.event.ActionEvent;
38  import java.awt.event.ActionListener;
39  import java.awt.event.FocusAdapter;
40  import java.awt.event.FocusEvent;
41  
42  /***
43   * Groovy editor wrapper
44   *
45   * @author ole.matzura
46   */
47  
48  public class GroovyEditor extends JPanel implements JEditorStatusBarTarget
49  {
50     private RSyntaxTextArea editArea;
51     private GroovyEditorModel model;
52     private InternalSettingsListener settingsListener;
53     private GroovyDocumentListener groovyDocumentListener;
54     private RTextScrollPane scrollPane;
55     private JCheckBoxMenuItem toggleLineNumbersMenuItem;
56     //private JPanel lineNumbersPanel;
57  
58     public GroovyEditor( GroovyEditorModel model )
59     {
60        super( new BorderLayout() );
61        this.model = model;
62  
63        Settings settings = model.getSettings();
64        Font editorFont = UISupport.getEditorFont( settings );
65  
66        editArea = new RSyntaxTextArea();
67        editArea.restoreDefaultSyntaxHighlightingColorScheme();
68  
69        setEditorFont( editorFont );
70  
71        editArea.setSyntaxEditingStyle( RSyntaxTextArea.GROOVY_SYNTAX_STYLE );
72        editArea.setBorder( BorderFactory.createMatteBorder( 0, 2, 0, 0, Color.WHITE ) );
73  
74        editArea.setText( model.getScript() );
75        editArea.setCaretPosition( 0 );
76        editArea.setCurrentLineHighlightEnabled( false );
77        Action runAction = model.getRunAction();
78        if( runAction != null )
79        {
80           editArea.getInputMap().put( KeyStroke.getKeyStroke( "alt ENTER" ), "run-action" );
81           editArea.getActionMap().put( "run-action", runAction );
82        }
83  
84        groovyDocumentListener = new GroovyDocumentListener();
85        editArea.getDocument().addDocumentListener( groovyDocumentListener );
86  
87        settingsListener = new InternalSettingsListener();
88        settings.addSettingsListener( settingsListener );
89  
90        scrollPane = new RTextScrollPane( 500, 300, editArea, true );
91        add( scrollPane );
92  
93        UISupport.addPreviewCorner( scrollPane, true );
94  
95        addFocusListener( new FocusAdapter()
96        {
97           public void focusGained( FocusEvent e )
98           {
99              editArea.requestFocusInWindow();
100          }
101       }
102       );
103 
104       RSyntaxAreaPopupMenu popup = RSyntaxAreaPopupMenu.add( editArea );
105       popup.add( new FindAndReplaceDialog( new RSyntaxTextAreaFindAndReplaceable() ) );
106       popup.addSeparator();
107       popup.add( new GoToLineAction() );
108 
109       toggleLineNumbersMenuItem = new JCheckBoxMenuItem( "Show Line Numbers", scrollPane.areLineNumbersEnabled() );
110       toggleLineNumbersMenuItem.setAccelerator( UISupport.getKeyStroke( "alt L" ) );
111       toggleLineNumbersMenuItem.addActionListener( new ActionListener()
112       {
113          public void actionPerformed( ActionEvent e )
114          {
115             enableLineNumbers( toggleLineNumbersMenuItem.isSelected() );
116          }
117       } );
118 
119       editArea.getInputMap().put( KeyStroke.getKeyStroke( "alt L" ), new AbstractAction()
120       {
121          public void actionPerformed( ActionEvent e )
122          {
123             enableLineNumbers( !scrollPane.areLineNumbersEnabled() );
124          }
125       } );
126 
127       popup.add( toggleLineNumbersMenuItem );
128       editArea.setComponentPopupMenu( popup );
129 
130       enableLineNumbers( settings.getBoolean( UISettings.SHOW_GROOVY_LINE_NUMBERS ) );
131    }
132 
133    public void enableLineNumbers( boolean enable )
134    {
135       scrollPane.setLineNumbersEnabled( enable );
136       try
137       {
138          if( scrollPane.areLineNumbersEnabled() )
139             ( (LineNumberBorder) scrollPane.getViewportBorder() ).setBackground( StandaloneSoapUICore.SoapUITheme.BACKGROUND_COLOR );
140       }
141       catch( Exception e )
142       {
143          e.printStackTrace();
144       }
145 
146       toggleLineNumbersMenuItem.setSelected( enable );
147    }
148 
149 //	private JComponent buildLineNumbers()
150 //	{
151 //		editArea.getInputHandler().addKeyBinding( "A+L", new ActionListener() {
152 //
153 //			public void actionPerformed( ActionEvent e )
154 //			{
155 //				lineNumbersPanel.setVisible( !lineNumbersPanel.isVisible() );
156 //				toggleLineNumbersMenuItem.setSelected( lineNumbersPanel.isVisible() );
157 //			}} );
158 //
159 //		lineNumbersPanel = new LineNumbersPanel( editArea );
160 //		return lineNumbersPanel;
161 //	}
162 
163    public RSyntaxTextArea getEditArea()
164    {
165       return editArea;
166    }
167 
168    public void release()
169    {
170       if( model != null )
171       {
172          model.getSettings().removeSettingsListener( settingsListener );
173       }
174       model = null;
175       editArea.getDocument().removeDocumentListener( groovyDocumentListener );
176 //		editArea.getInputHandler().removeAllKeyBindings();
177 //		editArea.getRightClickPopup().removeAll();
178 //		for( PopupMenuListener listener : editArea.getRightClickPopup().getPopupMenuListeners() )
179 //		{
180 //			editArea.getRightClickPopup().removePopupMenuListener( listener );
181 //		}
182    }
183 
184    public void selectError( String message )
185    {
186       int ix = message == null ? -1 : message.indexOf( "@ line " );
187       if( ix >= 0 )
188       {
189          try
190          {
191             int ix2 = message.indexOf( ',', ix );
192             int line = ix2 == -1 ? Integer.parseInt( message.substring( ix + 6 ).trim() ) : Integer.parseInt( message
193                     .substring( ix + 6, ix2 ).trim() );
194             int column = 0;
195             if( ix2 != -1 )
196             {
197                ix = message.indexOf( "column ", ix2 );
198                if( ix >= 0 )
199                {
200                   ix2 = message.indexOf( '.', ix );
201                   column = ix2 == -1 ? Integer.parseInt( message.substring( ix + 7 ).trim() ) : Integer
202                           .parseInt( message.substring( ix + 7, ix2 ).trim() );
203                }
204             }
205 
206             editArea.setCaretPosition( editArea.getLineStartOffset( line - 1 ) + column - 1 );
207          }
208          catch( Exception ex )
209          {
210          }
211 
212          editArea.requestFocus();
213       }
214    }
215 
216    private KeywordMap initKeywords()
217    {
218       KeywordMap keywords = GroovyTokenMarker.getKeywords();
219 
220       String[] kw = model.getKeywords();
221       if( kw != null )
222       {
223          for( String keyword : kw )
224             keywords.add( keyword, Token.KEYWORD2 );
225       }
226 
227       return keywords;
228    }
229 
230    private final class GroovyDocumentListener extends DocumentListenerAdapter
231    {
232       public void update( Document document )
233       {
234          GroovyEditor.this.model.setScript( editArea.getText() );
235       }
236    }
237 
238    private final class InternalSettingsListener implements SettingsListener
239    {
240       public void settingChanged( String name, String newValue, String oldValue )
241       {
242          if( name.equals( UISettings.EDITOR_FONT ) )
243          {
244             Font newFont = Font.decode( newValue );
245             setEditorFont( newFont );
246             invalidate();
247          }
248       }
249    }
250 
251    public void setEditorFont( Font newFont )
252    {
253       editArea.setFont( newFont );
254 
255       for( SyntaxScheme scheme : editArea.getSyntaxHighlightingColorScheme().syntaxSchemes )
256       {
257          if( scheme != null )
258          {
259             scheme.font = newFont;
260          }
261       }
262    }
263 
264    public void addCaretListener( CaretListener listener )
265    {
266       editArea.addCaretListener( listener );
267    }
268 
269    public int getCaretPosition()
270    {
271       return editArea.getCaretPosition();
272    }
273 
274    public int getLineOfOffset( int offset ) throws Exception
275    {
276       return editArea.getLineOfOffset( offset );
277    }
278 
279    public int getLineStartOffset( int line ) throws Exception
280    {
281       return editArea.getLineStartOffset( line );
282    }
283 
284    public void removeCaretListener( CaretListener listener )
285    {
286       editArea.removeCaretListener( listener );
287    }
288 
289    private final class GoToLineAction extends AbstractAction
290    {
291       public GoToLineAction()
292       {
293          super( "Go To Line" );
294          putValue( Action.SHORT_DESCRIPTION, "Moves the caret to the specified line" );
295          putValue( Action.ACCELERATOR_KEY, UISupport.getKeyStroke( "menu alt L" ) );
296       }
297 
298       public void actionPerformed( ActionEvent e )
299       {
300          String line = UISupport.prompt( "Enter line-number to (1.." + ( editArea.getLineCount() ) + ")", "Go To Line",
301                  String.valueOf( editArea.getCaretLineNumber() + 1 ) );
302 
303          if( line != null )
304          {
305             try
306             {
307                int ln = Integer.parseInt( line ) - 1;
308                if( ln >= 0 && ln < editArea.getLineCount() )
309                {
310                   editArea.scrollRectToVisible( editArea.modelToView( editArea.getLineStartOffset( ln ) ) );
311                   editArea.setCaretPosition( getLineStartOffset( ln ) );
312                }
313             }
314             catch( Exception e1 )
315             {
316             }
317          }
318       }
319    }
320 
321    private class RSyntaxTextAreaFindAndReplaceable implements FindAndReplaceable
322    {
323       public boolean isEditable()
324       {
325          return editArea.isEditable();
326       }
327 
328       public int getCaretPosition()
329       {
330          return editArea.getCaretPosition();
331       }
332 
333       public String getText()
334       {
335          return editArea.getText();
336       }
337 
338       public void select( int start, int end )
339       {
340          editArea.select( start, end );
341       }
342 
343       public int getSelectionStart()
344       {
345          return editArea.getSelectionStart();
346       }
347 
348       public int getSelectionEnd()
349       {
350          return editArea.getSelectionEnd();
351       }
352 
353       public void setSelectedText( String txt )
354       {
355          editArea.replaceSelection( txt );
356       }
357 
358       public String getSelectedText()
359       {
360          return editArea.getSelectedText();
361       }
362    }
363 }