PageRenderTime 47ms CodeModel.GetById 13ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

/bundles/plugins-trunk/SideKick/sidekick/SideKickActions.java

#
Java | 425 lines | 318 code | 51 blank | 56 comment | 91 complexity | c2a2b19e2f7295a31e89699e0b596b81 MD5 | raw file
  1/*
  2 * SideKickActions.java
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 2003, 2005 Slava Pestov
  7 *
  8 * This program is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU General Public License
 10 * as published by the Free Software Foundation; either version 2
 11 * of the License, or any later version.
 12 *
 13 * This program is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16 * GNU General Public License for more details.
 17 *
 18 * You should have received a copy of the GNU General Public License
 19 * along with this program; if not, write to the Free Software
 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 21 */
 22
 23package sidekick;
 24
 25//{{{ Import statements
 26import java.lang.ref.WeakReference;
 27import javax.swing.tree.*;
 28import javax.swing.Timer;
 29import java.awt.event.*;
 30
 31import org.gjt.sp.jedit.textarea.*;
 32import org.gjt.sp.jedit.*;
 33
 34//}}}
 35
 36// {{{ SideKickActions class
 37public class SideKickActions
 38{
 39	//{{{ Private members
 40	private static boolean completeDelay;
 41	private static boolean completeInstant;
 42	private static boolean autoCompletePopupGetFocus;
 43	private static int delay;
 44	private static WeakReference<JEditTextArea> delayedCompletionTarget;
 45	private static int caretWhenCompleteKeyPressed;
 46	private static Timer timer;
 47	private static SideKickCompletionPopup popup;
 48	//}}}
 49	//{{{ keyComplete() method
 50	public static void keyComplete(View view)
 51	{
 52		if(timer != null)
 53			timer.stop();
 54
 55		if(!completeInstant)
 56			return;
 57
 58		complete(view,COMPLETE_INSTANT_KEY);
 59	} //}}}
 60
 61	//{{{ keyCompleteWithDelay() method
 62	public static void keyCompleteWithDelay(View view)
 63	{
 64		if(!completeDelay)
 65			return;
 66
 67		if(timer != null)
 68			timer.stop();
 69
 70		JEditTextArea textArea = view.getTextArea();
 71		if (delayedCompletionTarget == null || delayedCompletionTarget.get() != textArea)
 72		{
 73			delayedCompletionTarget = new WeakReference<JEditTextArea>(textArea);
 74		}
 75		caretWhenCompleteKeyPressed = textArea.getCaretPosition();
 76
 77		if(timer == null)
 78		{
 79			timer = new Timer(0,new ActionListener()
 80			{
 81				public void actionPerformed(ActionEvent evt)
 82				{
 83					JEditTextArea textArea = delayedCompletionTarget.get();
 84					if(textArea != null
 85						&& caretWhenCompleteKeyPressed == textArea.getCaretPosition())
 86					{
 87						complete(textArea.getView(),COMPLETE_DELAY_KEY);
 88					}
 89				}
 90			});
 91
 92			timer.setInitialDelay(delay);
 93			timer.setRepeats(false);
 94		}
 95
 96		timer.start();
 97	} //}}}
 98
 99	//{{{ complete() method
100	public static final int COMPLETE_COMMAND = 0;
101	public static final int COMPLETE_DELAY_KEY = 1;
102	public static final int COMPLETE_INSTANT_KEY = 2;
103	public static String acceptChars;
104	public static String insertChars;
105
106	public static void complete(View view, int mode)
107	{
108		EditPane editPane = view.getEditPane();
109		Buffer buffer = editPane.getBuffer();
110		JEditTextArea textArea = editPane.getTextArea();
111
112		SideKickParser parser = SideKickPlugin
113			.getParserForBuffer(buffer);
114		SideKickParsedData data = SideKickParsedData
115			.getParsedData(view);
116
117		SideKickCompletion complete = null;
118
119		if(buffer.isEditable()
120			&& data != null && parser != null
121			&& parser.supportsCompletion())
122		{
123			complete = parser.complete(editPane,
124				textArea.getCaretPosition());
125		}
126
127		if(complete == null || complete.size() == 0)
128		{
129			if(mode == COMPLETE_INSTANT_KEY
130				|| mode == COMPLETE_DELAY_KEY)
131			{
132				// don't bother user with beep if eg
133				// they press < in XML mode
134				return;
135			}
136			else
137			{
138				view.getToolkit().beep();
139				return;
140			}
141		}
142		else if(complete.size() == 1)
143		{
144			// if user invokes complete explicitly, insert the
145			// completion immediately.
146			//
147			// if the user eg enters </ in XML mode, there will
148			// only be one completion and / is an instant complete
149			// key, so we insert it
150			if(mode == COMPLETE_COMMAND
151				|| mode == COMPLETE_INSTANT_KEY)
152			{
153				complete.insert(0);
154				return;
155			}
156		}
157
158		// show the popup if
159		// - complete has one element and user invoked with delay key
160		// - or complete has multiple elements
161		// and popup is not already shown because of explicit invocation
162		// of the complete action during the trigger delay
163		if(popup != null)
164			return;
165
166		boolean active = (mode == COMPLETE_COMMAND)
167			|| autoCompletePopupGetFocus;
168		popup = parser.getCompletionPopup(view,
169			textArea.getCaretPosition(), complete, active);
170		popup.addWindowListener(new WindowAdapter() {
171			public void windowClosed(WindowEvent e) {
172				popup = null;
173			}
174		});
175	} //}}}
176
177	//{{{ selectAsset() method
178	public static void selectAsset(View view)
179	{
180		SideKickParsedData data = SideKickParsedData.getParsedData(view);
181		if(data == null)
182		{
183			view.getToolkit().beep();
184			return;
185		}
186
187		JEditTextArea textArea = view.getTextArea();
188
189		IAsset asset = data.getAssetAtOffset(
190			textArea.getCaretPosition());
191
192		if(asset == null || asset.getEnd() == null)
193		{
194			view.getToolkit().beep();
195			return;
196		}
197
198		int pos = asset.getEnd().getOffset();
199		if (pos > textArea.getBuffer().getLength())
200		{
201		    view.getToolkit().beep();
202		    return;
203		}
204			
205		textArea.setCaretPosition(pos);
206		textArea.addToSelection(
207			new Selection.Range(
208				asset.getStart().getOffset(),
209				pos));
210	} //}}}
211
212	//{{{ narrowToAsset() method
213	public static void narrowToAsset(View view)
214	{
215		SideKickParsedData data = SideKickParsedData.getParsedData(view);
216		if(data == null)
217		{
218			view.getToolkit().beep();
219			return;
220		}
221
222		JEditTextArea textArea = view.getTextArea();
223
224		TreePath path = data.getTreePathForPosition(textArea.getCaretPosition());
225		if(path == null)
226		{
227			view.getToolkit().beep();
228			return;
229		}
230		IAsset asset = (IAsset)((DefaultMutableTreeNode)path
231			.getLastPathComponent()).getUserObject();
232
233		if(asset == null || asset.getEnd() == null)
234		{
235			view.getToolkit().beep();
236			return;
237		}
238
239		textArea.getDisplayManager().narrow(
240			textArea.getLineOfOffset(asset.getStart().getOffset()),
241			textArea.getLineOfOffset(asset.getStart().getOffset()));
242	} //}}}
243
244	//{{{ goToPrevAsset() method
245	public static void goToPrevAsset(View view)
246	{
247		SideKickParsedData data = SideKickParsedData.getParsedData(view);
248		if(data == null)
249		{
250			view.getToolkit().beep();
251			return;
252		}
253
254		JEditTextArea textArea = view.getTextArea();
255
256		int caret = textArea.getCaretPosition();
257		TreePath path = data.getTreePathForPosition(caret);
258		if(path == null)
259		{
260			view.getToolkit().beep();
261			return;
262		}
263
264		DefaultMutableTreeNode node = (DefaultMutableTreeNode)
265			path.getLastPathComponent();
266
267		// see if caret is at the end of a child of the current asset
268		for(int i = 0; i < node.getChildCount(); i++)
269		{
270			Object userObject = ((DefaultMutableTreeNode)node.getChildAt(i)).getUserObject();
271			if (userObject instanceof IAsset)
272			{
273				IAsset asset = (IAsset)userObject;
274				if(asset.getEnd() != null && caret == asset.getEnd().getOffset())
275				{
276					textArea.setCaretPosition(asset.getStart().getOffset());
277					return;
278				}
279			}
280		}
281
282		IAsset asset = ((IAsset)node.getUserObject());
283		if(caret == asset.getStart().getOffset())
284		{
285			DefaultMutableTreeNode parent = (DefaultMutableTreeNode)
286				node.getParent();
287			if (parent != null) 
288			{				
289				for(int i = 0; i < parent.getChildCount(); i++)
290				{
291					if(node == parent.getChildAt(i))
292					{
293						if(i == 0)
294						{
295							if(parent.getUserObject() instanceof IAsset)
296							{
297								textArea.setCaretPosition(
298									((IAsset)parent.getUserObject())
299									.getStart().getOffset());
300							}
301						}
302						else
303						{
304							Object child = ((DefaultMutableTreeNode)parent.getChildAt(i - 1)).getUserObject();
305							if (child instanceof IAsset) {
306								IAsset prevAsset = (IAsset)child;
307								if(prevAsset.getEnd() != null)
308									textArea.setCaretPosition(prevAsset.getEnd().getOffset());
309							}
310						}
311						return;
312					}
313				}
314			}
315		}
316		else
317			textArea.setCaretPosition(asset.getStart().getOffset());
318	} //}}}
319
320	//{{{ goToNextAsset() method
321	public static void goToNextAsset(View view)
322	{
323		SideKickParsedData data = SideKickParsedData.getParsedData(view);
324		if(data == null)
325		{
326			view.getToolkit().beep();
327			return;
328		}
329
330		JEditTextArea textArea = view.getTextArea();
331
332		int caret = textArea.getCaretPosition();
333		TreePath path = data.getTreePathForPosition(caret);
334		if(path == null)
335		{
336			view.getToolkit().beep();
337			return;
338		}
339
340		DefaultMutableTreeNode node = (DefaultMutableTreeNode)
341			path.getLastPathComponent();
342
343		// see if caret is at the end of a child of the current asset
344		for(int i = 0; i < node.getChildCount(); i++)
345		{
346			Object userObject = ((DefaultMutableTreeNode)node.getChildAt(i)).getUserObject();
347			if (userObject instanceof IAsset)
348			{
349				IAsset asset = (IAsset)userObject;
350				if(caret == asset.getEnd().getOffset())
351				{
352					if(i != node.getChildCount() - 1)
353					{
354						IAsset nextAsset = (IAsset)((DefaultMutableTreeNode)
355							node.getChildAt(i + 1)).getUserObject();
356						int offset = nextAsset.getStart().getOffset() >= textArea.getBufferLength() ? 
357							textArea.getBufferLength() - 1 :
358							nextAsset.getStart().getOffset();
359						textArea.setCaretPosition(offset);
360						return;
361					}
362					else
363						break;
364				}
365			}
366		}
367
368		int offset = ((IAsset)node.getUserObject()).getEnd().getOffset();
369		offset = offset >= textArea.getBufferLength() ? textArea.getBufferLength() - 1 : offset;
370		textArea.setCaretPosition(offset);
371	} //}}}
372
373	//{{{ propertiesChanged() method
374	public static void propertiesChanged()
375	{
376		completeDelay = jEdit.getBooleanProperty("sidekick.complete-delay.toggle");
377		completeInstant = jEdit.getBooleanProperty("sidekick.complete-instant.toggle");
378		autoCompletePopupGetFocus = jEdit.getBooleanProperty("sidekick.auto-complete-popup-get-focus");
379		acceptChars = MiscUtilities.escapesToChars(jEdit.getProperty("sidekick.complete-popup.accept-characters"));
380		insertChars = MiscUtilities.escapesToChars(jEdit.getProperty("sidekick.complete-popup.insert-characters"));
381		delay = jEdit.getIntegerProperty("sidekick.complete-delay",500);
382		if(timer != null)
383			timer.setInitialDelay(delay);
384	} //}}}
385
386	// {{{ SideKickAction class
387	abstract public static class SideKickAction extends EditAction 
388	{
389		protected String parserName;
390		protected SideKickAction(String actionName, String parserName) 
391		{
392			super(actionName, new Object[] {parserName} );
393			this.parserName = parserName;
394		}
395		
396	}// }}}
397
398	// {{{ ToggleParser class
399	/** An action which will always activate the SideKick parser,
400	 *  alternately selecting the default parser, and then the
401	 *  selected one, allowing you to toggle between say, Outline
402	 *  and Java parsers, XML and HTML, or Python and Jython parsers. 
403	 */
404	public static class ToggleParser extends SideKickAction 
405	{
406		public String getLabel() 
407		{
408			return parserName + " (Toggle)";
409		}
410		public ToggleParser(String parserName) 
411		{
412			super("sidekick.parser." + parserName + "-toggle", parserName);
413			this.parserName =parserName;
414		}
415		public String getCode() {
416			return "new sidekick.SideKickActions.ToggleAction(\"" + parserName + "\").invoke(view)";
417		}
418		public void invoke(View view)
419		{
420			
421			
422		}
423	} //}}}
424
425} // }}}