PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/gui/DockableWindowFactory.java

#
Java | 570 lines | 401 code | 69 blank | 100 comment | 35 complexity | 177f43ef630ac1ef01aa64bf36d8cf98 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. * DockableWindowFactory.java - loads dockables.xml, etc
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 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 org.gjt.sp.jedit.gui;
  23. //{{{ Imports
  24. import java.io.IOException;
  25. import java.net.URL;
  26. import java.util.HashMap;
  27. import java.util.Iterator;
  28. import java.util.LinkedList;
  29. import java.util.Map;
  30. import java.util.Stack;
  31. import javax.swing.JComponent;
  32. import org.gjt.sp.jedit.ActionSet;
  33. import org.gjt.sp.jedit.BeanShell;
  34. import org.gjt.sp.jedit.EditAction;
  35. import org.gjt.sp.jedit.MiscUtilities;
  36. import org.gjt.sp.jedit.PluginJAR;
  37. import org.gjt.sp.jedit.View;
  38. import org.gjt.sp.jedit.jEdit;
  39. import org.gjt.sp.util.Log;
  40. import org.gjt.sp.util.XMLUtilities;
  41. import org.xml.sax.Attributes;
  42. import org.xml.sax.InputSource;
  43. import org.xml.sax.helpers.DefaultHandler;
  44. import org.gjt.sp.jedit.bsh.NameSpace;
  45. import org.gjt.sp.jedit.bsh.UtilEvalError;
  46. //}}}
  47. /**
  48. * Loads <code>dockable.xml</code> files and manages creation
  49. * of new dockable windows.
  50. *
  51. * @see DockableWindowManager
  52. *
  53. * @since jEdit 4.3pre2
  54. */
  55. public class DockableWindowFactory
  56. {
  57. //{{{ getInstance() method
  58. public static synchronized DockableWindowFactory getInstance()
  59. {
  60. if(instance == null)
  61. instance = new DockableWindowFactory();
  62. return instance;
  63. } //}}}
  64. //{{{ DockableWindowFactory constructor
  65. public DockableWindowFactory()
  66. {
  67. dockableWindowFactories = new HashMap<String, Window>();
  68. } //}}}
  69. //{{{ loadDockableWindows() method
  70. /**
  71. * Plugins shouldn't need to call this method.
  72. * @since jEdit 4.2pre1
  73. */
  74. public void loadDockableWindows(PluginJAR plugin, URL uri,
  75. PluginJAR.PluginCacheEntry cache)
  76. {
  77. try
  78. {
  79. Log.log(Log.DEBUG,DockableWindowManager.class,
  80. "Loading dockables from " + uri);
  81. DockableListHandler dh = new DockableListHandler(plugin,uri);
  82. boolean failure = XMLUtilities.parseXML(uri.openStream(), dh);
  83. if (!failure && cache != null)
  84. {
  85. cache.cachedDockableNames = dh.getCachedDockableNames();
  86. cache.cachedDockableActionFlags = dh.getCachedDockableActionFlags();
  87. cache.cachedDockableMovableFlags = dh.getCachedDockableMovableFlags();
  88. }
  89. }
  90. catch(IOException e)
  91. {
  92. Log.log(Log.ERROR,DockableWindowManager.class,e);
  93. }
  94. } //}}}
  95. //{{{ unloadDockableWindows() method
  96. /**
  97. * Plugins shouldn't need to call this method.
  98. * @since jEdit 4.2pre1
  99. */
  100. public void unloadDockableWindows(PluginJAR plugin)
  101. {
  102. Iterator entries = dockableWindowFactories.entrySet().iterator();
  103. while(entries.hasNext())
  104. {
  105. Map.Entry entry = (Map.Entry)entries.next();
  106. Window factory = (Window)entry.getValue();
  107. if(factory.plugin == plugin)
  108. entries.remove();
  109. }
  110. } //}}}
  111. //{{{ cacheDockableWindows() method
  112. /**
  113. * @since jEdit 4.2pre1
  114. */
  115. public void cacheDockableWindows(PluginJAR plugin,
  116. String[] name, boolean[] actions, boolean[] movable)
  117. {
  118. for(int i = 0; i < name.length; i++)
  119. {
  120. Window factory = new Window(plugin,
  121. name[i],null,actions[i],movable[i]);
  122. dockableWindowFactories.put(name[i],factory);
  123. }
  124. } //}}}
  125. //{{{ registerDockableWindow() method
  126. public void registerDockableWindow(PluginJAR plugin,
  127. String name, String code, boolean actions, boolean movable)
  128. {
  129. Window factory = dockableWindowFactories.get(name);
  130. if(factory != null)
  131. {
  132. factory.code = code;
  133. factory.loaded = true;
  134. }
  135. else
  136. {
  137. factory = new Window(plugin,name,code,actions, movable);
  138. dockableWindowFactories.put(name,factory);
  139. }
  140. } //}}}
  141. //{{{ getRegisteredDockableWindows() method
  142. public String[] getRegisteredDockableWindows()
  143. {
  144. String[] retVal = new String[dockableWindowFactories.size()];
  145. Iterator<Window> entries = dockableWindowFactories.values().iterator();
  146. int i = 0;
  147. while(entries.hasNext())
  148. {
  149. Window factory = entries.next();
  150. retVal[i++] = factory.name;
  151. }
  152. return retVal;
  153. } //}}}
  154. public Window getDockableWindowFactory(String name)
  155. {
  156. return dockableWindowFactories.get(name);
  157. }
  158. public String getDockableWindowPluginClass(String name)
  159. {
  160. Window w = getDockableWindowFactory(name);
  161. if (w == null || w.plugin == null || w.plugin.getPlugin() == null)
  162. return null;
  163. return w.plugin.getPlugin().getClassName();
  164. }
  165. //{{{ getDockableWindowIterator() method
  166. Iterator<Window> getDockableWindowIterator()
  167. {
  168. return dockableWindowFactories.values().iterator();
  169. } //}}}
  170. //{{{ DockableListHandler class
  171. class DockableListHandler extends DefaultHandler
  172. {
  173. //{{{ DockableListHandler constructor
  174. /**
  175. * @param plugin - the pluginJAR for which we are loading the dockables.xml
  176. * @param uri - the uri of the dockables.xml file?
  177. */
  178. DockableListHandler(PluginJAR plugin, URL uri)
  179. {
  180. this.plugin = plugin;
  181. this.uri = uri;
  182. stateStack = new Stack<String>();
  183. actions = true;
  184. movable = MOVABLE_DEFAULT;
  185. code = new StringBuilder();
  186. cachedDockableNames = new LinkedList<String>();
  187. cachedDockableActionFlags = new LinkedList<Boolean>();
  188. cachedDockableMovableFlags = new LinkedList<Boolean>();
  189. } //}}}
  190. //{{{ resolveEntity() method
  191. @Override
  192. public InputSource resolveEntity(String publicId, String systemId)
  193. {
  194. return XMLUtilities.findEntity(systemId, "dockables.dtd", MiscUtilities.class);
  195. } //}}}
  196. //{{{ characters() method
  197. @Override
  198. public void characters(char[] c, int off, int len)
  199. {
  200. String tag = peekElement();
  201. if (tag.equals("DOCKABLE"))
  202. code.append(c, off, len);
  203. } //}}}
  204. //{{{ startElement() method
  205. @Override
  206. public void startElement(String uri, String localName,
  207. String qName, Attributes attrs)
  208. {
  209. String tag = pushElement(qName);
  210. if (tag.equals("DOCKABLE"))
  211. {
  212. dockableName = attrs.getValue("NAME");
  213. actions = "FALSE".equals(attrs.getValue("NO_ACTIONS"));
  214. String movableAttr = attrs.getValue("MOVABLE");
  215. if (movableAttr != null)
  216. movable = movableAttr.equalsIgnoreCase("TRUE");
  217. }
  218. } //}}}
  219. //{{{ endElement() method
  220. @Override
  221. public void endElement(String uri, String localName, String name)
  222. {
  223. if(name == null)
  224. return;
  225. String tag = peekElement();
  226. if(name.equals(tag))
  227. {
  228. if(tag.equals("DOCKABLE"))
  229. {
  230. registerDockableWindow(plugin,
  231. dockableName,code.toString(),actions, movable);
  232. cachedDockableNames.add(dockableName);
  233. cachedDockableActionFlags.add(
  234. Boolean.valueOf(actions));
  235. cachedDockableMovableFlags.add(
  236. Boolean.valueOf(movable));
  237. // make default be true for the next
  238. // action
  239. actions = true;
  240. movable = MOVABLE_DEFAULT;
  241. code.setLength(0);
  242. }
  243. popElement();
  244. }
  245. else
  246. {
  247. // can't happen
  248. throw new InternalError();
  249. }
  250. } //}}}
  251. //{{{ startDocument() method
  252. @Override
  253. public void startDocument()
  254. {
  255. try
  256. {
  257. pushElement(null);
  258. }
  259. catch (Exception e)
  260. {
  261. Log.log(Log.ERROR, this, e);
  262. }
  263. } //}}}
  264. //{{{ getCachedDockableNames() method
  265. public String[] getCachedDockableNames()
  266. {
  267. return cachedDockableNames.toArray(new String[cachedDockableNames.size()]);
  268. } //}}}
  269. //{{{ getCachedDockableActionFlags() method
  270. public boolean[] getCachedDockableActionFlags()
  271. {
  272. return booleanListToArray(cachedDockableActionFlags);
  273. } //}}}
  274. //{{{ getCachedDockableMovableFlags() method
  275. public boolean[] getCachedDockableMovableFlags()
  276. {
  277. return booleanListToArray(cachedDockableMovableFlags);
  278. } //}}}
  279. //{{{ booleanListToArray() method
  280. /**
  281. * This method transforms a List<Boolean> into the corresponding
  282. * boolean[] array
  283. * @param list the List<Boolean> you want to convert
  284. * @return a boolean[] array
  285. */
  286. private boolean[] booleanListToArray(java.util.List<Boolean> list)
  287. {
  288. boolean[] returnValue = new boolean[list.size()];
  289. int i = 0;
  290. for (Boolean value : list)
  291. {
  292. returnValue[i++] = value.booleanValue();
  293. }
  294. return returnValue;
  295. } //}}}
  296. //{{{ Private members
  297. //{{{ Instance variables
  298. private PluginJAR plugin;
  299. // What is the purpose of this?
  300. private URL uri;
  301. private java.util.List<String> cachedDockableNames;
  302. private java.util.List<Boolean> cachedDockableActionFlags;
  303. private java.util.List<Boolean> cachedDockableMovableFlags;
  304. private String dockableName;
  305. private StringBuilder code;
  306. private boolean actions;
  307. private boolean movable;
  308. static final boolean MOVABLE_DEFAULT = false;
  309. private Stack<String> stateStack;
  310. //}}}
  311. //{{{ pushElement() method
  312. private String pushElement(String name)
  313. {
  314. name = (name == null) ? null : name.intern();
  315. stateStack.push(name);
  316. return name;
  317. } //}}}
  318. //{{{ peekElement() method
  319. private String peekElement()
  320. {
  321. return stateStack.peek();
  322. } //}}}
  323. //{{{ popElement() method
  324. private String popElement()
  325. {
  326. return stateStack.pop();
  327. } //}}}
  328. //}}}
  329. } //}}}
  330. //{{{ Window class
  331. class Window
  332. {
  333. PluginJAR plugin;
  334. String name;
  335. String code;
  336. boolean loaded;
  337. boolean movable;
  338. boolean isBeingCreated = false;
  339. //{{{ Window constructor
  340. Window(PluginJAR plugin, String name, String code,
  341. boolean actions, boolean movable)
  342. {
  343. this.plugin = plugin;
  344. this.name = name;
  345. this.code = code;
  346. this.movable = movable;
  347. if(code != null)
  348. loaded = true;
  349. if(actions)
  350. {
  351. ActionSet actionSet = (plugin == null
  352. ? jEdit.getBuiltInActionSet()
  353. : plugin.getActionSet());
  354. actionSet.addAction(new OpenAction(name));
  355. actionSet.addAction(new ToggleAction(name));
  356. actionSet.addAction(new FloatAction(name));
  357. String label = jEdit.getProperty(name
  358. + ".label");
  359. if(label == null)
  360. label = "NO LABEL PROPERTY: " + name;
  361. String[] args = { label };
  362. jEdit.setTemporaryProperty(name + ".label",
  363. label);
  364. jEdit.setTemporaryProperty(name
  365. + "-toggle.label",
  366. jEdit.getProperty(
  367. "view.docking.toggle.label",args));
  368. jEdit.setTemporaryProperty(name
  369. + "-toggle.toggle","true");
  370. jEdit.setTemporaryProperty(name
  371. + "-float.label",
  372. jEdit.getProperty(
  373. "view.docking.float.label",args));
  374. }
  375. } //}}}
  376. //{{{ load() method
  377. void load()
  378. {
  379. if(loaded)
  380. return;
  381. loadDockableWindows(plugin,plugin.getDockablesURI(),null);
  382. } //}}}
  383. //{{{ createDockableWindow() method
  384. JComponent createDockableWindow(View view, String position)
  385. {
  386. // Avoid infinite recursion
  387. synchronized(this)
  388. {
  389. if (isBeingCreated)
  390. return null;
  391. isBeingCreated = true;
  392. }
  393. load();
  394. if(!loaded)
  395. {
  396. Log.log(Log.WARNING,this,"Outdated cache");
  397. return null;
  398. }
  399. NameSpace nameSpace = new NameSpace(
  400. BeanShell.getNameSpace(),
  401. "DockableWindowManager.Factory"
  402. + ".createDockableWindow()");
  403. try
  404. {
  405. nameSpace.setVariable(
  406. "position",position);
  407. }
  408. catch(UtilEvalError e)
  409. {
  410. Log.log(Log.ERROR,this,e);
  411. }
  412. JComponent win = (JComponent)BeanShell.eval(view,
  413. nameSpace,code);
  414. synchronized(this)
  415. {
  416. isBeingCreated = false;
  417. }
  418. return win;
  419. } //}}}
  420. //{{{ OpenAction class
  421. class OpenAction extends EditAction
  422. {
  423. private String dockable;
  424. //{{{ OpenAction constructor
  425. OpenAction(String name)
  426. {
  427. super(name);
  428. this.dockable = name;
  429. } //}}}
  430. //{{{ invoke() method
  431. public void invoke(View view)
  432. {
  433. view.getDockableWindowManager()
  434. .showDockableWindow(dockable);
  435. } //}}}
  436. //{{{ getCode() method
  437. @Override
  438. public String getCode()
  439. {
  440. return "view.getDockableWindowManager()"
  441. + ".showDockableWindow(\"" + dockable + "\");";
  442. } //}}}
  443. } //}}}
  444. //{{{ ToggleAction class
  445. class ToggleAction extends EditAction
  446. {
  447. private String dockable;
  448. //{{{ ToggleAction constructor
  449. ToggleAction(String name)
  450. {
  451. super(name + "-toggle");
  452. this.dockable = name;
  453. } //}}}
  454. //{{{ invoke() method
  455. public void invoke(View view)
  456. {
  457. view.getDockableWindowManager()
  458. .toggleDockableWindow(dockable);
  459. } //}}}
  460. //{{{ isSelected() method
  461. public boolean isSelected(View view)
  462. {
  463. return view.getDockableWindowManager()
  464. .isDockableWindowVisible(dockable);
  465. } //}}}
  466. //{{{ getCode() method
  467. @Override
  468. public String getCode()
  469. {
  470. return "view.getDockableWindowManager()"
  471. + ".toggleDockableWindow(\"" + dockable + "\");";
  472. } //}}}
  473. } //}}}
  474. //{{{ FloatAction class
  475. class FloatAction extends EditAction
  476. {
  477. private String dockable;
  478. //{{{ FloatAction constructor
  479. FloatAction(String name)
  480. {
  481. super(name + "-float");
  482. this.dockable = name;
  483. } //}}}
  484. //{{{ invoke() method
  485. public void invoke(View view)
  486. {
  487. view.getDockableWindowManager()
  488. .floatDockableWindow(dockable);
  489. } //}}}
  490. //{{{ getCode() method
  491. @Override
  492. public String getCode()
  493. {
  494. return "view.getDockableWindowManager()"
  495. + ".floatDockableWindow(\"" + dockable + "\");";
  496. } //}}}
  497. } //}}}
  498. } //}}}
  499. private static DockableWindowFactory instance;
  500. private final Map<String, Window> dockableWindowFactories;
  501. }