View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 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 java.awt.BorderLayout;
16  import java.awt.Color;
17  import java.awt.Font;
18  import java.awt.event.ActionEvent;
19  import java.awt.event.ActionListener;
20  import java.awt.event.FocusAdapter;
21  import java.awt.event.FocusEvent;
22  
23  import javax.swing.BorderFactory;
24  import javax.swing.JCheckBoxMenuItem;
25  import javax.swing.JComponent;
26  import javax.swing.JPanel;
27  import javax.swing.event.CaretListener;
28  import javax.swing.text.Document;
29  
30  import org.syntax.jedit.KeywordMap;
31  import org.syntax.jedit.tokenmarker.CTokenMarker;
32  import org.syntax.jedit.tokenmarker.GroovyTokenMarker;
33  import org.syntax.jedit.tokenmarker.Token;
34  
35  import com.eviware.soapui.model.settings.Settings;
36  import com.eviware.soapui.model.settings.SettingsListener;
37  import com.eviware.soapui.settings.UISettings;
38  import com.eviware.soapui.support.DocumentListenerAdapter;
39  import com.eviware.soapui.support.UISupport;
40  import com.eviware.soapui.support.components.JEditorStatusBar.JEditorStatusBarTarget;
41  import com.eviware.soapui.support.swing.JXEditAreaPopupMenu;
42  import com.eviware.soapui.support.xml.JXEditTextArea;
43  
44  /***
45   * Groovy editor wrapper
46   * 
47   * @author ole.matzura
48   */
49  
50  public class GroovyEditor extends JPanel implements JEditorStatusBarTarget
51  {
52  	private JXEditTextArea editArea;
53  	private GroovyEditorModel model;
54  	private InternalSettingsListener settingsListener;
55  	private GroovyDocumentListener groovyDocumentListener;
56  	private JCheckBoxMenuItem toggleLineNumbersMenuItem;
57  	private JPanel lineNumbersPanel;
58  
59  	public GroovyEditor( GroovyEditorModel model )
60  	{
61  		super( new BorderLayout() );
62  		this.model = model;
63  		
64  		editArea = new JXEditTextArea( new CTokenMarker( false, initKeywords() ) );
65  		editArea.setBorder( BorderFactory.createMatteBorder( 0, 2, 0, 0, Color.WHITE) );
66  		
67  		Settings settings = model.getSettings();
68  		String editorFont = settings.getString( UISettings.EDITOR_FONT, UISettings.DEFAULT_EDITOR_FONT );
69  		if( editorFont != null && editorFont.length() > 0 )
70  			editArea.setFont(Font.decode(editorFont));
71  		else
72  			editArea.setFont( Font.decode( UISettings.DEFAULT_EDITOR_FONT ));
73  
74  		editArea.setText( model.getScript() );
75  		editArea.setCaretPosition(  0 );
76  		ActionListener runAction = model.getRunAction();
77  		if( runAction != null )
78  			editArea.getInputHandler().addKeyBinding( "A+ENTER", runAction );
79  		
80  		groovyDocumentListener = new GroovyDocumentListener();
81  		editArea.getDocument().addDocumentListener( groovyDocumentListener );
82  		
83  		settingsListener = new InternalSettingsListener();
84  		settings.addSettingsListener( settingsListener );
85  		
86  		add( editArea );
87  		add( buildLineNumbers(), BorderLayout.WEST );
88  		
89  		lineNumbersPanel.setVisible( settings.getBoolean( UISettings.SHOW_GROOVY_LINE_NUMBERS ) );
90  		
91  		addFocusListener( new FocusAdapter() {
92  
93  			public void focusGained( FocusEvent e )
94  			{
95  				editArea.requestFocusInWindow();
96  			}}
97  		);
98  		
99  		JXEditAreaPopupMenu popup = JXEditAreaPopupMenu.add( editArea );
100 		popup.add( editArea.getFindAndReplaceAction());
101 		popup.addSeparator();
102 		popup.add( editArea.getGoToLineAction() );
103 		toggleLineNumbersMenuItem = new JCheckBoxMenuItem( "Show Line Numbers", lineNumbersPanel.isVisible() );
104 		toggleLineNumbersMenuItem.setAccelerator( UISupport.getKeyStroke( "alt L" ) );
105 		toggleLineNumbersMenuItem.addActionListener( new ActionListener() {
106 
107 			public void actionPerformed( ActionEvent e )
108 			{
109 				lineNumbersPanel.setVisible( toggleLineNumbersMenuItem.isSelected() );
110 			}} );
111 		popup.add( toggleLineNumbersMenuItem );
112 	}
113 	
114 	private JComponent buildLineNumbers()
115 	{
116 		editArea.getInputHandler().addKeyBinding( "A+L", new ActionListener() {
117 
118 			public void actionPerformed( ActionEvent e )
119 			{
120 				lineNumbersPanel.setVisible( !lineNumbersPanel.isVisible() );
121 				toggleLineNumbersMenuItem.setSelected( lineNumbersPanel.isVisible() );
122 			}} );
123 		
124 		lineNumbersPanel = new LineNumbersPanel( editArea );
125 		return lineNumbersPanel;
126 	}
127 	
128 	public JXEditTextArea getEditArea()
129 	{
130 		return editArea;
131 	}
132 
133 	public void release()
134 	{
135 		model.getSettings().removeSettingsListener( settingsListener );
136 		model = null;
137 		editArea.getDocument().removeDocumentListener( groovyDocumentListener );
138 		editArea.getInputHandler().removeAllKeyBindings();
139 	}
140 
141 	public void selectError(String message)
142 	{
143 		int ix = message == null ? -1 : message.indexOf( "@ line " );
144 		if( ix >= 0 )
145 		{
146 			try
147 			{
148 				int ix2 = message.indexOf(',', ix);
149 				int line = ix2 == -1 ? Integer.parseInt(message.substring(ix + 6).trim()) : Integer.parseInt(message
150 						.substring(ix + 6, ix2).trim());
151 				int column = 0;
152 				if (ix2 != -1)
153 				{
154 					ix = message.indexOf("column ", ix2);
155 					if (ix >= 0)
156 					{
157 						ix2 = message.indexOf('.', ix);
158 						column = ix2 == -1 ? Integer.parseInt(message.substring(ix + 7).trim()) : Integer
159 								.parseInt(message.substring(ix + 7, ix2).trim());
160 					}
161 				}
162 				
163 				editArea.setCaretPosition(editArea.getLineStartOffset(line - 1) + column - 1);
164 			}
165 			catch (Exception ex)
166 			{
167 			}					
168 			
169 			editArea.requestFocus();
170 		}
171 	}
172 	
173 	private KeywordMap initKeywords()
174 	{
175 		KeywordMap keywords = GroovyTokenMarker.getKeywords();
176 		
177 		for( String keyword : model.getKeywords() )
178 			keywords.add(keyword,Token.KEYWORD2);
179 		return keywords;
180 	}
181 	
182 	private final class GroovyDocumentListener extends DocumentListenerAdapter
183 	{
184 		public void update(Document document)
185 		{
186 			GroovyEditor.this.model.setScript( editArea.getText() );
187 		}
188 	}
189 
190 	private final class InternalSettingsListener implements SettingsListener
191 	{
192 		public void settingChanged(String name, String newValue, String oldValue)
193 		{
194 			if( name.equals( UISettings.EDITOR_FONT ))
195 			{
196 				editArea.setFont( Font.decode( newValue ));
197 				invalidate();
198 			}
199 		}
200 	}
201 
202 	public void addCaretListener( CaretListener listener )
203 	{
204 		editArea.addCaretListener( listener );
205 	}
206 
207 	public int getCaretPosition()
208 	{
209 		return editArea.getCaretPosition();
210 	}
211 
212 	public int getLineOfOffset( int offset ) throws Exception
213 	{
214 		return editArea.getLineOfOffset( offset );
215 	}
216 
217 	public int getLineStartOffset( int line ) throws Exception
218 	{
219 		return editArea.getLineStartOffset( line );
220 	}
221 
222 	public void removeCaretListener( CaretListener listener )
223 	{
224 		editArea.removeCaretListener( listener );
225 	}
226 }