PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/ActionSet.java

#
Java | 493 lines | 201 code | 36 blank | 256 comment | 25 complexity | c03b2c7bc93198af81dddbf7aaabbfd6 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. * ActionSet.java - A set of actions
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2001, 2003 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. import java.io.*;
  24. import java.net.URL;
  25. import java.util.*;
  26. import org.gjt.sp.jedit.gui.InputHandler;
  27. import org.gjt.sp.util.Log;
  28. /**
  29. * A set of actions, either loaded from an XML file, or constructed at runtime
  30. * by a plugin.<p>
  31. *
  32. * <h3>Action sets loaded from XML files</h3>
  33. *
  34. * Action sets are read from these files inside the plugin JAR:
  35. * <ul>
  36. * <li><code>actions.xml</code> - actions made available for use in jEdit views,
  37. * including the view's <b>Plugins</b> menu, the tool bar, etc.</li>
  38. * <li><code>browser.actions.xml</code> - actions for the file system browser's
  39. * <b>Plugins</b> menu.</li>
  40. * </ul>
  41. *
  42. * An action definition file has the following form:
  43. *
  44. * <pre>&lt;?xml version="1.0"?&gt;
  45. *&lt;!DOCTYPE ACTIONS SYSTEM "actions.dtd"&gt;
  46. *&lt;ACTIONS&gt;
  47. * &lt;ACTION NAME="some-action"&gt;
  48. * &lt;CODE&gt;
  49. * // BeanShell code evaluated when the action is invoked
  50. * &lt;/CODE&gt;
  51. * &lt;/ACTION&gt;
  52. * &lt;ACTION NAME="some-toggle-action"&gt;
  53. * &lt;CODE&gt;
  54. * // BeanShell code evaluated when the action is invoked
  55. * &lt;/CODE&gt;
  56. * &lt;IS_SELECTED&gt;
  57. * // BeanShell code that should evaluate to true or false
  58. * &lt;/IS_SELECTED&gt;
  59. * &lt;/ACTION&gt;
  60. *&lt;/ACTIONS&gt;</pre>
  61. *
  62. * The following elements are valid:
  63. *
  64. * <ul>
  65. * <li>
  66. * <code>ACTIONS</code> is the top-level element and refers
  67. * to the set of actions used by the plugin.
  68. * </li>
  69. * <li>
  70. * An <code>ACTION</code> contains the data for a particular action.
  71. * It has three attributes: a required <code>NAME</code>;
  72. * an optional <code>NO_REPEAT</code>, which is a flag
  73. * indicating whether the action should not be repeated with the
  74. * <b>C+ENTER</b> command; and an optional
  75. * <code>NO_RECORD</code> which is a a flag indicating whether the
  76. * action should be recorded if it is invoked while the user is recording a
  77. * macro. The two flag attributes
  78. * can have two possible values, "TRUE" or
  79. * "FALSE". In both cases, "FALSE" is the
  80. * default if the attribute is not specified.
  81. * </li>
  82. * <li>
  83. * An <code>ACTION</code> can have two child elements
  84. * within it: a required <code>CODE</code> element which
  85. * specifies the
  86. * BeanShell code that will be executed when the action is invoked,
  87. * and an optional <code>IS_SELECTED</code> element, used for
  88. * checkbox
  89. * menu items. The <code>IS_SELECTED</code> element contains
  90. * BeanShell code that returns a boolean flag that will
  91. * determine the state of the checkbox.
  92. * </li>
  93. * </ul>
  94. *
  95. * Each action must have a property <code><i>name</i>.label</code> containing
  96. * the action's menu item label.
  97. *
  98. * <h3>View actions</h3>
  99. *
  100. * Actions defined in <code>actions.xml</code> can be added to the view's
  101. * <b>Plugins</b> menu; see {@link EditPlugin}.
  102. * The action code may use any standard predefined
  103. * BeanShell variable; see {@link BeanShell}.
  104. *
  105. * <h3>File system browser actions</h3>
  106. *
  107. * Actions defined in <code>actions.xml</code> can be added to the file
  108. * system browser's <b>Plugins</b> menu; see {@link EditPlugin}.
  109. * The action code may use any standard predefined
  110. * BeanShell variable, in addition to a variable <code>browser</code> which
  111. * contains a reference to the current
  112. * {@link org.gjt.sp.jedit.browser.VFSBrowser} instance.<p>
  113. *
  114. * File system browser actions should not define
  115. * <code>&lt;IS_SELECTED&gt;</code> blocks.
  116. *
  117. * <h3>Custom action sets</h3>
  118. *
  119. * Call {@link jEdit#addActionSet(ActionSet)} to add a custom action set to
  120. * jEdit's action context. You must also call {@link #initKeyBindings()} for new
  121. * action sets. Don't forget to call {@link jEdit#removeActionSet(ActionSet)}
  122. * before your plugin is unloaded, too.
  123. *
  124. * @see jEdit#getActionContext()
  125. * @see org.gjt.sp.jedit.browser.VFSBrowser#getActionContext()
  126. * @see ActionContext#getActionNames()
  127. * @see ActionContext#getAction(String)
  128. * @see jEdit#addActionSet(ActionSet)
  129. * @see jEdit#removeActionSet(ActionSet)
  130. * @see PluginJAR#getActionSet()
  131. * @see BeanShell
  132. * @see View
  133. *
  134. * @author Slava Pestov
  135. * @author John Gellene (API documentation)
  136. * @version $Id: ActionSet.java 5443 2006-06-18 18:51:40Z vanza $
  137. * @since jEdit 4.0pre1
  138. */
  139. public class ActionSet
  140. {
  141. //{{{ ActionSet constructor
  142. /**
  143. * Creates a new action set.
  144. * @since jEdit 4.0pre1
  145. */
  146. public ActionSet()
  147. {
  148. actions = new Hashtable();
  149. loaded = true;
  150. label = "<no label set; plugin bug>";
  151. } //}}}
  152. //{{{ ActionSet constructor
  153. /**
  154. * Creates a new action set.
  155. * @param plugin The plugin
  156. * @param cachedActionNames The list of cached action names
  157. * @param cachedActionToggleFlags The list of cached action toggle flags
  158. * @param uri The actions.xml URI
  159. * @since jEdit 4.2pre2
  160. */
  161. public ActionSet(PluginJAR plugin, String[] cachedActionNames,
  162. boolean[] cachedActionToggleFlags, URL uri)
  163. {
  164. this();
  165. this.plugin = plugin;
  166. this.uri = uri;
  167. if(cachedActionNames != null)
  168. {
  169. for(int i = 0; i < cachedActionNames.length; i++)
  170. {
  171. actions.put(cachedActionNames[i],placeholder);
  172. jEdit.setTemporaryProperty(cachedActionNames[i]
  173. + ".toggle",cachedActionToggleFlags[i]
  174. ? "true" : "false");
  175. }
  176. }
  177. loaded = false;
  178. } //}}}
  179. //{{{ ActionSet constructor
  180. /**
  181. * Creates a new action set.
  182. * @param label The label, shown in the shortcuts option pane
  183. * @since jEdit 4.0pre1
  184. */
  185. public ActionSet(String label)
  186. {
  187. this();
  188. setLabel(label);
  189. } //}}}
  190. //{{{ getLabel() method
  191. /**
  192. * Return the action source label.
  193. * @since jEdit 4.0pre1
  194. */
  195. public String getLabel()
  196. {
  197. return label;
  198. } //}}}
  199. //{{{ setLabel() method
  200. /**
  201. * Sets the action source label.
  202. * @param label The label
  203. * @since jEdit 4.0pre1
  204. */
  205. public void setLabel(String label)
  206. {
  207. if(label == null)
  208. throw new NullPointerException();
  209. this.label = label;
  210. } //}}}
  211. //{{{ getPluginJAR() method
  212. /**
  213. * Return the plugin this action set was loaded from, or null.
  214. * @since jEdit 4.2pre13
  215. */
  216. public PluginJAR getPluginJAR()
  217. {
  218. return plugin;
  219. } //}}}
  220. //{{{ addAction() method
  221. /**
  222. * Adds an action to the action set.
  223. * @param action The action
  224. * @since jEdit 4.0pre1
  225. */
  226. public void addAction(EditAction action)
  227. {
  228. actions.put(action.getName(),action);
  229. if(context != null)
  230. {
  231. context.actionNames = null;
  232. context.actionHash.put(action.getName(),this);
  233. }
  234. } //}}}
  235. //{{{ removeAction() method
  236. /**
  237. * Removes an action from the action set.
  238. * @param name The action name
  239. * @since jEdit 4.0pre1
  240. */
  241. public void removeAction(String name)
  242. {
  243. actions.remove(name);
  244. if(context != null)
  245. {
  246. context.actionNames = null;
  247. context.actionHash.remove(name);
  248. }
  249. } //}}}
  250. //{{{ removeAllActions() method
  251. /**
  252. * Removes all actions from the action set.
  253. * @since jEdit 4.0pre1
  254. */
  255. public void removeAllActions()
  256. {
  257. if(context != null)
  258. {
  259. context.actionNames = null;
  260. String[] actions = getActionNames();
  261. for(int i = 0; i < actions.length; i++)
  262. {
  263. context.actionHash.remove(actions[i]);
  264. }
  265. }
  266. this.actions.clear();
  267. } //}}}
  268. //{{{ getAction() method
  269. /**
  270. * Returns an action with the specified name.<p>
  271. *
  272. * <b>Deferred loading:</b> this will load the action set if necessary.
  273. *
  274. * @param name The action name
  275. * @since jEdit 4.0pre1
  276. */
  277. public EditAction getAction(String name)
  278. {
  279. Object obj = actions.get(name);
  280. if(obj == placeholder)
  281. {
  282. load();
  283. obj = actions.get(name);
  284. if(obj == placeholder)
  285. {
  286. Log.log(Log.WARNING,this,"Outdated cache");
  287. obj = null;
  288. }
  289. }
  290. return (EditAction)obj;
  291. } //}}}
  292. //{{{ getActionCount() method
  293. /**
  294. * Returns the number of actions in the set.
  295. * @since jEdit 4.0pre1
  296. */
  297. public int getActionCount()
  298. {
  299. return actions.size();
  300. } //}}}
  301. //{{{ getActionNames() method
  302. /**
  303. * Returns an array of all action names in this action set.
  304. * @since jEdit 4.2pre1
  305. */
  306. public String[] getActionNames()
  307. {
  308. String[] retVal = new String[actions.size()];
  309. Enumeration e = actions.keys();
  310. int i = 0;
  311. while(e.hasMoreElements())
  312. {
  313. retVal[i++] = (String)e.nextElement();
  314. }
  315. return retVal;
  316. } //}}}
  317. //{{{ getCacheableActionNames() method
  318. /**
  319. * Returns an array of all action names in this action set that should
  320. * be cached; namely, <code>BeanShellAction</code>s.
  321. * @since jEdit 4.2pre1
  322. */
  323. public String[] getCacheableActionNames()
  324. {
  325. LinkedList retVal = new LinkedList();
  326. Enumeration e = actions.elements();
  327. while(e.hasMoreElements())
  328. {
  329. Object obj = e.nextElement();
  330. if(obj == placeholder)
  331. {
  332. // ??? this should only be called with
  333. // fully loaded action set
  334. Log.log(Log.WARNING,this,"Action set not up "
  335. + "to date");
  336. }
  337. else if(obj instanceof BeanShellAction)
  338. retVal.add(((BeanShellAction)obj).getName());
  339. }
  340. return (String[])retVal.toArray(new String[retVal.size()]);
  341. } //}}}
  342. //{{{ getActions() method
  343. /**
  344. * Returns an array of all actions in this action set.<p>
  345. *
  346. * <b>Deferred loading:</b> this will load the action set if necessary.
  347. *
  348. * @since jEdit 4.0pre1
  349. */
  350. public EditAction[] getActions()
  351. {
  352. load();
  353. EditAction[] retVal = new EditAction[actions.size()];
  354. Enumeration e = actions.elements();
  355. int i = 0;
  356. while(e.hasMoreElements())
  357. {
  358. retVal[i++] = (EditAction)e.nextElement();
  359. }
  360. return retVal;
  361. } //}}}
  362. //{{{ contains() method
  363. /**
  364. * Returns if this action set contains the specified action.
  365. * @param action The action
  366. * @since jEdit 4.2pre1
  367. */
  368. public boolean contains(String action)
  369. {
  370. boolean retval = actions.containsKey(action);
  371. return retval;
  372. // return actions.containsKey(action);
  373. } //}}}
  374. //{{{ size() method
  375. /**
  376. * Returns the number of actions in this action set.
  377. * @since jEdit 4.2pre2
  378. */
  379. public int size()
  380. {
  381. return actions.size();
  382. } //}}}
  383. //{{{ toString() method
  384. public String toString()
  385. {
  386. return label;
  387. } //}}}
  388. //{{{ initKeyBindings() method
  389. /**
  390. * Initializes the action set's key bindings.
  391. * jEdit calls this method for all registered action sets when the
  392. * user changes key bindings in the <b>Global Options</b> dialog box.<p>
  393. *
  394. * Note if your plugin adds a custom action set to jEdit's collection,
  395. * it must also call this method on the action set after adding it.
  396. *
  397. * @since jEdit 4.2pre1
  398. */
  399. public void initKeyBindings()
  400. {
  401. InputHandler inputHandler = jEdit.getInputHandler();
  402. Iterator iter = actions.entrySet().iterator();
  403. while(iter.hasNext())
  404. {
  405. Map.Entry entry = (Map.Entry)iter.next();
  406. String name = (String)entry.getKey();
  407. String shortcut1 = jEdit.getProperty(name + ".shortcut");
  408. if(shortcut1 != null)
  409. inputHandler.addKeyBinding(shortcut1,name);
  410. String shortcut2 = jEdit.getProperty(name + ".shortcut2");
  411. if(shortcut2 != null)
  412. inputHandler.addKeyBinding(shortcut2,name);
  413. }
  414. } //}}}
  415. //{{{ load() method
  416. /**
  417. * Forces the action set to be loaded. Plugins and macros should not
  418. * call this method.
  419. * @since jEdit 4.2pre1
  420. */
  421. public void load()
  422. {
  423. if(loaded)
  424. return;
  425. loaded = true;
  426. //actions.clear();
  427. Reader stream = null;
  428. try
  429. {
  430. Log.log(Log.DEBUG,this,"Loading actions from " + uri);
  431. ActionListHandler ah = new ActionListHandler(uri.toString(),this);
  432. MiscUtilities.parseXML(uri.openStream(), ah);
  433. }
  434. catch(IOException e)
  435. {
  436. Log.log(Log.ERROR,uri,e);
  437. }
  438. } //}}}
  439. //{{{ Package-private members
  440. ActionContext context;
  441. //{{{ getActionNames() method
  442. void getActionNames(List vec)
  443. {
  444. Enumeration e = actions.keys();
  445. while(e.hasMoreElements())
  446. vec.add(e.nextElement());
  447. } //}}}
  448. //}}}
  449. //{{{ Private members
  450. private String label;
  451. private Hashtable actions;
  452. private PluginJAR plugin;
  453. private URL uri;
  454. private boolean loaded;
  455. private static final Object placeholder = new Object();
  456. //}}}
  457. }