PageRenderTime 48ms CodeModel.GetById 23ms RepoModel.GetById 0ms 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
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  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. package sidekick;
  23. //{{{ Import statements
  24. import java.lang.ref.WeakReference;
  25. import javax.swing.tree.*;
  26. import javax.swing.Timer;
  27. import java.awt.event.*;
  28. import org.gjt.sp.jedit.textarea.*;
  29. import org.gjt.sp.jedit.*;
  30. //}}}
  31. // {{{ SideKickActions class
  32. public class SideKickActions
  33. {
  34. //{{{ Private members
  35. private static boolean completeDelay;
  36. private static boolean completeInstant;
  37. private static boolean autoCompletePopupGetFocus;
  38. private static int delay;
  39. private static WeakReference<JEditTextArea> delayedCompletionTarget;
  40. private static int caretWhenCompleteKeyPressed;
  41. private static Timer timer;
  42. private static SideKickCompletionPopup popup;
  43. //}}}
  44. //{{{ keyComplete() method
  45. public static void keyComplete(View view)
  46. {
  47. if(timer != null)
  48. timer.stop();
  49. if(!completeInstant)
  50. return;
  51. complete(view,COMPLETE_INSTANT_KEY);
  52. } //}}}
  53. //{{{ keyCompleteWithDelay() method
  54. public static void keyCompleteWithDelay(View view)
  55. {
  56. if(!completeDelay)
  57. return;
  58. if(timer != null)
  59. timer.stop();
  60. JEditTextArea textArea = view.getTextArea();
  61. if (delayedCompletionTarget == null || delayedCompletionTarget.get() != textArea)
  62. {
  63. delayedCompletionTarget = new WeakReference<JEditTextArea>(textArea);
  64. }
  65. caretWhenCompleteKeyPressed = textArea.getCaretPosition();
  66. if(timer == null)
  67. {
  68. timer = new Timer(0,new ActionListener()
  69. {
  70. public void actionPerformed(ActionEvent evt)
  71. {
  72. JEditTextArea textArea = delayedCompletionTarget.get();
  73. if(textArea != null
  74. && caretWhenCompleteKeyPressed == textArea.getCaretPosition())
  75. {
  76. complete(textArea.getView(),COMPLETE_DELAY_KEY);
  77. }
  78. }
  79. });
  80. timer.setInitialDelay(delay);
  81. timer.setRepeats(false);
  82. }
  83. timer.start();
  84. } //}}}
  85. //{{{ complete() method
  86. public static final int COMPLETE_COMMAND = 0;
  87. public static final int COMPLETE_DELAY_KEY = 1;
  88. public static final int COMPLETE_INSTANT_KEY = 2;
  89. public static String acceptChars;
  90. public static String insertChars;
  91. public static void complete(View view, int mode)
  92. {
  93. EditPane editPane = view.getEditPane();
  94. Buffer buffer = editPane.getBuffer();
  95. JEditTextArea textArea = editPane.getTextArea();
  96. SideKickParser parser = SideKickPlugin
  97. .getParserForBuffer(buffer);
  98. SideKickParsedData data = SideKickParsedData
  99. .getParsedData(view);
  100. SideKickCompletion complete = null;
  101. if(buffer.isEditable()
  102. && data != null && parser != null
  103. && parser.supportsCompletion())
  104. {
  105. complete = parser.complete(editPane,
  106. textArea.getCaretPosition());
  107. }
  108. if(complete == null || complete.size() == 0)
  109. {
  110. if(mode == COMPLETE_INSTANT_KEY
  111. || mode == COMPLETE_DELAY_KEY)
  112. {
  113. // don't bother user with beep if eg
  114. // they press < in XML mode
  115. return;
  116. }
  117. else
  118. {
  119. view.getToolkit().beep();
  120. return;
  121. }
  122. }
  123. else if(complete.size() == 1)
  124. {
  125. // if user invokes complete explicitly, insert the
  126. // completion immediately.
  127. //
  128. // if the user eg enters </ in XML mode, there will
  129. // only be one completion and / is an instant complete
  130. // key, so we insert it
  131. if(mode == COMPLETE_COMMAND
  132. || mode == COMPLETE_INSTANT_KEY)
  133. {
  134. complete.insert(0);
  135. return;
  136. }
  137. }
  138. // show the popup if
  139. // - complete has one element and user invoked with delay key
  140. // - or complete has multiple elements
  141. // and popup is not already shown because of explicit invocation
  142. // of the complete action during the trigger delay
  143. if(popup != null)
  144. return;
  145. boolean active = (mode == COMPLETE_COMMAND)
  146. || autoCompletePopupGetFocus;
  147. popup = parser.getCompletionPopup(view,
  148. textArea.getCaretPosition(), complete, active);
  149. popup.addWindowListener(new WindowAdapter() {
  150. public void windowClosed(WindowEvent e) {
  151. popup = null;
  152. }
  153. });
  154. } //}}}
  155. //{{{ selectAsset() method
  156. public static void selectAsset(View view)
  157. {
  158. SideKickParsedData data = SideKickParsedData.getParsedData(view);
  159. if(data == null)
  160. {
  161. view.getToolkit().beep();
  162. return;
  163. }
  164. JEditTextArea textArea = view.getTextArea();
  165. IAsset asset = data.getAssetAtOffset(
  166. textArea.getCaretPosition());
  167. if(asset == null || asset.getEnd() == null)
  168. {
  169. view.getToolkit().beep();
  170. return;
  171. }
  172. int pos = asset.getEnd().getOffset();
  173. if (pos > textArea.getBuffer().getLength())
  174. {
  175. view.getToolkit().beep();
  176. return;
  177. }
  178. textArea.setCaretPosition(pos);
  179. textArea.addToSelection(
  180. new Selection.Range(
  181. asset.getStart().getOffset(),
  182. pos));
  183. } //}}}
  184. //{{{ narrowToAsset() method
  185. public static void narrowToAsset(View view)
  186. {
  187. SideKickParsedData data = SideKickParsedData.getParsedData(view);
  188. if(data == null)
  189. {
  190. view.getToolkit().beep();
  191. return;
  192. }
  193. JEditTextArea textArea = view.getTextArea();
  194. TreePath path = data.getTreePathForPosition(textArea.getCaretPosition());
  195. if(path == null)
  196. {
  197. view.getToolkit().beep();
  198. return;
  199. }
  200. IAsset asset = (IAsset)((DefaultMutableTreeNode)path
  201. .getLastPathComponent()).getUserObject();
  202. if(asset == null || asset.getEnd() == null)
  203. {
  204. view.getToolkit().beep();
  205. return;
  206. }
  207. textArea.getDisplayManager().narrow(
  208. textArea.getLineOfOffset(asset.getStart().getOffset()),
  209. textArea.getLineOfOffset(asset.getStart().getOffset()));
  210. } //}}}
  211. //{{{ goToPrevAsset() method
  212. public static void goToPrevAsset(View view)
  213. {
  214. SideKickParsedData data = SideKickParsedData.getParsedData(view);
  215. if(data == null)
  216. {
  217. view.getToolkit().beep();
  218. return;
  219. }
  220. JEditTextArea textArea = view.getTextArea();
  221. int caret = textArea.getCaretPosition();
  222. TreePath path = data.getTreePathForPosition(caret);
  223. if(path == null)
  224. {
  225. view.getToolkit().beep();
  226. return;
  227. }
  228. DefaultMutableTreeNode node = (DefaultMutableTreeNode)
  229. path.getLastPathComponent();
  230. // see if caret is at the end of a child of the current asset
  231. for(int i = 0; i < node.getChildCount(); i++)
  232. {
  233. Object userObject = ((DefaultMutableTreeNode)node.getChildAt(i)).getUserObject();
  234. if (userObject instanceof IAsset)
  235. {
  236. IAsset asset = (IAsset)userObject;
  237. if(asset.getEnd() != null && caret == asset.getEnd().getOffset())
  238. {
  239. textArea.setCaretPosition(asset.getStart().getOffset());
  240. return;
  241. }
  242. }
  243. }
  244. IAsset asset = ((IAsset)node.getUserObject());
  245. if(caret == asset.getStart().getOffset())
  246. {
  247. DefaultMutableTreeNode parent = (DefaultMutableTreeNode)
  248. node.getParent();
  249. if (parent != null)
  250. {
  251. for(int i = 0; i < parent.getChildCount(); i++)
  252. {
  253. if(node == parent.getChildAt(i))
  254. {
  255. if(i == 0)
  256. {
  257. if(parent.getUserObject() instanceof IAsset)
  258. {
  259. textArea.setCaretPosition(
  260. ((IAsset)parent.getUserObject())
  261. .getStart().getOffset());
  262. }
  263. }
  264. else
  265. {
  266. Object child = ((DefaultMutableTreeNode)parent.getChildAt(i - 1)).getUserObject();
  267. if (child instanceof IAsset) {
  268. IAsset prevAsset = (IAsset)child;
  269. if(prevAsset.getEnd() != null)
  270. textArea.setCaretPosition(prevAsset.getEnd().getOffset());
  271. }
  272. }
  273. return;
  274. }
  275. }
  276. }
  277. }
  278. else
  279. textArea.setCaretPosition(asset.getStart().getOffset());
  280. } //}}}
  281. //{{{ goToNextAsset() method
  282. public static void goToNextAsset(View view)
  283. {
  284. SideKickParsedData data = SideKickParsedData.getParsedData(view);
  285. if(data == null)
  286. {
  287. view.getToolkit().beep();
  288. return;
  289. }
  290. JEditTextArea textArea = view.getTextArea();
  291. int caret = textArea.getCaretPosition();
  292. TreePath path = data.getTreePathForPosition(caret);
  293. if(path == null)
  294. {
  295. view.getToolkit().beep();
  296. return;
  297. }
  298. DefaultMutableTreeNode node = (DefaultMutableTreeNode)
  299. path.getLastPathComponent();
  300. // see if caret is at the end of a child of the current asset
  301. for(int i = 0; i < node.getChildCount(); i++)
  302. {
  303. Object userObject = ((DefaultMutableTreeNode)node.getChildAt(i)).getUserObject();
  304. if (userObject instanceof IAsset)
  305. {
  306. IAsset asset = (IAsset)userObject;
  307. if(caret == asset.getEnd().getOffset())
  308. {
  309. if(i != node.getChildCount() - 1)
  310. {
  311. IAsset nextAsset = (IAsset)((DefaultMutableTreeNode)
  312. node.getChildAt(i + 1)).getUserObject();
  313. int offset = nextAsset.getStart().getOffset() >= textArea.getBufferLength() ?
  314. textArea.getBufferLength() - 1 :
  315. nextAsset.getStart().getOffset();
  316. textArea.setCaretPosition(offset);
  317. return;
  318. }
  319. else
  320. break;
  321. }
  322. }
  323. }
  324. int offset = ((IAsset)node.getUserObject()).getEnd().getOffset();
  325. offset = offset >= textArea.getBufferLength() ? textArea.getBufferLength() - 1 : offset;
  326. textArea.setCaretPosition(offset);
  327. } //}}}
  328. //{{{ propertiesChanged() method
  329. public static void propertiesChanged()
  330. {
  331. completeDelay = jEdit.getBooleanProperty("sidekick.complete-delay.toggle");
  332. completeInstant = jEdit.getBooleanProperty("sidekick.complete-instant.toggle");
  333. autoCompletePopupGetFocus = jEdit.getBooleanProperty("sidekick.auto-complete-popup-get-focus");
  334. acceptChars = MiscUtilities.escapesToChars(jEdit.getProperty("sidekick.complete-popup.accept-characters"));
  335. insertChars = MiscUtilities.escapesToChars(jEdit.getProperty("sidekick.complete-popup.insert-characters"));
  336. delay = jEdit.getIntegerProperty("sidekick.complete-delay",500);
  337. if(timer != null)
  338. timer.setInitialDelay(delay);
  339. } //}}}
  340. // {{{ SideKickAction class
  341. abstract public static class SideKickAction extends EditAction
  342. {
  343. protected String parserName;
  344. protected SideKickAction(String actionName, String parserName)
  345. {
  346. super(actionName, new Object[] {parserName} );
  347. this.parserName = parserName;
  348. }
  349. }// }}}
  350. // {{{ ToggleParser class
  351. /** An action which will always activate the SideKick parser,
  352. * alternately selecting the default parser, and then the
  353. * selected one, allowing you to toggle between say, Outline
  354. * and Java parsers, XML and HTML, or Python and Jython parsers.
  355. */
  356. public static class ToggleParser extends SideKickAction
  357. {
  358. public String getLabel()
  359. {
  360. return parserName + " (Toggle)";
  361. }
  362. public ToggleParser(String parserName)
  363. {
  364. super("sidekick.parser." + parserName + "-toggle", parserName);
  365. this.parserName =parserName;
  366. }
  367. public String getCode() {
  368. return "new sidekick.SideKickActions.ToggleAction(\"" + parserName + "\").invoke(view)";
  369. }
  370. public void invoke(View view)
  371. {
  372. }
  373. } //}}}
  374. } // }}}