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