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

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/gui/DockableWindowManager.java

#
Java | 1900 lines | 1323 code | 216 blank | 361 comment | 194 complexity | 8d3d0fed43f813f4fee9bfb7a8240f1e 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. * DockableWindowManager.java - manages dockable windows
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2004 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 bsh.*;
  25. import com.microstar.xml.*;
  26. import javax.swing.*;
  27. import java.awt.event.*;
  28. import java.awt.*;
  29. import java.io.*;
  30. import java.net.URL;
  31. import java.util.*;
  32. import org.gjt.sp.jedit.msg.*;
  33. import org.gjt.sp.jedit.*;
  34. import org.gjt.sp.util.Log;
  35. //}}}
  36. /**
  37. * The <code>DockableWindowManager</code> keeps track of dockable windows.
  38. * Each {@link org.gjt.sp.jedit.View} has an instance of this class.<p>
  39. *
  40. * <b>dockables.xml:</b><p>
  41. *
  42. * Dockable window definitions are read from <code>dockables.xml</code> files
  43. * contained inside plugin JARs. A dockable definition file has the following
  44. * form:
  45. *
  46. * <pre>&lt;?xml version="1.0"?&gt;
  47. *&lt;!DOCTYPE DOCKABLES SYSTEM "dockables.dtd"&gt;
  48. *&lt;DOCKABLES&gt;
  49. * &lt;DOCKABLE NAME="name"&gt;
  50. * // Code to create the dockable
  51. * &lt;/DOCKABLE&gt;
  52. *&lt;/DOCKABLES&gt;</pre>
  53. *
  54. * More than one <code>&lt;DOCKABLE&gt;<code> tag may be present. The code that
  55. * creates the dockable can reference any BeanShell built-in variable
  56. * (see {@link org.gjt.sp.jedit.BeanShell}), along with a variable
  57. * <code>position</code> whose value is one of
  58. * {@link #FLOATING}, {@link #TOP}, {@link #LEFT}, {@link #BOTTOM},
  59. * and {@link #RIGHT}.<p>
  60. *
  61. * The following properties must be defined for each dockable window:
  62. *
  63. * <ul>
  64. * <li><code><i>name</i>.title</code> - the string to show in the title bar
  65. * of the dockable.</li>
  66. * <li><code><i>name</i>.label</code> - the dockable's menu item label.</li>
  67. * </ul>
  68. *
  69. * A number of actions are automatically created for each dockable window:
  70. *
  71. * <ul>
  72. * <li><code><i>name</i></code> - opens the dockable window.</li>
  73. * <li><code><i>name</i>-toggle</code> - toggles the dockable window's visibility.</li>
  74. * <li><code><i>name</i>-float</code> - opens the dockable window in a new
  75. * floating window.</li>
  76. * </ul>
  77. *
  78. * Note that only the first action needs a <code>label</code> property, the
  79. * rest have automatically-generated labels.
  80. *
  81. * <b>Implementation details:</b><p>
  82. *
  83. * When an instance of this class is initialized by the {@link org.gjt.sp.jedit.View}
  84. * class, it
  85. * iterates through the list of registered dockable windows (from jEdit itself,
  86. * and any loaded plugins) and
  87. * examines options supplied by the user in the <b>Global
  88. * Options</b> dialog box. Any plugins designated for one of the
  89. * four docking positions are displayed.<p>
  90. *
  91. * To create an instance of a dockable window, the <code>DockableWindowManager</code>
  92. * finds and executes the BeanShell code extracted from the appropriate
  93. * <code>dockables.xml</code> file. This code will typically consist of a call
  94. * to the constructor of the dockable window component. The result of the
  95. * BeanShell expression, typically a newly constructed component, is placed
  96. * in a window managed by this class.
  97. *
  98. * @see org.gjt.sp.jedit.View#getDockableWindowManager()
  99. *
  100. * @author Slava Pestov
  101. * @author John Gellene (API documentation)
  102. * @version $Id: DockableWindowManager.java 5053 2004-05-29 01:55:26Z spestov $
  103. * @since jEdit 2.6pre3
  104. */
  105. public class DockableWindowManager extends JPanel implements EBComponent
  106. {
  107. //{{{ Static part of class
  108. //{{{ Constants
  109. /**
  110. * Floating position.
  111. * @since jEdit 2.6pre3
  112. */
  113. public static final String FLOATING = "floating";
  114. /**
  115. * Top position.
  116. * @since jEdit 2.6pre3
  117. */
  118. public static final String TOP = "top";
  119. /**
  120. * Left position.
  121. * @since jEdit 2.6pre3
  122. */
  123. public static final String LEFT = "left";
  124. /**
  125. * Bottom position.
  126. * @since jEdit 2.6pre3
  127. */
  128. public static final String BOTTOM = "bottom";
  129. /**
  130. * Right position.
  131. * @since jEdit 2.6pre3
  132. */
  133. public static final String RIGHT = "right";
  134. //}}}
  135. //{{{ loadDockableWindows() method
  136. /**
  137. * Plugins shouldn't need to call this method.
  138. * @since jEdit 4.2pre1
  139. */
  140. public static void loadDockableWindows(PluginJAR plugin, URL uri,
  141. PluginJAR.PluginCacheEntry cache)
  142. {
  143. Reader in = null;
  144. try
  145. {
  146. Log.log(Log.DEBUG,DockableWindowManager.class,
  147. "Loading dockables from " + uri);
  148. DockableListHandler dh = new DockableListHandler(plugin,uri);
  149. in = new BufferedReader(
  150. new InputStreamReader(
  151. uri.openStream()));
  152. XmlParser parser = new XmlParser();
  153. parser.setHandler(dh);
  154. parser.parse(null, null, in);
  155. if(cache != null)
  156. {
  157. cache.cachedDockableNames = dh.getCachedDockableNames();
  158. cache.cachedDockableActionFlags = dh.getCachedDockableActionFlags();
  159. }
  160. }
  161. catch(XmlException xe)
  162. {
  163. int line = xe.getLine();
  164. String message = xe.getMessage();
  165. Log.log(Log.ERROR,DockableWindowManager.class,uri + ":" + line
  166. + ": " + message);
  167. }
  168. catch(Exception e)
  169. {
  170. Log.log(Log.ERROR,DockableWindowManager.class,e);
  171. }
  172. finally
  173. {
  174. try
  175. {
  176. if(in != null)
  177. in.close();
  178. }
  179. catch(IOException io)
  180. {
  181. Log.log(Log.ERROR,DockableWindowManager.class,io);
  182. }
  183. }
  184. } //}}}
  185. //{{{ unloadDockableWindows() method
  186. /**
  187. * Plugins shouldn't need to call this method.
  188. * @since jEdit 4.2pre1
  189. */
  190. public static void unloadDockableWindows(PluginJAR plugin)
  191. {
  192. Iterator entries = dockableWindowFactories.entrySet().iterator();
  193. while(entries.hasNext())
  194. {
  195. Map.Entry entry = (Map.Entry)entries.next();
  196. Factory factory = (Factory)entry.getValue();
  197. if(factory.plugin == plugin)
  198. entries.remove();
  199. }
  200. } //}}}
  201. //{{{ cacheDockableWindows() method
  202. /**
  203. * @since jEdit 4.2pre1
  204. */
  205. public static void cacheDockableWindows(PluginJAR plugin,
  206. String[] name, boolean[] actions)
  207. {
  208. for(int i = 0; i < name.length; i++)
  209. {
  210. Factory factory = new Factory(plugin,
  211. name[i],null,actions[i]);
  212. dockableWindowFactories.put(name[i],factory);
  213. }
  214. } //}}}
  215. //{{{ registerDockableWindow() method
  216. public static void registerDockableWindow(PluginJAR plugin,
  217. String name, String code, boolean actions)
  218. {
  219. Factory factory = (Factory)dockableWindowFactories.get(name);
  220. if(factory != null)
  221. {
  222. factory.code = code;
  223. factory.loaded = true;
  224. }
  225. else
  226. {
  227. factory = new Factory(plugin,name,code,actions);
  228. dockableWindowFactories.put(name,factory);
  229. }
  230. } //}}}
  231. //{{{ getRegisteredDockableWindows() method
  232. public static String[] getRegisteredDockableWindows()
  233. {
  234. String[] retVal = new String[dockableWindowFactories.size()];
  235. Iterator entries = dockableWindowFactories.values().iterator();
  236. int i = 0;
  237. while(entries.hasNext())
  238. {
  239. Factory factory = (Factory)entries.next();
  240. retVal[i++] = factory.name;
  241. }
  242. return retVal;
  243. } //}}}
  244. //{{{ DockableListHandler class
  245. static class DockableListHandler extends HandlerBase
  246. {
  247. //{{{ DockableListHandler constructor
  248. DockableListHandler(PluginJAR plugin, URL uri)
  249. {
  250. this.plugin = plugin;
  251. this.uri = uri;
  252. stateStack = new Stack();
  253. actions = true;
  254. cachedDockableNames = new LinkedList();
  255. cachedDockableActionFlags = new LinkedList();
  256. } //}}}
  257. //{{{ resolveEntity() method
  258. public Object resolveEntity(String publicId, String systemId)
  259. {
  260. if("dockables.dtd".equals(systemId))
  261. {
  262. // this will result in a slight speed up, since we
  263. // don't need to read the DTD anyway, as AElfred is
  264. // non-validating
  265. return new StringReader("<!-- -->");
  266. /* try
  267. {
  268. return new BufferedReader(new InputStreamReader(
  269. getClass().getResourceAsStream
  270. ("/org/gjt/sp/jedit/dockables.dtd")));
  271. }
  272. catch(Exception e)
  273. {
  274. Log.log(Log.ERROR,this,"Error while opening"
  275. + " dockables.dtd:");
  276. Log.log(Log.ERROR,this,e);
  277. } */
  278. }
  279. return null;
  280. } //}}}
  281. //{{{ attribute() method
  282. public void attribute(String aname, String value, boolean isSpecified)
  283. {
  284. aname = (aname == null) ? null : aname.intern();
  285. value = (value == null) ? null : value.intern();
  286. if(aname == "NAME")
  287. dockableName = value;
  288. else if(aname == "NO_ACTIONS")
  289. actions = (value == "FALSE");
  290. } //}}}
  291. //{{{ doctypeDecl() method
  292. public void doctypeDecl(String name, String publicId,
  293. String systemId) throws Exception
  294. {
  295. if("DOCKABLES".equals(name))
  296. return;
  297. Log.log(Log.ERROR,this,uri + ": DOCTYPE must be DOCKABLES");
  298. } //}}}
  299. //{{{ charData() method
  300. public void charData(char[] c, int off, int len)
  301. {
  302. String tag = peekElement();
  303. String text = new String(c, off, len);
  304. if (tag == "DOCKABLE")
  305. {
  306. code = text;
  307. }
  308. } //}}}
  309. //{{{ startElement() method
  310. public void startElement(String tag)
  311. {
  312. tag = pushElement(tag);
  313. } //}}}
  314. //{{{ endElement() method
  315. public void endElement(String name)
  316. {
  317. if(name == null)
  318. return;
  319. String tag = peekElement();
  320. if(name.equals(tag))
  321. {
  322. if(tag == "DOCKABLE")
  323. {
  324. registerDockableWindow(plugin,
  325. dockableName,code,actions);
  326. cachedDockableNames.add(dockableName);
  327. cachedDockableActionFlags.add(
  328. Boolean.valueOf(actions));
  329. // make default be true for the next
  330. // action
  331. actions = true;
  332. }
  333. popElement();
  334. }
  335. else
  336. {
  337. // can't happen
  338. throw new InternalError();
  339. }
  340. } //}}}
  341. //{{{ startDocument() method
  342. public void startDocument()
  343. {
  344. try
  345. {
  346. pushElement(null);
  347. }
  348. catch (Exception e)
  349. {
  350. e.printStackTrace();
  351. }
  352. } //}}}
  353. //{{{ getCachedDockableNames() method
  354. public String[] getCachedDockableNames()
  355. {
  356. return (String[])cachedDockableNames.toArray(new String[cachedDockableNames.size()]);
  357. } //}}}
  358. //{{{ getCachedDockableActionFlags() method
  359. public boolean[] getCachedDockableActionFlags()
  360. {
  361. boolean[] returnValue = new boolean[
  362. cachedDockableActionFlags.size()];
  363. Iterator iter = cachedDockableActionFlags.iterator();
  364. int i = 0;
  365. while(iter.hasNext())
  366. {
  367. boolean flag = ((Boolean)iter.next())
  368. .booleanValue();
  369. returnValue[i++] = flag;
  370. }
  371. return returnValue;
  372. } //}}}
  373. //{{{ Private members
  374. //{{{ Instance variables
  375. private PluginJAR plugin;
  376. private URL uri;
  377. private java.util.List cachedDockableNames;
  378. private java.util.List cachedDockableActionFlags;
  379. private String dockableName;
  380. private String code;
  381. private boolean actions;
  382. private Stack stateStack;
  383. //}}}
  384. //{{{ pushElement() method
  385. private String pushElement(String name)
  386. {
  387. name = (name == null) ? null : name.intern();
  388. stateStack.push(name);
  389. return name;
  390. } //}}}
  391. //{{{ peekElement() method
  392. private String peekElement()
  393. {
  394. return (String) stateStack.peek();
  395. } //}}}
  396. //{{{ popElement() method
  397. private String popElement()
  398. {
  399. return (String) stateStack.pop();
  400. } //}}}
  401. //}}}
  402. } //}}}
  403. //{{{ Factory class
  404. static class Factory
  405. {
  406. PluginJAR plugin;
  407. String name;
  408. String code;
  409. boolean loaded;
  410. //{{{ Factory constructor
  411. Factory(PluginJAR plugin, String name, String code,
  412. boolean actions)
  413. {
  414. this.plugin = plugin;
  415. this.name = name;
  416. this.code = code;
  417. if(code != null)
  418. loaded = true;
  419. if(actions)
  420. {
  421. ActionSet actionSet = (plugin == null
  422. ? jEdit.getBuiltInActionSet()
  423. : plugin.getActionSet());
  424. actionSet.addAction(new OpenAction(name));
  425. actionSet.addAction(new ToggleAction(name));
  426. actionSet.addAction(new FloatAction(name));
  427. String label = jEdit.getProperty(name
  428. + ".label");
  429. if(label == null)
  430. label = "NO LABEL PROPERTY: " + name;
  431. String[] args = { label };
  432. jEdit.setTemporaryProperty(name + ".label",
  433. label);
  434. jEdit.setTemporaryProperty(name
  435. + "-toggle.label",
  436. jEdit.getProperty(
  437. "view.docking.toggle.label",args));
  438. jEdit.setTemporaryProperty(name
  439. + "-toggle.toggle","true");
  440. jEdit.setTemporaryProperty(name
  441. + "-float.label",
  442. jEdit.getProperty(
  443. "view.docking.float.label",args));
  444. }
  445. } //}}}
  446. //{{{ load() method
  447. void load()
  448. {
  449. if(loaded)
  450. return;
  451. loadDockableWindows(plugin,plugin.getDockablesURI(),null);
  452. } //}}}
  453. //{{{ createDockableWindow() method
  454. JComponent createDockableWindow(View view, String position)
  455. {
  456. load();
  457. if(!loaded)
  458. {
  459. Log.log(Log.WARNING,this,"Outdated cache");
  460. return null;
  461. }
  462. NameSpace nameSpace = new NameSpace(
  463. BeanShell.getNameSpace(),
  464. "DockableWindowManager.Factory"
  465. + ".createDockableWindow()");
  466. try
  467. {
  468. nameSpace.setVariable(
  469. "position",position);
  470. }
  471. catch(UtilEvalError e)
  472. {
  473. Log.log(Log.ERROR,this,e);
  474. }
  475. JComponent win = (JComponent)BeanShell.eval(view,
  476. nameSpace,code);
  477. return win;
  478. } //}}}
  479. //{{{ OpenAction class
  480. static class OpenAction extends EditAction
  481. {
  482. private String dockable;
  483. //{{{ OpenAction constructor
  484. OpenAction(String name)
  485. {
  486. super(name);
  487. this.dockable = name;
  488. } //}}}
  489. //{{{ invoke() method
  490. public void invoke(View view)
  491. {
  492. view.getDockableWindowManager()
  493. .showDockableWindow(dockable);
  494. } //}}}
  495. //{{{ getCode() method
  496. public String getCode()
  497. {
  498. return "view.getDockableWindowManager()"
  499. + ".showDockableWindow(\"" + dockable + "\");";
  500. } //}}}
  501. } //}}}
  502. //{{{ ToggleAction class
  503. static class ToggleAction extends EditAction
  504. {
  505. private String dockable;
  506. //{{{ ToggleAction constructor
  507. ToggleAction(String name)
  508. {
  509. super(name + "-toggle");
  510. this.dockable = name;
  511. } //}}}
  512. //{{{ invoke() method
  513. public void invoke(View view)
  514. {
  515. view.getDockableWindowManager()
  516. .toggleDockableWindow(dockable);
  517. } //}}}
  518. //{{{ isSelected() method
  519. public boolean isSelected(View view)
  520. {
  521. return view.getDockableWindowManager()
  522. .isDockableWindowVisible(dockable);
  523. } //}}}
  524. //{{{ getCode() method
  525. public String getCode()
  526. {
  527. return "view.getDockableWindowManager()"
  528. + ".toggleDockableWindow(\"" + dockable + "\");";
  529. } //}}}
  530. } //}}}
  531. //{{{ FloatAction class
  532. static class FloatAction extends EditAction
  533. {
  534. private String dockable;
  535. //{{{ FloatAction constructor
  536. FloatAction(String name)
  537. {
  538. super(name + "-float");
  539. this.dockable = name;
  540. } //}}}
  541. //{{{ invoke() method
  542. public void invoke(View view)
  543. {
  544. view.getDockableWindowManager()
  545. .floatDockableWindow(dockable);
  546. } //}}}
  547. //{{{ getCode() method
  548. public String getCode()
  549. {
  550. return "view.getDockableWindowManager()"
  551. + ".floatDockableWindow(\"" + dockable + "\");";
  552. } //}}}
  553. } //}}}
  554. } //}}}
  555. private static HashMap dockableWindowFactories;
  556. //{{{ Static initializer
  557. static
  558. {
  559. dockableWindowFactories = new HashMap();
  560. } //}}}
  561. //}}}
  562. //{{{ Instance part of class
  563. //{{{ DockableWindowManager constructor
  564. /**
  565. * Creates a new dockable window manager.
  566. * @param view The view
  567. * @since jEdit 2.6pre3
  568. */
  569. public DockableWindowManager(View view, View.ViewConfig config)
  570. {
  571. setLayout(new DockableLayout());
  572. this.view = view;
  573. windows = new Hashtable();
  574. clones = new ArrayList();
  575. top = new PanelWindowContainer(this,TOP,config.topPos);
  576. left = new PanelWindowContainer(this,LEFT,config.leftPos);
  577. bottom = new PanelWindowContainer(this,BOTTOM,config.bottomPos);
  578. right = new PanelWindowContainer(this,RIGHT,config.rightPos);
  579. add(DockableLayout.TOP_BUTTONS,top.buttonPanel);
  580. add(DockableLayout.LEFT_BUTTONS,left.buttonPanel);
  581. add(DockableLayout.BOTTOM_BUTTONS,bottom.buttonPanel);
  582. add(DockableLayout.RIGHT_BUTTONS,right.buttonPanel);
  583. add(TOP,top.dockablePanel);
  584. add(LEFT,left.dockablePanel);
  585. add(BOTTOM,bottom.dockablePanel);
  586. add(RIGHT,right.dockablePanel);
  587. } //}}}
  588. //{{{ init() method
  589. /**
  590. * Initialises dockable window manager. Do not call this method directly.
  591. */
  592. public void init()
  593. {
  594. EditBus.addToBus(this);
  595. Iterator entries = dockableWindowFactories.values().iterator();
  596. while(entries.hasNext())
  597. addEntry((Factory)entries.next());
  598. propertiesChanged();
  599. } //}}}
  600. //{{{ getView() method
  601. /**
  602. * Returns this dockable window manager's view.
  603. * @since jEdit 4.0pre2
  604. */
  605. public View getView()
  606. {
  607. return view;
  608. } //}}}
  609. //{{{ floatDockableWindow() method
  610. /**
  611. * Opens a new instance of the specified dockable window in a floating
  612. * container.
  613. * @param name The dockable window name
  614. * @return The new dockable window instance
  615. * @since jEdit 4.1pre2
  616. */
  617. public JComponent floatDockableWindow(String name)
  618. {
  619. Entry entry = (Entry)windows.get(name);
  620. if(entry == null)
  621. {
  622. Log.log(Log.ERROR,this,"Unknown dockable window: " + name);
  623. return null;
  624. }
  625. // create a copy of this dockable window and float it
  626. Entry newEntry = new Entry(entry.factory,FLOATING);
  627. newEntry.win = newEntry.factory.createDockableWindow(view,FLOATING);
  628. if(newEntry.win != null)
  629. {
  630. newEntry.container = new FloatingWindowContainer(this,true);
  631. newEntry.container.register(newEntry);
  632. newEntry.container.show(newEntry);
  633. }
  634. clones.add(newEntry);
  635. return newEntry.win;
  636. } //}}}
  637. //{{{ showDockableWindow() method
  638. /**
  639. * Opens the specified dockable window.
  640. * @param name The dockable window name
  641. * @since jEdit 2.6pre3
  642. */
  643. public void showDockableWindow(String name)
  644. {
  645. Entry entry = (Entry)windows.get(name);
  646. if(entry == null)
  647. {
  648. Log.log(Log.ERROR,this,"Unknown dockable window: " + name);
  649. return;
  650. }
  651. if(entry.win == null)
  652. {
  653. entry.win = entry.factory.createDockableWindow(
  654. view,entry.position);
  655. }
  656. if(entry.win != null)
  657. {
  658. if(entry.position.equals(FLOATING)
  659. && entry.container == null)
  660. {
  661. entry.container = new FloatingWindowContainer(
  662. this,view.isPlainView());
  663. entry.container.register(entry);
  664. }
  665. entry.container.show(entry);
  666. }
  667. else
  668. /* an error occurred */;
  669. } //}}}
  670. //{{{ addDockableWindow() method
  671. /**
  672. * Opens the specified dockable window. As of jEdit 4.0pre1, has the
  673. * same effect as calling showDockableWindow().
  674. * @param name The dockable window name
  675. * @since jEdit 2.6pre3
  676. */
  677. public void addDockableWindow(String name)
  678. {
  679. showDockableWindow(name);
  680. } //}}}
  681. //{{{ hideDockableWindow() method
  682. /**
  683. * Hides the specified dockable window.
  684. * @param name The dockable window name
  685. * @since jEdit 2.6pre3
  686. */
  687. public void hideDockableWindow(String name)
  688. {
  689. Entry entry = (Entry)windows.get(name);
  690. if(entry == null)
  691. {
  692. Log.log(Log.ERROR,this,"Unknown dockable window: " + name);
  693. return;
  694. }
  695. if(entry.win == null)
  696. return;
  697. entry.container.show(null);
  698. } //}}}
  699. //{{{ removeDockableWindow() method
  700. /**
  701. * Hides the specified dockable window. As of jEdit 4.2pre1, has the
  702. * same effect as calling hideDockableWindow().
  703. * @param name The dockable window name
  704. * @since jEdit 4.2pre1
  705. */
  706. public void removeDockableWindow(String name)
  707. {
  708. hideDockableWindow(name);
  709. } //}}}
  710. //{{{ toggleDockableWindow() method
  711. /**
  712. * Toggles the visibility of the specified dockable window.
  713. * @param name The dockable window name
  714. */
  715. public void toggleDockableWindow(String name)
  716. {
  717. if(isDockableWindowVisible(name))
  718. removeDockableWindow(name);
  719. else
  720. addDockableWindow(name);
  721. } //}}}
  722. //{{{ getDockableWindow() method
  723. /**
  724. * Returns the specified dockable window.
  725. *
  726. * Note that this method
  727. * will return null if the dockable has not been added yet.
  728. * Make sure you call {@link #addDockableWindow(String)} first.
  729. *
  730. * @param name The name of the dockable window
  731. * @since jEdit 4.1pre2
  732. */
  733. public JComponent getDockableWindow(String name)
  734. {
  735. return getDockable(name);
  736. } //}}}
  737. //{{{ getDockable() method
  738. /**
  739. * Returns the specified dockable window.
  740. *
  741. * Note that this method
  742. * will return null if the dockable has not been added yet.
  743. * Make sure you call {@link #addDockableWindow(String)} first.
  744. *
  745. * For historical reasons, this
  746. * does the same thing as {@link #getDockableWindow(String)}.
  747. *
  748. * @param name The name of the dockable window
  749. * @since jEdit 4.0pre1
  750. */
  751. public JComponent getDockable(String name)
  752. {
  753. Entry entry = (Entry)windows.get(name);
  754. if(entry == null || entry.win == null)
  755. return null;
  756. else
  757. return entry.win;
  758. } //}}}
  759. //{{{ getDockableTitle() method
  760. /**
  761. * Returns the title of the specified dockable window.
  762. * @param name The name of the dockable window.
  763. * @since jEdit 4.1pre5
  764. */
  765. public String getDockableTitle(String name)
  766. {
  767. String title = jEdit.getProperty(name + ".title");
  768. if(title == null)
  769. return "NO TITLE PROPERTY: " + name;
  770. else
  771. return title;
  772. } //}}}
  773. //{{{ isDockableWindowVisible() method
  774. /**
  775. * Returns if the specified dockable window is visible.
  776. * @param name The dockable window name
  777. */
  778. public boolean isDockableWindowVisible(String name)
  779. {
  780. Entry entry = (Entry)windows.get(name);
  781. if(entry == null || entry.win == null)
  782. return false;
  783. else
  784. return entry.container.isVisible(entry);
  785. } //}}}
  786. //{{{ isDockableWindowDocked() method
  787. /**
  788. * Returns if the specified dockable window is docked into the
  789. * view.
  790. * @param name The dockable's name
  791. * @since jEdit 4.0pre2
  792. */
  793. public boolean isDockableWindowDocked(String name)
  794. {
  795. Entry entry = (Entry)windows.get(name);
  796. if(entry == null)
  797. return false;
  798. else
  799. return !entry.position.equals(FLOATING);
  800. } //}}}
  801. //{{{ closeCurrentArea() method
  802. /**
  803. * Closes the currently focused docking area.
  804. * @since jEdit 4.1pre3
  805. */
  806. public void closeCurrentArea()
  807. {
  808. // I don't know of any other way to fix this, since invoking this
  809. // command from a menu results in the focus owner being the menu
  810. // until the menu goes away.
  811. SwingUtilities.invokeLater(new Runnable()
  812. {
  813. public void run()
  814. {
  815. Component comp = view.getFocusOwner();
  816. while(comp != null)
  817. {
  818. //System.err.println(comp.getClass());
  819. if(comp instanceof PanelWindowContainer
  820. .DockablePanel)
  821. {
  822. PanelWindowContainer container =
  823. ((PanelWindowContainer.DockablePanel)
  824. comp).getWindowContainer();
  825. container.show(null);
  826. return;
  827. }
  828. comp = comp.getParent();
  829. }
  830. getToolkit().beep();
  831. }
  832. });
  833. } //}}}
  834. //{{{ close() method
  835. /**
  836. * Called when the view is being closed.
  837. * @since jEdit 2.6pre3
  838. */
  839. public void close()
  840. {
  841. EditBus.removeFromBus(this);
  842. Iterator iter = windows.values().iterator();
  843. while(iter.hasNext())
  844. {
  845. Entry entry = (Entry)iter.next();
  846. if(entry.win != null)
  847. {
  848. entry.container.unregister(entry);
  849. }
  850. }
  851. iter = clones.iterator();
  852. while(iter.hasNext())
  853. {
  854. Entry entry = (Entry)iter.next();
  855. if(entry.win != null)
  856. {
  857. entry.container.unregister(entry);
  858. }
  859. }
  860. } //}}}
  861. //{{{ getTopDockingArea() method
  862. public PanelWindowContainer getTopDockingArea()
  863. {
  864. return top;
  865. } //}}}
  866. //{{{ getLeftDockingArea() method
  867. public PanelWindowContainer getLeftDockingArea()
  868. {
  869. return left;
  870. } //}}}
  871. //{{{ getBottomDockingArea() method
  872. public PanelWindowContainer getBottomDockingArea()
  873. {
  874. return bottom;
  875. } //}}}
  876. //{{{ getRightDockingArea() method
  877. public PanelWindowContainer getRightDockingArea()
  878. {
  879. return right;
  880. } //}}}
  881. //{{{ createPopupMenu() method
  882. public JPopupMenu createPopupMenu(
  883. final DockableWindowContainer container,
  884. final String dockable,
  885. final boolean clone)
  886. {
  887. JPopupMenu popup = new JPopupMenu();
  888. if(dockable == null && container instanceof PanelWindowContainer)
  889. {
  890. ActionListener listener = new ActionListener()
  891. {
  892. public void actionPerformed(ActionEvent evt)
  893. {
  894. showDockableWindow(evt.getActionCommand());
  895. }
  896. };
  897. String[] dockables = ((PanelWindowContainer)
  898. container).getDockables();
  899. for(int i = 0; i < dockables.length; i++)
  900. {
  901. String name = dockables[i];
  902. JMenuItem item = new JMenuItem(getDockableTitle(name));
  903. item.setActionCommand(name);
  904. item.addActionListener(listener);
  905. popup.add(item);
  906. }
  907. }
  908. else
  909. {
  910. JMenuItem caption = new JMenuItem(getDockableTitle(dockable));
  911. caption.setEnabled(false);
  912. popup.add(caption);
  913. popup.addSeparator();
  914. String currentPos = jEdit.getProperty(dockable + ".dock-position",FLOATING);
  915. if(!clone)
  916. {
  917. String[] positions = { FLOATING, TOP, LEFT, BOTTOM, RIGHT };
  918. for(int i = 0; i < positions.length; i++)
  919. {
  920. final String pos = positions[i];
  921. if(pos.equals(currentPos))
  922. continue;
  923. JMenuItem moveMenuItem = new JMenuItem(jEdit.getProperty("view.docking.menu-"
  924. + pos));
  925. moveMenuItem.addActionListener(new ActionListener()
  926. {
  927. public void actionPerformed(ActionEvent evt)
  928. {
  929. jEdit.setProperty(dockable + ".dock-position",pos);
  930. EditBus.send(new DockableWindowUpdate(
  931. DockableWindowManager.this,
  932. DockableWindowUpdate.PROPERTIES_CHANGED,
  933. null
  934. ));
  935. showDockableWindow(dockable);
  936. }
  937. });
  938. popup.add(moveMenuItem);
  939. }
  940. popup.addSeparator();
  941. }
  942. JMenuItem cloneMenuItem = new JMenuItem(jEdit.getProperty("view.docking.menu-clone"));
  943. cloneMenuItem.addActionListener(new ActionListener()
  944. {
  945. public void actionPerformed(ActionEvent evt)
  946. {
  947. floatDockableWindow(dockable);
  948. }
  949. });
  950. popup.add(cloneMenuItem);
  951. popup.addSeparator();
  952. JMenuItem closeMenuItem = new JMenuItem(jEdit.getProperty("view.docking.menu-close"));
  953. closeMenuItem.addActionListener(new ActionListener()
  954. {
  955. public void actionPerformed(ActionEvent evt)
  956. {
  957. if(clone)
  958. ((FloatingWindowContainer)container).dispose();
  959. else
  960. removeDockableWindow(dockable);
  961. }
  962. });
  963. popup.add(closeMenuItem);
  964. if(!(clone || currentPos.equals(FLOATING)))
  965. {
  966. JMenuItem undockMenuItem = new JMenuItem(jEdit.getProperty("view.docking.menu-undock"));
  967. undockMenuItem.addActionListener(new ActionListener()
  968. {
  969. public void actionPerformed(ActionEvent evt)
  970. {
  971. jEdit.setProperty(dockable + ".dock-position",FLOATING);
  972. EditBus.send(new DockableWindowUpdate(
  973. DockableWindowManager.this,
  974. DockableWindowUpdate.PROPERTIES_CHANGED,
  975. null
  976. ));
  977. }
  978. });
  979. popup.add(undockMenuItem);
  980. }
  981. }
  982. return popup;
  983. } //}}}
  984. //{{{ paintChildren() method
  985. public void paintChildren(Graphics g)
  986. {
  987. super.paintChildren(g);
  988. if(resizeRect != null)
  989. {
  990. g.setColor(Color.darkGray);
  991. g.fillRect(resizeRect.x,resizeRect.y,
  992. resizeRect.width,resizeRect.height);
  993. }
  994. } //}}}
  995. //{{{ handleMessage() method
  996. public void handleMessage(EBMessage msg)
  997. {
  998. if(msg instanceof DockableWindowUpdate)
  999. {
  1000. if(((DockableWindowUpdate)msg).getWhat()
  1001. == DockableWindowUpdate.PROPERTIES_CHANGED)
  1002. propertiesChanged();
  1003. }
  1004. else if(msg instanceof PropertiesChanged)
  1005. propertiesChanged();
  1006. else if(msg instanceof PluginUpdate)
  1007. {
  1008. PluginUpdate pmsg = (PluginUpdate)msg;
  1009. if(pmsg.getWhat() == PluginUpdate.LOADED)
  1010. {
  1011. Iterator iter = dockableWindowFactories
  1012. .values().iterator();
  1013. while(iter.hasNext())
  1014. {
  1015. Factory factory = (Factory)iter.next();
  1016. if(factory.plugin == pmsg.getPluginJAR())
  1017. addEntry(factory);
  1018. }
  1019. propertiesChanged();
  1020. }
  1021. else if(pmsg.isExiting())
  1022. {
  1023. // we don't care
  1024. }
  1025. else if(pmsg.getWhat() == PluginUpdate.DEACTIVATED)
  1026. {
  1027. Iterator iter = getAllPluginEntries(
  1028. pmsg.getPluginJAR(),false);
  1029. while(iter.hasNext())
  1030. {
  1031. Entry entry = (Entry)iter.next();
  1032. if(entry.container != null)
  1033. entry.container.remove(entry);
  1034. }
  1035. }
  1036. else if(pmsg.getWhat() == PluginUpdate.UNLOADED)
  1037. {
  1038. Iterator iter = getAllPluginEntries(
  1039. pmsg.getPluginJAR(),true);
  1040. while(iter.hasNext())
  1041. {
  1042. Entry entry = (Entry)iter.next();
  1043. if(entry.container != null)
  1044. {
  1045. entry.container.unregister(entry);
  1046. entry.win = null;
  1047. entry.container = null;
  1048. }
  1049. }
  1050. }
  1051. }
  1052. } //}}}
  1053. //{{{ Package-private members
  1054. int resizePos;
  1055. Rectangle resizeRect;
  1056. //{{{ setResizePos() method
  1057. void setResizePos(int resizePos, PanelWindowContainer resizing)
  1058. {
  1059. this.resizePos = resizePos;
  1060. if(resizePos < 0)
  1061. resizePos = 0;
  1062. Rectangle newResizeRect = new Rectangle(0,0,
  1063. PanelWindowContainer.SPLITTER_WIDTH - 2,
  1064. PanelWindowContainer.SPLITTER_WIDTH - 2);
  1065. if(resizing == top)
  1066. {
  1067. resizePos = Math.min(resizePos,getHeight()
  1068. - top.buttonPanel.getHeight()
  1069. - bottom.dockablePanel.getHeight()
  1070. - bottom.buttonPanel.getHeight()
  1071. - PanelWindowContainer.SPLITTER_WIDTH);
  1072. newResizeRect.x = top.dockablePanel.getX() + 1;
  1073. newResizeRect.y = resizePos + top.buttonPanel.getHeight() + 1;
  1074. newResizeRect.width = top.dockablePanel.getWidth() - 2;
  1075. }
  1076. else if(resizing == left)
  1077. {
  1078. resizePos = Math.min(resizePos,getWidth()
  1079. - left.buttonPanel.getWidth()
  1080. - right.dockablePanel.getWidth()
  1081. - right.buttonPanel.getWidth()
  1082. - PanelWindowContainer.SPLITTER_WIDTH);
  1083. newResizeRect.x = resizePos + left.buttonPanel.getWidth() + 1;
  1084. newResizeRect.y = left.dockablePanel.getY() + 1;
  1085. newResizeRect.height = left.dockablePanel.getHeight() - 2;
  1086. }
  1087. else if(resizing == bottom)
  1088. {
  1089. resizePos = Math.min(resizePos,getHeight()
  1090. - bottom.buttonPanel.getHeight()
  1091. - top.dockablePanel.getHeight()
  1092. - top.buttonPanel.getHeight()
  1093. - PanelWindowContainer.SPLITTER_WIDTH);
  1094. newResizeRect.x = bottom.dockablePanel.getX() + 1;
  1095. newResizeRect.y = getHeight() - bottom.buttonPanel.getHeight() - resizePos
  1096. - PanelWindowContainer.SPLITTER_WIDTH + 2;
  1097. newResizeRect.width = bottom.dockablePanel.getWidth() - 2;
  1098. }
  1099. else if(resizing == right)
  1100. {
  1101. resizePos = Math.min(resizePos,getWidth()
  1102. - right.buttonPanel.getWidth()
  1103. - left.dockablePanel.getWidth()
  1104. - left.buttonPanel.getWidth()
  1105. - PanelWindowContainer.SPLITTER_WIDTH);
  1106. newResizeRect.x = getWidth() - right.buttonPanel.getWidth() - resizePos
  1107. - PanelWindowContainer.SPLITTER_WIDTH + 1;
  1108. newResizeRect.y = right.dockablePanel.getY() + 1;
  1109. newResizeRect.height = right.dockablePanel.getHeight() - 2;
  1110. }
  1111. Rectangle toRepaint;
  1112. if(resizeRect == null)
  1113. toRepaint = newResizeRect;
  1114. else
  1115. toRepaint = resizeRect.union(newResizeRect);
  1116. resizeRect = newResizeRect;
  1117. repaint(toRepaint);
  1118. } //}}}
  1119. //{{{ finishResizing() method
  1120. void finishResizing()
  1121. {
  1122. resizeRect = null;
  1123. repaint();
  1124. } //}}}
  1125. //}}}
  1126. //{{{ Private members
  1127. private View view;
  1128. private Hashtable windows;
  1129. private boolean alternateLayout;
  1130. private PanelWindowContainer left;
  1131. private PanelWindowContainer right;
  1132. private PanelWindowContainer top;
  1133. private PanelWindowContainer bottom;
  1134. private ArrayList clones;
  1135. //{{{ propertiesChanged() method
  1136. private void propertiesChanged()
  1137. {
  1138. if(view.isPlainView())
  1139. return;
  1140. alternateLayout = jEdit.getBooleanProperty("view.docking.alternateLayout");
  1141. String[] windowList = getRegisteredDockableWindows();
  1142. for(int i = 0; i < windowList.length; i++)
  1143. {
  1144. String dockable = windowList[i];
  1145. Entry entry = (Entry)windows.get(dockable);
  1146. String newPosition = jEdit.getProperty(dockable
  1147. + ".dock-position",FLOATING);
  1148. if(newPosition.equals(entry.position))
  1149. {
  1150. continue;
  1151. }
  1152. entry.position = newPosition;
  1153. if(entry.container != null)
  1154. {
  1155. entry.container.unregister(entry);
  1156. entry.container = null;
  1157. entry.win = null;
  1158. }
  1159. if(newPosition.equals(FLOATING))
  1160. /* do nothing */;
  1161. else
  1162. {
  1163. if(newPosition.equals(TOP))
  1164. entry.container = top;
  1165. else if(newPosition.equals(LEFT))
  1166. entry.container = left;
  1167. else if(newPosition.equals(BOTTOM))
  1168. entry.container = bottom;
  1169. else if(newPosition.equals(RIGHT))
  1170. entry.container = right;
  1171. else
  1172. {
  1173. Log.log(Log.WARNING,this,
  1174. "Unknown position: "
  1175. + newPosition);
  1176. continue;
  1177. }
  1178. entry.container.register(entry);
  1179. }
  1180. }
  1181. top.sortDockables();
  1182. left.sortDockables();
  1183. bottom.sortDockables();
  1184. right.sortDockables();
  1185. revalidate();
  1186. repaint();
  1187. } //}}}
  1188. //{{{ addEntry() method
  1189. private void addEntry(Factory factory)
  1190. {
  1191. Entry e;
  1192. if(view.isPlainView())
  1193. {
  1194. // don't show menu items to dock into a plain view
  1195. e = new Entry(factory,FLOATING);
  1196. }
  1197. else
  1198. {
  1199. e = new Entry(factory);
  1200. if(e.position.equals(FLOATING))
  1201. /* nothing to do */;
  1202. else if(e.position.equals(TOP))
  1203. e.container = top;
  1204. else if(e.position.equals(LEFT))
  1205. e.container = left;
  1206. else if(e.position.equals(BOTTOM))
  1207. e.container = bottom;
  1208. else if(e.position.equals(RIGHT))
  1209. e.container = right;
  1210. else
  1211. {
  1212. Log.log(Log.WARNING,this,
  1213. "Unknown position: "
  1214. + e.position);
  1215. }
  1216. if(e.container != null)
  1217. e.container.register(e);
  1218. }
  1219. windows.put(factory.name,e);
  1220. } //}}}
  1221. //{{{ getAllPluginEntries() method
  1222. /**
  1223. * If remove is false, only remove from clones list, otherwise remove
  1224. * from both entries and clones.
  1225. */
  1226. private Iterator getAllPluginEntries(PluginJAR plugin, boolean remove)
  1227. {
  1228. java.util.List returnValue = new LinkedList();
  1229. Iterator iter = windows.values().iterator();
  1230. while(iter.hasNext())
  1231. {
  1232. Entry entry = (Entry)iter.next();
  1233. if(entry.factory.plugin == plugin)
  1234. {
  1235. returnValue.add(entry);
  1236. if(remove)
  1237. iter.remove();
  1238. }
  1239. }
  1240. iter = clones.iterator();
  1241. while(iter.hasNext())
  1242. {
  1243. Entry entry = (Entry)iter.next();
  1244. if(entry.factory.plugin == plugin)
  1245. {
  1246. returnValue.add(entry);
  1247. iter.remove();
  1248. }
  1249. }
  1250. return returnValue.iterator();
  1251. } //}}}
  1252. //}}}
  1253. //}}}
  1254. //{{{ DockableLayout class
  1255. public class DockableLayout implements LayoutManager2
  1256. {
  1257. // for backwards compatibility with plugins that fiddle with
  1258. // jEdit's UI layout
  1259. static final String CENTER = BorderLayout.CENTER;
  1260. public static final String TOP_TOOLBARS = "top-toolbars";
  1261. public static final String BOTTOM_TOOLBARS = "bottom-toolbars";
  1262. static final String TOP_BUTTONS = "top-buttons";
  1263. static final String LEFT_BUTTONS = "left-buttons";
  1264. static final String BOTTOM_BUTTONS = "bottom-buttons";
  1265. static final String RIGHT_BUTTONS = "right-buttons";
  1266. Component topToolbars, bottomToolbars;
  1267. Component center;
  1268. Component top, left, bottom, right;
  1269. Component topButtons, leftButtons, bottomButtons, rightButtons;
  1270. //{{{ addLayoutComponent() method
  1271. public void addLayoutComponent(String name, Component comp)
  1272. {
  1273. addLayoutComponent(comp,name);
  1274. } //}}}
  1275. //{{{ addLayoutComponent() method
  1276. public void addLayoutComponent(Component comp, Object cons)
  1277. {
  1278. if(cons == null || CENTER.equals(cons))
  1279. center = comp;
  1280. else if(TOP_TOOLBARS.equals(cons))
  1281. topToolbars = comp;
  1282. else if(BOTTOM_TOOLBARS.equals(cons))
  1283. bottomToolbars = comp;
  1284. else if(TOP.equals(cons))
  1285. top = comp;
  1286. else if(LEFT.equals(cons))
  1287. left = comp;
  1288. else if(BOTTOM.equals(cons))
  1289. bottom = comp;
  1290. else if(RIGHT.equals(cons))
  1291. right = comp;
  1292. else if(TOP_BUTTONS.equals(cons))
  1293. topButtons = comp;
  1294. else if(LEFT_BUTTONS.equals(cons))
  1295. leftButtons = comp;
  1296. else if(BOTTOM_BUTTONS.equals(cons))
  1297. bottomButtons = comp;
  1298. else if(RIGHT_BUTTONS.equals(cons))
  1299. rightButtons = comp;
  1300. } //}}}
  1301. //{{{ removeLayoutComponent() method
  1302. public void removeLayoutComponent(Component comp)
  1303. {
  1304. if(center == comp)
  1305. center = null;
  1306. if(comp == topToolbars)
  1307. topToolbars = null;
  1308. if(comp == bottomToolbars)
  1309. bottomToolbars = null;
  1310. {
  1311. // none of the others are ever meant to be
  1312. // removed. retarded, eh? this needs to be
  1313. // fixed eventually, for plugins might
  1314. // want to do weird stuff to jEdit's UI
  1315. }
  1316. } //}}}
  1317. //{{{ preferredLayoutSize() method
  1318. public Dimension preferredLayoutSize(Container parent)
  1319. {
  1320. Dimension prefSize = new Dimension(0,0);
  1321. Dimension _top = top.getPreferredSize();
  1322. Dimension _left = left.getPreferredSize();
  1323. Dimension _bottom = bottom.getPreferredSize();
  1324. Dimension _right = right.getPreferredSize();
  1325. Dimension _topButtons = topButtons.getPreferredSize();
  1326. Dimension _leftButtons = leftButtons.getPreferredSize();
  1327. Dimension _bottomButtons = bottomButtons.getPreferredSize();
  1328. Dimension _rightButtons = rightButtons.getPreferredSize();
  1329. Dimension _center = (center == null
  1330. ? new Dimension(0,0)
  1331. : center.getPreferredSize());
  1332. Dimension _topToolbars = (topToolbars == null
  1333. ? new Dimension(0,0)
  1334. : topToolbars.getPreferredSize());
  1335. Dimension _bottomToolbars = (bottomToolbars == null
  1336. ? new Dimension(0,0)
  1337. : bottomToolbars.getPreferredSize());
  1338. prefSize.height = _top.height + _bottom.height + _center.height
  1339. + _topButtons.height + _bottomButtons.height
  1340. + _topToolbars.height + _bottomToolbars.height;
  1341. prefSize.width = _left.width + _right.width
  1342. + Math.max(_center.width,
  1343. Math.max(_topToolbars.width,_bottomToolbars.width))
  1344. + _leftButtons.width + _rightButtons.width;
  1345. return prefSize;
  1346. } //}}}
  1347. //{{{ minimumLayoutSize() method
  1348. public Dimension minimumLayoutSize(Container parent)
  1349. {
  1350. // I'm lazy
  1351. return preferredLayoutSize(parent);
  1352. } //}}}
  1353. //{{{ maximumLayoutSize() method
  1354. public Dimension maximumLayoutSize(Container parent)
  1355. {
  1356. return new Dimension(Integer.MAX_VALUE,Integer.MAX_VALUE);
  1357. } //}}}
  1358. //{{{ layoutContainer() method
  1359. public void layoutContainer(Container parent)
  1360. {
  1361. Dimension size = parent.getSize();
  1362. Dimension _topToolbars = (topToolbars == null
  1363. ? new Dimension(0,0)
  1364. : topToolbars.getPreferredSize());
  1365. Dimension _bottomToolbars = (bottomToolbars == null
  1366. ? new Dimension(0,0)
  1367. : bottomToolbars.getPreferredSize());
  1368. int topButtonHeight = -1;
  1369. int bottomButtonHeight = -1;
  1370. int leftButtonWidth = -1;
  1371. int rightButtonWidth = -1;
  1372. Dimension _top = top.getPreferredSize();
  1373. Dimension _left = left.getPreferredSize();
  1374. Dimension _bottom = bottom.getPreferredSize();
  1375. Dimension _right = right.getPreferredSize();
  1376. int topHeight = _top.height;
  1377. int bottomHeight = _bottom.height;
  1378. int leftWidth = _left.width;
  1379. int rightWidth = _right.width;
  1380. boolean topEmpty = ((Container)topButtons)
  1381. .getComponentCount() <= 2;
  1382. boolean leftEmpty = ((Container)leftButtons)
  1383. .getComponentCount() <= 2;
  1384. boolean bottomEmpty = ((Container)bottomButtons)
  1385. .getComponentCount() <= 2;
  1386. boolean rightEmpty = ((Container)rightButtons)
  1387. .getComponentCount() <= 2;
  1388. Dimension closeBoxSize;
  1389. if(((Container)topButtons).getComponentCount() == 0)
  1390. closeBoxSize = new Dimension(0,0);
  1391. else
  1392. {
  1393. closeBoxSize = ((Container)topButtons)
  1394. .getComponent(0).getPreferredSize();
  1395. }
  1396. int closeBoxWidth = Math.max(closeBoxSize.width,
  1397. closeBoxSize.height) + 1;
  1398. if(alternateLayout)
  1399. {
  1400. //{{{ Lay out independent buttons
  1401. int _width = size.width;
  1402. int padding = (leftEmpty&&rightEmpty)
  1403. ? 0 : closeBoxWidth;
  1404. topButtonHeight = DockableWindowManager.this.
  1405. top.getWrappedDimension(_width
  1406. - closeBoxWidth * 2);
  1407. topButtons.setBounds(
  1408. padding,
  1409. 0,
  1410. size.width - padding * 2,
  1411. topButtonHeight);
  1412. bottomButtonHeight = DockableWindowManager.this.
  1413. bottom.getWrappedDimension(_width);
  1414. bottomButtons.setBounds(
  1415. padding,
  1416. size.height - bottomButtonHeight,
  1417. size.width - padding * 2,
  1418. bottomButtonHeight);
  1419. int _height = size.height
  1420. - topButtonHeight
  1421. - bottomButtonHeight;
  1422. //}}}
  1423. //{{{ Lay out dependent buttons
  1424. leftButtonWidth = DockableWindowManager.this.
  1425. left.getWrappedDimension(_height);
  1426. leftButtons.setBounds(
  1427. 0,
  1428. topHeight + topButtonHeight,
  1429. leftButtonWidth,
  1430. _height - topHeight - bottomHeight);
  1431. rightButtonWidth = DockableWindowManager.this.
  1432. right.getWrappedDimension(_height);
  1433. rightButtons.setBounds(
  1434. size.width - rightButtonWidth,
  1435. topHeight + topButtonHeight,
  1436. rightButtonWidth,
  1437. _height - topHeight - bottomHeight);
  1438. //}}}
  1439. int[] dimensions = adjustDockingAreasToFit(
  1440. size,
  1441. topHeight,
  1442. leftWidth,
  1443. bottomHeight,
  1444. rightWidth,
  1445. topButtonHeight,
  1446. leftButtonWidth,
  1447. bottomButtonHeight,
  1448. rightButtonWidth,
  1449. _topToolbars,
  1450. _bottomToolbars);
  1451. topHeight = dimensions[0];
  1452. leftWidth = dimensions[1];
  1453. bottomHeight = dimensions[2];
  1454. rightWidth = dimensions[3];
  1455. //{{{ Lay out docking areas
  1456. top.setBounds(
  1457. 0,
  1458. topButtonHeight,
  1459. size.width,
  1460. topHeight);
  1461. bottom.setBounds(
  1462. 0,
  1463. size.height
  1464. - bottomHeight
  1465. - bottomButtonHeight,
  1466. size.width,
  1467. bottomHeight);
  1468. left.setBounds(
  1469. leftButtonWidth,
  1470. topButtonHeight + topHeight,
  1471. leftWidth,
  1472. _height - topHeight - bottomHeight);
  1473. right.setBounds(
  1474. _width - rightButtonWidth - rightWidth,
  1475. topButtonHeight + topHeight,
  1476. rightWidth,
  1477. _height - topHeight - bottomHeight); //}}}
  1478. }
  1479. else
  1480. {
  1481. //{{{ Lay out independent buttons
  1482. int _height = size.height;
  1483. int padding = (topEmpty && bottomEmpty
  1484. ? 0 : closeBoxWidth);
  1485. leftButtonWidth = DockableWindowManager.this.
  1486. left.getWrappedDimension(_height
  1487. - closeBoxWidth * 2);
  1488. leftButtons.setBounds(
  1489. 0,
  1490. padding,
  1491. leftButtonWidth,
  1492. _height - padding * 2);
  1493. rightButtonWidth = DockableWindowManager.this.
  1494. right.getWrappedDimension(_height);
  1495. rightButtons.setBounds(
  1496. size.width - rightButtonWidth,
  1497. padding,
  1498. rightButtonWidth,
  1499. _height - padding * 2);
  1500. int _width = size.width
  1501. - leftButtonWidth
  1502. - rightButtonWidth;
  1503. //}}}
  1504. //{{{ Lay out dependent buttons
  1505. topButtonHeight = DockableWindowManager.this.
  1506. top.getWrappedDimension(_width);
  1507. topButtons.setBounds(
  1508. leftButtonWidth + leftWidth,
  1509. 0,
  1510. _width - leftWidth - rightWidth,
  1511. topButtonHeight);
  1512. bottomButtonHeight = DockableWindowManager.this.
  1513. bottom.getWrappedDimension(_width);
  1514. bottomButtons.setBounds(
  1515. leftButtonWidth + leftWidth,
  1516. _height - bottomButtonHeight,
  1517. _width - leftWidth - rightWidth,
  1518. bottomButtonHeight); //}}}
  1519. int[] dimensions = adjustDockingAreasToFit(
  1520. size,
  1521. topHeight,
  1522. leftWidth,
  1523. bottomHeight,
  1524. rightWidth,
  1525. topButtonHeight,
  1526. leftButtonWidth,
  1527. bottomButtonHeight,
  1528. rightButtonWidth,
  1529. _topToolbars,
  1530. _bottomToolbars);
  1531. topHeight = dimensions[0];
  1532. leftWidth = dimensions[1];
  1533. bottomHeight = dimensions[2];
  1534. rightWidth = dimensions[3];
  1535. //{{{ Lay out docking areas
  1536. top.setBounds(
  1537. leftButtonWidth + leftWidth,
  1538. topButtonHeight,
  1539. _width - leftWidth - rightWidth,
  1540. topHeight);
  1541. bottom.setBounds(
  1542. leftButtonWidth + leftWidth,
  1543. size.height - bottomHeight - bottomButtonHeight,
  1544. _width - leftWidth - rightWidth,
  1545. bottomHeight);
  1546. left.setBounds(
  1547. leftButtonWidth,
  1548. 0,
  1549. leftWidth,
  1550. _height);
  1551. right.setBounds(
  1552. size.width - rightWidth - rightButtonWidth,
  1553. 0,
  1554. rightWidth,
  1555. _height); //}}}
  1556. }
  1557. //{{{ Position tool bars if they are managed by us
  1558. if(topToolbars != null)
  1559. {
  1560. topToolbars.setBounds(
  1561. leftButtonWidth + leftWidth,
  1562. topButtonHeight + topHeight,
  1563. size.width - leftWidth - rightWidth
  1564. - leftButtonWidth - rightButtonWidth,
  1565. _topToolbars.height);
  1566. }
  1567. if(bottomToolbars != null)
  1568. {
  1569. bottomToolbars.setBounds(
  1570. leftButtonWidth + leftWidth,
  1571. size.height - bottomHeight
  1572. - bottomButtonHeight
  1573. - _bottomToolbars.height
  1574. + topButtonHeight
  1575. + topHeight,
  1576. size.width - leftWidth - rightWidth
  1577. - leftButtonWidth - rightButtonWidth,
  1578. _bottomToolbars.height);
  1579. } //}}}
  1580. //{{{ Position center (edit pane, or split pane)
  1581. if(center != null)
  1582. {
  1583. center.setBounds(
  1584. leftButtonWidth + leftWidth,
  1585. topButtonHeight + topHeight
  1586. + _topToolbars.height,
  1587. size.width
  1588. - leftWidth
  1589. - rightWidth
  1590. - leftButtonWidth
  1591. - rightButtonWidth,
  1592. size.height
  1593. - topHeight
  1594. - topButtonHeight
  1595. - bottomHeight
  1596. - bottomButtonHeight
  1597. - _topToolbars.height
  1598. - _bottomToolbars.height);
  1599. } //}}}
  1600. } //}}}
  1601. //{{{ adjustDockingAreasToFit() method
  1602. private int[] adjustDockingAreasToFit(
  1603. Dimension size,
  1604. int topHeight,
  1605. int leftWidth,
  1606. int bottomHeight,
  1607. int rightWidth,
  1608. int topButtonHeight,
  1609. int leftButtonWidth,
  1610. int bottomButtonHeight,
  1611. int rightButtonWidth,
  1612. Dimension _topToolbars,
  1613. Dimension _bottomToolbars)
  1614. {
  1615. int maxTopHeight = size.height - bottomHeight
  1616. - topButtonHeight - bottomButtonHeight
  1617. - _topToolbars.height - _bottomToolbars.height;
  1618. topHeight = Math.min(Math.max(0,maxTopHeight),
  1619. topHeight);
  1620. leftWidth = Math.min(Math.max(0,
  1621. size.width - leftButtonWidth
  1622. - rightButtonWidth - rightWidth),leftWidth);
  1623. int maxBottomHeight = size.height - topHeight
  1624. - topButtonHeight - bottomButtonHeight
  1625. - _topToolbars.height - _bottomToolbars.height;
  1626. bottomHeight = Math.min(Math.max(0,maxBottomHeight),
  1627. bottomHeight);
  1628. rightWidth = Math.min(Math.max(0,
  1629. size.width - leftButtonWidth
  1630. - rightButtonWidth - leftWidth),rightWidth);
  1631. DockableWindowManager.this.top.setDimension(topHeight);
  1632. DockableWindowManager.this.left.setDimension(leftWidth);
  1633. DockableWindowManager.this.bottom.setDimension(bottomHeight);
  1634. DockableWindowManager.this.right.setDimension(rightWidth);
  1635. return new int[] {
  1636. topHeight,
  1637. leftWidth,
  1638. bottomHeight,
  1639. rightWidth
  1640. };
  1641. } //}}}
  1642. //{{{ getLayoutAlignmentX() method
  1643. public float getLayoutAlignmentX(Container target)
  1644. {
  1645. return 0.5f;
  1646. } //}}}
  1647. //{{{ getLayoutAlignmentY() method
  1648. public float getLayoutAlignmentY(Container target)
  1649. {
  1650. return 0.5f;
  1651. } //}}}
  1652. //{{{ invalidateLayout() method
  1653. public void invalidateLayout(Container target) {}
  1654. //}}}
  1655. } //}}}
  1656. //{{{ Entry class
  1657. class Entry
  1658. {
  1659. Factory factory;
  1660. String title;
  1661. String position;
  1662. DockableWindowContainer container;
  1663. // only set if open
  1664. JComponent win;
  1665. // only for docked
  1666. AbstractButton btn;
  1667. //{{{ Entry constructor
  1668. Entry(Factory factory)
  1669. {
  1670. this(factory,jEdit.getProperty(factory.name
  1671. + ".dock-position",FLOATING));
  1672. } //}}}
  1673. //{{{ Entry constructor
  1674. Entry(Factory factory, String position)
  1675. {
  1676. this.factory = factory;
  1677. this.position = position;
  1678. // get the title here, not in the factory constructor,
  1679. // since the factory might be created before a plugin's
  1680. // props are loaded
  1681. title = getDockableTitle(factory.name);
  1682. } //}}}
  1683. } //}}}
  1684. }