PageRenderTime 69ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre3/org/gjt/sp/jedit/Macros.java

#
Java | 639 lines | 367 code | 82 blank | 190 comment | 54 complexity | d082eb66337e4847a02e663421753267 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. * Macros.java - Macro manager
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2000, 2001 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 org.gjt.sp.jedit;
  23. //{{{ Imports
  24. import javax.swing.JOptionPane;
  25. import java.awt.event.ActionEvent;
  26. import java.awt.event.ActionListener;
  27. import java.awt.*;
  28. import java.io.*;
  29. import java.util.*;
  30. import org.gjt.sp.jedit.browser.*;
  31. import org.gjt.sp.jedit.gui.*;
  32. import org.gjt.sp.jedit.io.VFSManager;
  33. import org.gjt.sp.jedit.msg.*;
  34. import org.gjt.sp.util.Log;
  35. //}}}
  36. /**
  37. * This class records and runs macros.
  38. *
  39. * @author Slava Pestov
  40. * @version $Id: Macros.java 3928 2001-12-01 05:48:48Z spestov $
  41. */
  42. public class Macros
  43. {
  44. //{{{ message() method
  45. /**
  46. * Utility method that can be used to display a message dialog in a macro.
  47. * @param comp The component to show the dialog on behalf of, this
  48. * will usually be a view instance
  49. * @param message The message
  50. * @since jEdit 2.7pre2
  51. */
  52. public static void message(Component comp, String message)
  53. {
  54. GUIUtilities.hideSplashScreen();
  55. JOptionPane.showMessageDialog(comp,message,
  56. jEdit.getProperty("macro-message.title"),
  57. JOptionPane.INFORMATION_MESSAGE);
  58. } //}}}
  59. //{{{ error() method
  60. /**
  61. * Utility method that can be used to display an error dialog in a macro.
  62. * @param comp The component to show the dialog on behalf of, this
  63. * will usually be a view instance
  64. * @param message The message
  65. * @since jEdit 2.7pre2
  66. */
  67. public static void error(Component comp, String message)
  68. {
  69. GUIUtilities.hideSplashScreen();
  70. JOptionPane.showMessageDialog(comp,message,
  71. jEdit.getProperty("macro-message.title"),
  72. JOptionPane.ERROR_MESSAGE);
  73. } //}}}
  74. //{{{ input() method
  75. /**
  76. * Utility method that can be used to prompt for input in a macro.
  77. * @param comp The component to show the dialog on behalf of, this
  78. * will usually be a view instance
  79. * @param prompt The prompt string
  80. * @since jEdit 2.7pre2
  81. */
  82. public static String input(Component comp, String prompt)
  83. {
  84. GUIUtilities.hideSplashScreen();
  85. return input(comp,prompt,null);
  86. } //}}}
  87. //{{{ input() method
  88. /**
  89. * Utility method that can be used to prompt for input in a macro.
  90. * @param comp The component to show the dialog on behalf of, this
  91. * will usually be a view instance
  92. * @param prompt The prompt string
  93. * @since jEdit 3.1final
  94. */
  95. public static String input(Component comp, String prompt, String defaultValue)
  96. {
  97. GUIUtilities.hideSplashScreen();
  98. return (String)JOptionPane.showInputDialog(comp,prompt,
  99. jEdit.getProperty("macro-input.title"),
  100. JOptionPane.QUESTION_MESSAGE,null,null,defaultValue);
  101. } //}}}
  102. //{{{ confirm() method
  103. /**
  104. * Utility method that can be used to ask for confirmation in a macro.
  105. * @param comp The component to show the dialog on behalf of, this
  106. * will usually be a view instance
  107. * @param prompt The prompt string
  108. * @param buttons The buttons to display - for example,
  109. * JOptionPane.YES_NO_CANCEL_OPTION
  110. * @since jEdit 4.0pre2
  111. */
  112. public static int confirm(Component comp, String prompt, int buttons)
  113. {
  114. GUIUtilities.hideSplashScreen();
  115. return JOptionPane.showConfirmDialog(comp,prompt,
  116. jEdit.getProperty("macro-confirm.title"),buttons,
  117. JOptionPane.QUESTION_MESSAGE);
  118. } //}}}
  119. //{{{ confirm() method
  120. /**
  121. * Utility method that can be used to ask for confirmation in a macro.
  122. * @param comp The component to show the dialog on behalf of, this
  123. * will usually be a view instance
  124. * @param prompt The prompt string
  125. * @param buttons The buttons to display - for example,
  126. * JOptionPane.YES_NO_CANCEL_OPTION
  127. * @param type The dialog type - for example,
  128. * JOptionPane.WARNING_MESSAGE
  129. */
  130. public static int confirm(Component comp, String prompt, int buttons, int type)
  131. {
  132. GUIUtilities.hideSplashScreen();
  133. return JOptionPane.showConfirmDialog(comp,prompt,
  134. jEdit.getProperty("macro-confirm.title"),buttons,type);
  135. } //}}}
  136. //{{{ browseSystemMacros() method
  137. /**
  138. * Opens the system macro directory in a VFS browser.
  139. * @param view The view
  140. * @since jEdit 2.7pre2
  141. */
  142. public static void browseSystemMacros(View view)
  143. {
  144. if(systemMacroPath == null)
  145. {
  146. GUIUtilities.error(view,"no-webstart",null);
  147. return;
  148. }
  149. VFSBrowser.browseDirectory(view,systemMacroPath);
  150. } //}}}
  151. //{{{ browseUserMacros() method
  152. /**
  153. * Opens the user macro directory in a VFS browser.
  154. * @param view The view
  155. * @since jEdit 2.7pre2
  156. */
  157. public static void browseUserMacros(View view)
  158. {
  159. if(userMacroPath == null)
  160. {
  161. GUIUtilities.error(view,"no-settings",null);
  162. return;
  163. }
  164. VFSBrowser.browseDirectory(view,userMacroPath);
  165. } //}}}
  166. //{{{ loadMacros() method
  167. /**
  168. * Rebuilds the macros list, and sends a MacrosChanged message
  169. * (views update their Macros menu upon receiving it)
  170. * @since jEdit 2.2pre4
  171. */
  172. public static void loadMacros()
  173. {
  174. macroActionSet.removeAllActions();
  175. macroHierarchy.removeAllElements();
  176. macroHash.clear();
  177. if(jEdit.getJEditHome() != null)
  178. {
  179. systemMacroPath = MiscUtilities.constructPath(
  180. jEdit.getJEditHome(),"macros");
  181. loadMacros(macroHierarchy,"",new File(systemMacroPath));
  182. }
  183. String settings = jEdit.getSettingsDirectory();
  184. if(settings != null)
  185. {
  186. userMacroPath = MiscUtilities.constructPath(
  187. settings,"macros");
  188. loadMacros(macroHierarchy,"",new File(userMacroPath));
  189. }
  190. EditBus.send(new MacrosChanged(null));
  191. } //}}}
  192. //{{{ getMacroHierarchy() method
  193. /**
  194. * Returns a vector hierarchy with all known macros in it.
  195. * Each element of this vector is either a macro name string,
  196. * or another vector. If it is a vector, the first element is a
  197. * string label, the rest are again, either macro name strings
  198. * or vectors.
  199. * @since jEdit 2.6pre1
  200. */
  201. public static Vector getMacroHierarchy()
  202. {
  203. return macroHierarchy;
  204. } //}}}
  205. //{{{ getMacroActionSet() method
  206. /**
  207. * Returns an action set with all known macros in it.
  208. * @since jEdit 4.0pre1
  209. */
  210. public static ActionSet getMacroActionSet()
  211. {
  212. return macroActionSet;
  213. } //}}}
  214. //{{{ getMacro() method
  215. /**
  216. * Returns the macro with the specified name.
  217. * @param macro The macro's name
  218. * @since jEdit 2.6pre1
  219. */
  220. public static Macro getMacro(String macro)
  221. {
  222. return (Macro)macroHash.get(macro);
  223. } //}}}
  224. //{{{ Macro class
  225. /**
  226. * Encapsulates the macro's label, name and path.
  227. * @since jEdit 2.2pre4
  228. */
  229. public static class Macro extends EditAction
  230. {
  231. //{{{ Macro constructor
  232. public Macro(String name, String path)
  233. {
  234. // stupid name for backwards compatibility
  235. super("play-macro@" + name);
  236. this.path = path;
  237. int index = name.lastIndexOf('/');
  238. label = name.substring(index + 1)
  239. .replace('_',' ');
  240. } //}}}
  241. //{{{ getLabel() method
  242. public String getLabel()
  243. {
  244. return label;
  245. } //}}}
  246. //{{{ invoke() method
  247. public void invoke(View view)
  248. {
  249. lastMacro = path;
  250. Buffer buffer = view.getBuffer();
  251. try
  252. {
  253. buffer.beginCompoundEdit();
  254. BeanShell.runScript(view,path,
  255. true,false);
  256. }
  257. finally
  258. {
  259. buffer.endCompoundEdit();
  260. }
  261. } //}}}
  262. //{{{ getCode() method
  263. public String getCode()
  264. {
  265. return "Macros.getMacro(\""
  266. + getName().substring("play-macro@".length())
  267. + "\").invoke(view);";
  268. } //}}}
  269. //{{{ Private members
  270. private String path;
  271. private String label;
  272. //}}}
  273. } //}}}
  274. //{{{ recordTemporaryMacro() method
  275. /**
  276. * Starts recording a temporary macro.
  277. * @param view The view
  278. * @since jEdit 2.7pre2
  279. */
  280. public static void recordTemporaryMacro(View view)
  281. {
  282. String settings = jEdit.getSettingsDirectory();
  283. if(settings == null)
  284. {
  285. GUIUtilities.error(view,"no-settings",new String[0]);
  286. return;
  287. }
  288. if(view.getMacroRecorder() != null)
  289. {
  290. GUIUtilities.error(view,"already-recording",new String[0]);
  291. return;
  292. }
  293. Buffer buffer = jEdit.openFile(null,settings + File.separator
  294. + "macros","Temporary_Macro.bsh",true,null);
  295. if(buffer == null)
  296. return;
  297. buffer.remove(0,buffer.getLength());
  298. buffer.insert(0,jEdit.getProperty("macro.temp.header"));
  299. recordMacro(view,buffer,true);
  300. } //}}}
  301. //{{{ recordMacro() method
  302. /**
  303. * Starts recording a macro.
  304. * @param view The view
  305. * @since jEdit 2.7pre2
  306. */
  307. public static void recordMacro(View view)
  308. {
  309. String settings = jEdit.getSettingsDirectory();
  310. if(settings == null)
  311. {
  312. GUIUtilities.error(view,"no-settings",new String[0]);
  313. return;
  314. }
  315. if(view.getMacroRecorder() != null)
  316. {
  317. GUIUtilities.error(view,"already-recording",new String[0]);
  318. return;
  319. }
  320. String name = GUIUtilities.input(view,"record",null);
  321. if(name == null)
  322. return;
  323. name = name.replace(' ','_');
  324. Buffer buffer = jEdit.openFile(null,null,
  325. MiscUtilities.constructPath(settings,"macros",
  326. name + ".bsh"),true,null);
  327. if(buffer == null)
  328. return;
  329. buffer.remove(0,buffer.getLength());
  330. buffer.insert(0,jEdit.getProperty("macro.header"));
  331. recordMacro(view,buffer,false);
  332. } //}}}
  333. //{{{ stopRecording() method
  334. /**
  335. * Stops a recording currently in progress.
  336. * @param view The view
  337. * @since jEdit 2.7pre2
  338. */
  339. public static void stopRecording(View view)
  340. {
  341. InputHandler inputHandler = view.getInputHandler();
  342. Recorder recorder = view.getMacroRecorder();
  343. if(recorder == null)
  344. GUIUtilities.error(view,"macro-not-recording",null);
  345. else
  346. {
  347. view.setMacroRecorder(null);
  348. if(!recorder.temporary)
  349. view.setBuffer(recorder.buffer);
  350. recorder.dispose();
  351. }
  352. } //}}}
  353. //{{{ runTemporaryMacro() method
  354. /**
  355. * Runs the temporary macro.
  356. * @param view The view
  357. * @since jEdit 2.7pre2
  358. */
  359. public static void runTemporaryMacro(View view)
  360. {
  361. String settings = jEdit.getSettingsDirectory();
  362. if(settings == null)
  363. {
  364. GUIUtilities.error(view,"no-settings",new String[0]);
  365. return;
  366. }
  367. lastMacro = MiscUtilities.constructPath(
  368. jEdit.getSettingsDirectory(),"macros",
  369. "Temporary_Macro.bsh");
  370. Buffer buffer = view.getBuffer();
  371. try
  372. {
  373. buffer.beginCompoundEdit();
  374. BeanShell.runScript(view,lastMacro,true,false);
  375. }
  376. finally
  377. {
  378. buffer.endCompoundEdit();
  379. }
  380. } //}}}
  381. //{{{ runLastMacro() method
  382. /**
  383. * Runs the most recently run or recorded macro.
  384. * @param view The view
  385. * @since jEdit 2.7pre2
  386. */
  387. public static void runLastMacro(View view)
  388. {
  389. if(lastMacro == null)
  390. view.getToolkit().beep();
  391. else
  392. BeanShell.runScript(view,lastMacro,true,false);
  393. } //}}}
  394. //{{{ Private members
  395. //{{{ Static variables
  396. private static String systemMacroPath;
  397. private static String userMacroPath;
  398. private static ActionSet macroActionSet;
  399. private static Vector macroHierarchy;
  400. private static Hashtable macroHash;
  401. private static String lastMacro;
  402. //}}}
  403. //{{{ Class initializer
  404. static
  405. {
  406. macroActionSet = new ActionSet(jEdit.getProperty("action-set.macros"));
  407. jEdit.addActionSet(macroActionSet);
  408. macroHierarchy = new Vector();
  409. macroHash = new Hashtable();
  410. } //}}}
  411. //{{{ loadMacros() method
  412. private static void loadMacros(Vector vector, String path, File directory)
  413. {
  414. String[] macroFiles = directory.list();
  415. if(macroFiles == null)
  416. return;
  417. MiscUtilities.quicksort(macroFiles,new MiscUtilities.StringICaseCompare());
  418. for(int i = 0; i < macroFiles.length; i++)
  419. {
  420. String fileName = macroFiles[i];
  421. File file = new File(directory,fileName);
  422. if(fileName.toLowerCase().endsWith(".bsh"))
  423. {
  424. String label = fileName.substring(0,fileName.length() - 4);
  425. String name = path + label;
  426. Macro newMacro = new Macro(name,file.getPath());
  427. vector.addElement(newMacro);
  428. macroActionSet.addAction(newMacro);
  429. macroHash.put(name,newMacro);
  430. }
  431. else if(file.isDirectory())
  432. {
  433. Vector submenu = new Vector();
  434. submenu.addElement(fileName.replace('_',' '));
  435. loadMacros(submenu,path + fileName + '/',file);
  436. if(submenu.size() != 1)
  437. vector.addElement(submenu);
  438. }
  439. }
  440. } //}}}
  441. //{{{ recordMacro() method
  442. /**
  443. * Starts recording a macro.
  444. * @param view The view
  445. * @param buffer The buffer to record to
  446. * @param temporary True if this is a temporary macro
  447. * @since jEdit 3.0pre5
  448. */
  449. private static void recordMacro(View view, Buffer buffer, boolean temporary)
  450. {
  451. lastMacro = buffer.getPath();
  452. view.setMacroRecorder(new Recorder(view,buffer,temporary));
  453. // setting the message to 'null' causes the status bar to check
  454. // if a recording is in progress
  455. view.getStatus().setMessage(null);
  456. } //}}}
  457. //}}}
  458. //{{{ Recorder class
  459. public static class Recorder implements EBComponent
  460. {
  461. View view;
  462. Buffer buffer;
  463. boolean temporary;
  464. boolean lastWasInput;
  465. //{{{ Recorder constructor
  466. public Recorder(View view, Buffer buffer, boolean temporary)
  467. {
  468. this.view = view;
  469. this.buffer = buffer;
  470. this.temporary = temporary;
  471. EditBus.addToBus(this);
  472. } //}}}
  473. //{{{ record() method
  474. public void record(String code)
  475. {
  476. if(lastWasInput)
  477. {
  478. lastWasInput = false;
  479. append("\");");
  480. }
  481. append("\n");
  482. append(code);
  483. } //}}}
  484. //{{{ record() method
  485. public void record(int repeat, String code)
  486. {
  487. if(repeat == 1)
  488. record(code);
  489. else
  490. {
  491. record("for(int i = 1; i <= " + repeat + "; i++)\n"
  492. + "{\n"
  493. + code + "\n"
  494. + "}");
  495. }
  496. } //}}}
  497. //{{{ record() method
  498. public void record(int repeat, char ch)
  499. {
  500. // record \n and \t on lines specially so that auto indent
  501. // can take place
  502. if(ch == '\n')
  503. record(repeat,"textArea.userInput(\'\\n\');");
  504. else if(ch == '\t')
  505. record(repeat,"textArea.userInput(\'\\t\');");
  506. else
  507. {
  508. StringBuffer buf = new StringBuffer();
  509. for(int i = 0; i < repeat; i++)
  510. buf.append(ch);
  511. String charStr = MiscUtilities.charsToEscapes(buf.toString());
  512. if(lastWasInput)
  513. append(charStr);
  514. else
  515. {
  516. append("\ntextArea.setSelectedText(\"" + charStr);
  517. lastWasInput = true;
  518. }
  519. }
  520. } //}}}
  521. //{{{ handleMessage() method
  522. public void handleMessage(EBMessage msg)
  523. {
  524. if(msg instanceof BufferUpdate)
  525. {
  526. BufferUpdate bmsg = (BufferUpdate)msg;
  527. if(bmsg.getWhat() == BufferUpdate.CLOSED)
  528. {
  529. if(bmsg.getBuffer() == buffer)
  530. stopRecording(view);
  531. }
  532. }
  533. } //}}}
  534. //{{{ append() method
  535. private void append(String str)
  536. {
  537. buffer.insert(buffer.getLength(),str);
  538. } //}}}
  539. //{{{ dispose() method
  540. private void dispose()
  541. {
  542. if(lastWasInput)
  543. {
  544. lastWasInput = false;
  545. append("\");");
  546. }
  547. for(int i = 0; i < buffer.getLineCount(); i++)
  548. {
  549. buffer.indentLine(i,true,true);
  550. }
  551. EditBus.removeFromBus(this);
  552. // setting the message to 'null' causes the status bar to
  553. // check if a recording is in progress
  554. view.getStatus().setMessage(null);
  555. } //}}}
  556. } //}}}
  557. }