PageRenderTime 41ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

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

#
Java | 695 lines | 524 code | 101 blank | 70 comment | 96 complexity | 40a610987f5deebc26b0a4e97becf11c 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. * OptionsDialog.java - Tree options dialog
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1998, 2003 Slava Pestov
  7. * Portions copyright (C) 1999 mike dillon
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. */
  23. package org.gjt.sp.jedit.gui;
  24. //{{{ Imports
  25. import javax.swing.*;
  26. import javax.swing.border.*;
  27. import javax.swing.event.*;
  28. import javax.swing.tree.*;
  29. import java.awt.*;
  30. import java.awt.event.*;
  31. import java.util.*;
  32. import org.gjt.sp.jedit.*;
  33. import org.gjt.sp.util.Log;
  34. //}}}
  35. /**
  36. * An abstract tabbed options dialog box.
  37. * @author Slava Pestov
  38. * @version $Id: OptionsDialog.java 5370 2006-04-11 23:03:51Z ezust $
  39. *
  40. */
  41. public abstract class OptionsDialog extends EnhancedDialog
  42. implements ActionListener, TreeSelectionListener
  43. {
  44. //{{{ OptionsDialog constructor
  45. public OptionsDialog(Frame frame, String name, String pane)
  46. {
  47. super(frame, jEdit.getProperty(name + ".title"), true);
  48. init(name,pane);
  49. } //}}}
  50. //{{{ OptionsDialog constructor
  51. public OptionsDialog(Dialog dialog, String name, String pane)
  52. {
  53. super(dialog, jEdit.getProperty(name + ".title"), true);
  54. init(name,pane);
  55. } //}}}
  56. //{{{ addOptionGroup() method
  57. public void addOptionGroup(OptionGroup group)
  58. {
  59. getDefaultGroup().addOptionGroup(group);
  60. } //}}}
  61. //{{{ addOptionPane() method
  62. public void addOptionPane(OptionPane pane)
  63. {
  64. getDefaultGroup().addOptionPane(pane);
  65. } //}}}
  66. //{{{ ok() method
  67. public void ok()
  68. {
  69. if(currentPane != null)
  70. jEdit.setProperty(name + ".last",currentPane.getName());
  71. ok(true);
  72. } //}}}
  73. //{{{ cancel() method
  74. public void cancel()
  75. {
  76. if(currentPane != null)
  77. jEdit.setProperty(name + ".last",currentPane.getName());
  78. dispose();
  79. } //}}}
  80. //{{{ ok() method
  81. public void ok(boolean dispose)
  82. {
  83. OptionTreeModel m = (OptionTreeModel) paneTree
  84. .getModel();
  85. save(m.getRoot());
  86. /* This will fire the PROPERTIES_CHANGED event */
  87. jEdit.propertiesChanged();
  88. // Save settings to disk
  89. jEdit.saveSettings();
  90. // get rid of this dialog if necessary
  91. if(dispose)
  92. dispose();
  93. } //}}}
  94. //{{{ dispose() method
  95. public void dispose()
  96. {
  97. GUIUtilities.saveGeometry(this,name);
  98. jEdit.setIntegerProperty(name + ".splitter",splitter.getDividerLocation());
  99. super.dispose();
  100. } //}}}
  101. //{{{ actionPerformed() method
  102. public void actionPerformed(ActionEvent evt)
  103. {
  104. Object source = evt.getSource();
  105. if(source == ok)
  106. {
  107. ok();
  108. }
  109. else if(source == cancel)
  110. {
  111. cancel();
  112. }
  113. else if(source == apply)
  114. {
  115. ok(false);
  116. }
  117. } //}}}
  118. //{{{ valueChanged() method
  119. public void valueChanged(TreeSelectionEvent evt)
  120. {
  121. TreePath path = evt.getPath();
  122. if(path == null)
  123. return;
  124. Object lastPathComponent = path.getLastPathComponent();
  125. if(!(lastPathComponent instanceof String
  126. || lastPathComponent instanceof OptionPane))
  127. {
  128. return;
  129. }
  130. Object[] nodes = path.getPath();
  131. StringBuffer buf = new StringBuffer();
  132. OptionPane optionPane = null;
  133. int lastIdx = nodes.length - 1;
  134. for (int i = paneTree.isRootVisible() ? 0 : 1;
  135. i <= lastIdx; i++)
  136. {
  137. String label;
  138. Object node = nodes[i];
  139. if (node instanceof OptionPane)
  140. {
  141. optionPane = (OptionPane)node;
  142. label = jEdit.getProperty("options."
  143. + optionPane.getName()
  144. + ".label");
  145. }
  146. else if (node instanceof OptionGroup)
  147. {
  148. label = ((OptionGroup)node).getLabel();
  149. }
  150. else if (node instanceof String)
  151. {
  152. label = jEdit.getProperty("options."
  153. + node + ".label");
  154. optionPane = (OptionPane)deferredOptionPanes
  155. .get(node);
  156. if(optionPane == null)
  157. {
  158. String propName = "options." + node + ".code";
  159. String code = jEdit.getProperty(propName);
  160. if(code != null)
  161. {
  162. optionPane = (OptionPane)
  163. BeanShell.eval(
  164. jEdit.getActiveView(),
  165. BeanShell.getNameSpace(),
  166. code
  167. );
  168. if(optionPane != null)
  169. {
  170. deferredOptionPanes.put(
  171. node,optionPane);
  172. }
  173. else
  174. continue;
  175. }
  176. else
  177. {
  178. Log.log(Log.ERROR,this,propName
  179. + " not defined");
  180. continue;
  181. }
  182. }
  183. }
  184. else
  185. {
  186. continue;
  187. }
  188. buf.append(label);
  189. if (i != lastIdx)
  190. buf.append(": ");
  191. }
  192. if(optionPane == null)
  193. return;
  194. setTitle(jEdit.getProperty("options.title-template",
  195. new Object[] { jEdit.getProperty(this.name + ".title"),
  196. buf.toString() }));
  197. try
  198. {
  199. optionPane.init();
  200. }
  201. catch(Throwable t)
  202. {
  203. Log.log(Log.ERROR,this,"Error initializing options:");
  204. Log.log(Log.ERROR,this,t);
  205. }
  206. if(currentPane != null)
  207. stage.remove(currentPane.getComponent());
  208. currentPane = optionPane;
  209. stage.add(BorderLayout.CENTER,currentPane.getComponent());
  210. stage.revalidate();
  211. stage.repaint();
  212. if(!isShowing())
  213. addNotify();
  214. updateSize();
  215. currentPane = optionPane;
  216. } //}}}
  217. //{{{ Protected members
  218. // {{{ createOptionTreeModel
  219. /**
  220. * Creates the tree model that goes on the left of the option pane,
  221. * loading all the items that are needed.
  222. */
  223. protected abstract OptionTreeModel createOptionTreeModel();
  224. // }}}
  225. protected abstract OptionGroup getDefaultGroup();
  226. //}}}
  227. //{{{ Private members
  228. //{{{ Instance variables
  229. private String name;
  230. private JSplitPane splitter;
  231. private JTree paneTree;
  232. private JPanel stage;
  233. private JButton ok;
  234. private JButton cancel;
  235. private JButton apply;
  236. private OptionPane currentPane;
  237. private Map deferredOptionPanes;
  238. //}}}
  239. //{{{ init() method
  240. private void init(String name, String pane)
  241. {
  242. this.name = name;
  243. deferredOptionPanes = new HashMap();
  244. JPanel content = new JPanel(new BorderLayout(12,12));
  245. content.setBorder(new EmptyBorder(12,12,12,12));
  246. setContentPane(content);
  247. stage = new JPanel(new BorderLayout());
  248. paneTree = new JTree(createOptionTreeModel());
  249. paneTree.setVisibleRowCount(1);
  250. paneTree.setCellRenderer(new PaneNameRenderer());
  251. // looks bad with the OS X L&F, apparently...
  252. if(!OperatingSystem.isMacOSLF())
  253. paneTree.putClientProperty("JTree.lineStyle", "Angled");
  254. paneTree.setShowsRootHandles(true);
  255. paneTree.setRootVisible(false);
  256. JScrollPane scroller = new JScrollPane(paneTree,
  257. JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
  258. JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
  259. scroller.setMinimumSize(new Dimension(100, 0));
  260. splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
  261. scroller,stage);
  262. content.add(splitter, BorderLayout.CENTER);
  263. Box buttons = new Box(BoxLayout.X_AXIS);
  264. buttons.add(Box.createGlue());
  265. ok = new JButton(jEdit.getProperty("common.ok"));
  266. ok.addActionListener(this);
  267. buttons.add(ok);
  268. buttons.add(Box.createHorizontalStrut(6));
  269. getRootPane().setDefaultButton(ok);
  270. cancel = new JButton(jEdit.getProperty("common.cancel"));
  271. cancel.addActionListener(this);
  272. buttons.add(cancel);
  273. buttons.add(Box.createHorizontalStrut(6));
  274. apply = new JButton(jEdit.getProperty("common.apply"));
  275. apply.addActionListener(this);
  276. buttons.add(apply);
  277. buttons.add(Box.createGlue());
  278. content.add(buttons, BorderLayout.SOUTH);
  279. // register the Options dialog as a TreeSelectionListener.
  280. // this is done before the initial selection to ensure that the
  281. // first selected OptionPane is displayed on startup.
  282. paneTree.getSelectionModel().addTreeSelectionListener(this);
  283. OptionGroup rootNode = (OptionGroup)paneTree.getModel().getRoot();
  284. for(int i = 0; i < rootNode.getMemberCount(); i++)
  285. {
  286. paneTree.expandPath(new TreePath(
  287. new Object[] { rootNode, rootNode.getMember(i) }));
  288. }
  289. // returns false if no such pane exists; calling with null
  290. // param selects first option pane found
  291. if(!selectPane(rootNode,pane))
  292. selectPane(rootNode,null);
  293. splitter.setDividerLocation(paneTree.getPreferredSize().width
  294. + scroller.getVerticalScrollBar().getPreferredSize()
  295. .width);
  296. GUIUtilities.loadGeometry(this,name);
  297. int dividerLocation = jEdit.getIntegerProperty(name + ".splitter",-1);
  298. if(dividerLocation != -1)
  299. splitter.setDividerLocation(dividerLocation);
  300. // in case saved geometry is too small
  301. updateSize();
  302. setVisible(true);
  303. } //}}}
  304. //{{{ selectPane() method
  305. private boolean selectPane(OptionGroup node, String name)
  306. {
  307. return selectPane(node,name,new ArrayList());
  308. } //}}}
  309. //{{{ selectPane() method
  310. private boolean selectPane(OptionGroup node, String name, ArrayList path)
  311. {
  312. path.add(node);
  313. Enumeration e = node.getMembers();
  314. while(e.hasMoreElements())
  315. {
  316. Object obj = e.nextElement();
  317. if(obj instanceof OptionGroup)
  318. {
  319. OptionGroup grp = (OptionGroup)obj;
  320. if(grp.getName().equals(name))
  321. {
  322. path.add(grp);
  323. path.add(grp.getMember(0));
  324. TreePath treePath = new TreePath(
  325. path.toArray());
  326. paneTree.scrollPathToVisible(treePath);
  327. paneTree.setSelectionPath(treePath);
  328. return true;
  329. }
  330. else if(selectPane((OptionGroup)obj,name,path))
  331. return true;
  332. }
  333. else if(obj instanceof OptionPane)
  334. {
  335. OptionPane pane = (OptionPane)obj;
  336. if(pane.getName().equals(name)
  337. || name == null)
  338. {
  339. path.add(pane);
  340. TreePath treePath = new TreePath(
  341. path.toArray());
  342. paneTree.scrollPathToVisible(treePath);
  343. paneTree.setSelectionPath(treePath);
  344. return true;
  345. }
  346. }
  347. else if(obj instanceof String)
  348. {
  349. String pane = (String)obj;
  350. if(pane.equals(name)
  351. || name == null)
  352. {
  353. path.add(pane);
  354. TreePath treePath = new TreePath(
  355. path.toArray());
  356. paneTree.scrollPathToVisible(treePath);
  357. paneTree.setSelectionPath(treePath);
  358. return true;
  359. }
  360. }
  361. }
  362. path.remove(node);
  363. return false;
  364. } //}}}
  365. //{{{ save() method
  366. private void save(Object obj)
  367. {
  368. if(obj instanceof OptionGroup)
  369. {
  370. OptionGroup grp = (OptionGroup)obj;
  371. Enumeration members = grp.getMembers();
  372. while(members.hasMoreElements())
  373. {
  374. save(members.nextElement());
  375. }
  376. }
  377. else if(obj instanceof OptionPane)
  378. {
  379. try
  380. {
  381. ((OptionPane)obj).save();
  382. }
  383. catch(Throwable t)
  384. {
  385. Log.log(Log.ERROR,this,"Error saving options:");
  386. Log.log(Log.ERROR,this,t);
  387. }
  388. }
  389. else if(obj instanceof String)
  390. {
  391. save(deferredOptionPanes.get(obj));
  392. }
  393. } //}}}
  394. //{{{ updateSize() method
  395. private void updateSize()
  396. {
  397. Dimension currentSize = getSize();
  398. Dimension requestedSize = getPreferredSize();
  399. Dimension newSize = new Dimension(
  400. Math.max(currentSize.width,requestedSize.width),
  401. Math.max(currentSize.height,requestedSize.height)
  402. );
  403. if(newSize.width < 300)
  404. newSize.width = 300;
  405. if(newSize.height < 200)
  406. newSize.height = 200;
  407. setSize(newSize);
  408. validate();
  409. } //}}}
  410. //}}}
  411. //{{{ PaneNameRenderer class
  412. public static class PaneNameRenderer extends DefaultTreeCellRenderer
  413. {
  414. public PaneNameRenderer()
  415. {
  416. paneFont = UIManager.getFont("Tree.font");
  417. if(paneFont == null)
  418. paneFont = jEdit.getFontProperty("metal.secondary.font");
  419. groupFont = paneFont.deriveFont(Font.BOLD);
  420. }
  421. public Component getTreeCellRendererComponent(JTree tree,
  422. Object value, boolean selected, boolean expanded,
  423. boolean leaf, int row, boolean hasFocus)
  424. {
  425. super.getTreeCellRendererComponent(tree,value,
  426. selected,expanded,leaf,row,hasFocus);
  427. String name = null;
  428. if (value instanceof OptionGroup)
  429. {
  430. setText(((OptionGroup)value).getLabel());
  431. this.setFont(groupFont);
  432. }
  433. else if (value instanceof OptionPane)
  434. {
  435. name = ((OptionPane)value).getName();
  436. this.setFont(paneFont);
  437. }
  438. else if (value instanceof String)
  439. {
  440. name = ((String)value);
  441. this.setFont(paneFont);
  442. }
  443. if (name != null)
  444. {
  445. String label = jEdit.getProperty("options." +
  446. name + ".label");
  447. if (label == null)
  448. {
  449. setText("NO LABEL PROPERTY: " + name);
  450. }
  451. else
  452. {
  453. setText(label);
  454. }
  455. }
  456. setIcon(null);
  457. return this;
  458. }
  459. private Font paneFont;
  460. private Font groupFont;
  461. } //}}}
  462. //{{{ OptionTreeModel class
  463. public class OptionTreeModel implements TreeModel
  464. {
  465. public void addTreeModelListener(TreeModelListener l)
  466. {
  467. listenerList.add(TreeModelListener.class, l);
  468. }
  469. public void removeTreeModelListener(TreeModelListener l)
  470. {
  471. listenerList.remove(TreeModelListener.class, l);
  472. }
  473. public Object getChild(Object parent, int index)
  474. {
  475. if (parent instanceof OptionGroup)
  476. {
  477. return ((OptionGroup)parent).getMember(index);
  478. }
  479. else
  480. {
  481. return null;
  482. }
  483. }
  484. public int getChildCount(Object parent)
  485. {
  486. if (parent instanceof OptionGroup)
  487. {
  488. return ((OptionGroup)parent).getMemberCount();
  489. }
  490. else
  491. {
  492. return 0;
  493. }
  494. }
  495. public int getIndexOfChild(Object parent, Object child)
  496. {
  497. if (parent instanceof OptionGroup)
  498. {
  499. return ((OptionGroup)parent)
  500. .getMemberIndex(child);
  501. }
  502. else
  503. {
  504. return -1;
  505. }
  506. }
  507. public Object getRoot()
  508. {
  509. return root;
  510. }
  511. public boolean isLeaf(Object node)
  512. {
  513. return !(node instanceof OptionGroup);
  514. }
  515. public void valueForPathChanged(TreePath path, Object newValue)
  516. {
  517. // this model may not be changed by the TableCellEditor
  518. }
  519. protected void fireNodesChanged(Object source, Object[] path,
  520. int[] childIndices, Object[] children)
  521. {
  522. Object[] listeners = listenerList.getListenerList();
  523. TreeModelEvent modelEvent = null;
  524. for (int i = listeners.length - 2; i >= 0; i -= 2)
  525. {
  526. if (listeners[i] != TreeModelListener.class)
  527. continue;
  528. if (modelEvent == null)
  529. {
  530. modelEvent = new TreeModelEvent(source,
  531. path, childIndices, children);
  532. }
  533. ((TreeModelListener)listeners[i + 1])
  534. .treeNodesChanged(modelEvent);
  535. }
  536. }
  537. protected void fireNodesInserted(Object source, Object[] path,
  538. int[] childIndices, Object[] children)
  539. {
  540. Object[] listeners = listenerList.getListenerList();
  541. TreeModelEvent modelEvent = null;
  542. for (int i = listeners.length - 2; i >= 0; i -= 2)
  543. {
  544. if (listeners[i] != TreeModelListener.class)
  545. continue;
  546. if (modelEvent == null)
  547. {
  548. modelEvent = new TreeModelEvent(source,
  549. path, childIndices, children);
  550. }
  551. ((TreeModelListener)listeners[i + 1])
  552. .treeNodesInserted(modelEvent);
  553. }
  554. }
  555. protected void fireNodesRemoved(Object source, Object[] path,
  556. int[] childIndices, Object[] children)
  557. {
  558. Object[] listeners = listenerList.getListenerList();
  559. TreeModelEvent modelEvent = null;
  560. for (int i = listeners.length - 2; i >= 0; i -= 2)
  561. {
  562. if (listeners[i] != TreeModelListener.class)
  563. continue;
  564. if (modelEvent == null)
  565. {
  566. modelEvent = new TreeModelEvent(source,
  567. path, childIndices, children);
  568. }
  569. ((TreeModelListener)listeners[i + 1])
  570. .treeNodesRemoved(modelEvent);
  571. }
  572. }
  573. protected void fireTreeStructureChanged(Object source,
  574. Object[] path, int[] childIndices, Object[] children)
  575. {
  576. Object[] listeners = listenerList.getListenerList();
  577. TreeModelEvent modelEvent = null;
  578. for (int i = listeners.length - 2; i >= 0; i -= 2)
  579. {
  580. if (listeners[i] != TreeModelListener.class)
  581. continue;
  582. if (modelEvent == null)
  583. {
  584. modelEvent = new TreeModelEvent(source,
  585. path, childIndices, children);
  586. }
  587. ((TreeModelListener)listeners[i + 1])
  588. .treeStructureChanged(modelEvent);
  589. }
  590. }
  591. private OptionGroup root = new OptionGroup(null);
  592. private EventListenerList listenerList = new EventListenerList();
  593. } //}}}
  594. }