/jEdit/tags/jedit-4-1-pre8/org/gjt/sp/jedit/gui/OptionsDialog.java

# · Java · 598 lines · 438 code · 98 blank · 62 comment · 70 complexity · baf055cc3e73242878cbd3b8eca8cc2a MD5 · raw file

  1. /*
  2. * OptionsDialog.java - Tree options dialog
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1998, 2002 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 4419 2003-01-07 23:30:53Z spestov $
  39. */
  40. public abstract class OptionsDialog extends EnhancedDialog
  41. implements ActionListener, TreeSelectionListener
  42. {
  43. //{{{ OptionsDialog constructor
  44. public OptionsDialog(Frame frame, String name, String pane)
  45. {
  46. super(frame, jEdit.getProperty(name + ".title"), true);
  47. init(name,pane);
  48. } //}}}
  49. //{{{ OptionsDialog constructor
  50. public OptionsDialog(Dialog dialog, String name, String pane)
  51. {
  52. super(dialog, jEdit.getProperty(name + ".title"), true);
  53. init(name,pane);
  54. } //}}}
  55. //{{{ addOptionGroup() method
  56. public void addOptionGroup(OptionGroup group)
  57. {
  58. addOptionGroup(group, getDefaultGroup());
  59. } //}}}
  60. //{{{ addOptionPane() method
  61. public void addOptionPane(OptionPane pane)
  62. {
  63. addOptionPane(pane, getDefaultGroup());
  64. } //}}}
  65. //{{{ ok() method
  66. public void ok()
  67. {
  68. jEdit.setProperty(name + ".last",currentPane);
  69. ok(true);
  70. } //}}}
  71. //{{{ cancel() method
  72. public void cancel()
  73. {
  74. jEdit.setProperty(name + ".last",currentPane);
  75. dispose();
  76. } //}}}
  77. //{{{ ok() method
  78. public void ok(boolean dispose)
  79. {
  80. OptionTreeModel m = (OptionTreeModel) paneTree
  81. .getModel();
  82. ((OptionGroup) m.getRoot()).save();
  83. /* This will fire the PROPERTIES_CHANGED event */
  84. jEdit.propertiesChanged();
  85. // Save settings to disk
  86. jEdit.saveSettings();
  87. // get rid of this dialog if necessary
  88. if(dispose)
  89. dispose();
  90. } //}}}
  91. //{{{ actionPerformed() method
  92. public void actionPerformed(ActionEvent evt)
  93. {
  94. Object source = evt.getSource();
  95. if(source == ok)
  96. {
  97. ok();
  98. }
  99. else if(source == cancel)
  100. {
  101. cancel();
  102. }
  103. else if(source == apply)
  104. {
  105. ok(false);
  106. }
  107. } //}}}
  108. //{{{ valueChanged() method
  109. public void valueChanged(TreeSelectionEvent evt)
  110. {
  111. TreePath path = evt.getPath();
  112. if (path == null || !(path.getLastPathComponent() instanceof
  113. OptionPane)) return;
  114. Object[] nodes = path.getPath();
  115. StringBuffer buf = new StringBuffer();
  116. OptionPane optionPane = null;
  117. String name = null;
  118. int lastIdx = nodes.length - 1;
  119. for (int i = paneTree.isRootVisible() ? 0 : 1;
  120. i <= lastIdx; i++)
  121. {
  122. if (nodes[i] instanceof OptionPane)
  123. {
  124. optionPane = (OptionPane)nodes[i];
  125. name = optionPane.getName();
  126. }
  127. else if (nodes[i] instanceof OptionGroup)
  128. {
  129. name = ((OptionGroup)nodes[i]).getName();
  130. }
  131. else
  132. {
  133. continue;
  134. }
  135. if (name != null)
  136. {
  137. String label = jEdit.getProperty("options." +
  138. name + ".label");
  139. if (label == null)
  140. {
  141. buf.append(name);
  142. }
  143. else
  144. {
  145. buf.append(label);
  146. }
  147. }
  148. if (i != lastIdx) buf.append(": ");
  149. }
  150. currentLabel.setText(buf.toString());
  151. optionPane.init();
  152. ((CardLayout)cardPanel.getLayout()).show(cardPanel, name);
  153. // workaround...
  154. addNotify();
  155. Dimension currentSize = getSize();
  156. Dimension requestedSize = getPreferredSize();
  157. Dimension newSize = new Dimension(
  158. Math.max(currentSize.width,requestedSize.width),
  159. Math.max(currentSize.height,requestedSize.height)
  160. );
  161. if(newSize.width < 400)
  162. newSize.width = 400;
  163. if(newSize.height < 300)
  164. newSize.height = 300;
  165. setSize(newSize);
  166. validate();
  167. currentPane = name;
  168. } //}}}
  169. //{{{ Protected members
  170. protected abstract OptionTreeModel createOptionTreeModel();
  171. protected abstract OptionGroup getDefaultGroup();
  172. //{{{ addOptionGroup() method
  173. protected void addOptionGroup(OptionGroup child, OptionGroup parent)
  174. {
  175. Enumeration enum = child.getMembers();
  176. while (enum.hasMoreElements())
  177. {
  178. Object elem = enum.nextElement();
  179. if (elem instanceof OptionPane)
  180. {
  181. addOptionPane((OptionPane) elem, child);
  182. }
  183. else if (elem instanceof OptionGroup)
  184. {
  185. addOptionGroup((OptionGroup) elem, child);
  186. }
  187. }
  188. parent.addOptionGroup(child);
  189. } //}}}
  190. //{{{ addOptionPane() method
  191. protected void addOptionPane(OptionPane pane, OptionGroup parent)
  192. {
  193. String name = pane.getName();
  194. if(firstPane == null)
  195. firstPane = name;
  196. cardPanel.add(pane.getComponent(), name);
  197. parent.addOptionPane(pane);
  198. } //}}}
  199. //}}}
  200. //{{{ Private members
  201. //{{{ Instance variables
  202. private String name;
  203. private JTree paneTree;
  204. private JPanel cardPanel;
  205. private JLabel currentLabel;
  206. private JButton ok;
  207. private JButton cancel;
  208. private JButton apply;
  209. private String currentPane;
  210. private String firstPane;
  211. //}}}
  212. //{{{ init() method
  213. private void init(String name, String pane)
  214. {
  215. this.name = name;
  216. JPanel content = new JPanel(new BorderLayout(12,12));
  217. content.setBorder(new EmptyBorder(12,12,12,12));
  218. setContentPane(content);
  219. JPanel stage = new JPanel(new BorderLayout(6,6));
  220. // currentLabel displays the path of the currently selected
  221. // OptionPane at the top of the stage area
  222. currentLabel = new JLabel();
  223. currentLabel.setHorizontalAlignment(JLabel.LEFT);
  224. stage.add(currentLabel, BorderLayout.NORTH);
  225. cardPanel = new JPanel(new CardLayout());
  226. stage.add(cardPanel, BorderLayout.CENTER);
  227. paneTree = new JTree(createOptionTreeModel());
  228. paneTree.setVisibleRowCount(1);
  229. paneTree.setCellRenderer(new PaneNameRenderer());
  230. // looks bad with the OS X L&F, apparently...
  231. if(!OperatingSystem.isMacOSLF())
  232. paneTree.putClientProperty("JTree.lineStyle", "Angled");
  233. paneTree.setShowsRootHandles(true);
  234. paneTree.setRootVisible(false);
  235. JScrollPane scroller = new JScrollPane(paneTree,
  236. JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
  237. JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
  238. JSplitPane splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
  239. scroller,stage);
  240. splitter.setDividerLocation(scroller.getPreferredSize().width);
  241. content.add(splitter, BorderLayout.CENTER);
  242. Box buttons = new Box(BoxLayout.X_AXIS);
  243. buttons.add(Box.createGlue());
  244. ok = new JButton(jEdit.getProperty("common.ok"));
  245. ok.addActionListener(this);
  246. buttons.add(ok);
  247. buttons.add(Box.createHorizontalStrut(6));
  248. getRootPane().setDefaultButton(ok);
  249. cancel = new JButton(jEdit.getProperty("common.cancel"));
  250. cancel.addActionListener(this);
  251. buttons.add(cancel);
  252. buttons.add(Box.createHorizontalStrut(6));
  253. apply = new JButton(jEdit.getProperty("common.apply"));
  254. apply.addActionListener(this);
  255. buttons.add(apply);
  256. buttons.add(Box.createGlue());
  257. content.add(buttons, BorderLayout.SOUTH);
  258. // register the Options dialog as a TreeSelectionListener.
  259. // this is done before the initial selection to ensure that the
  260. // first selected OptionPane is displayed on startup.
  261. paneTree.getSelectionModel().addTreeSelectionListener(this);
  262. OptionGroup rootNode = (OptionGroup)paneTree.getModel().getRoot();
  263. for(int i = 0; i < rootNode.getMemberCount(); i++)
  264. {
  265. paneTree.expandPath(new TreePath(
  266. new Object[] { rootNode, rootNode.getMember(i) }));
  267. }
  268. if(pane == null || !selectPane(rootNode,pane))
  269. selectPane(rootNode,firstPane);
  270. setLocationRelativeTo(getParent());
  271. show();
  272. } //}}}
  273. //{{{ selectPane() method
  274. private boolean selectPane(OptionGroup node, String name)
  275. {
  276. return selectPane(node,name,new ArrayList());
  277. } //}}}
  278. //{{{ selectPane() method
  279. private boolean selectPane(OptionGroup node, String name, ArrayList path)
  280. {
  281. path.add(node);
  282. Enumeration enum = node.getMembers();
  283. while(enum.hasMoreElements())
  284. {
  285. Object obj = enum.nextElement();
  286. if(obj instanceof OptionGroup)
  287. {
  288. OptionGroup grp = (OptionGroup)obj;
  289. if(grp.getName().equals(name))
  290. {
  291. path.add(grp);
  292. path.add(grp.getMember(0));
  293. TreePath treePath = new TreePath(
  294. path.toArray());
  295. paneTree.scrollPathToVisible(treePath);
  296. paneTree.setSelectionPath(treePath);
  297. return true;
  298. }
  299. else if(selectPane((OptionGroup)obj,name,path))
  300. return true;
  301. }
  302. else
  303. {
  304. OptionPane pane = (OptionPane)obj;
  305. if(pane.getName().equals(name))
  306. {
  307. path.add(pane);
  308. TreePath treePath = new TreePath(
  309. path.toArray());
  310. paneTree.scrollPathToVisible(treePath);
  311. paneTree.setSelectionPath(treePath);
  312. return true;
  313. }
  314. }
  315. }
  316. path.remove(node);
  317. return false;
  318. } //}}}
  319. //}}}
  320. //{{{ PaneNameRenderer class
  321. class PaneNameRenderer extends DefaultTreeCellRenderer
  322. {
  323. public PaneNameRenderer()
  324. {
  325. paneFont = UIManager.getFont("Tree.font");
  326. groupFont = paneFont.deriveFont(Font.BOLD);
  327. }
  328. public Component getTreeCellRendererComponent(JTree tree,
  329. Object value, boolean selected, boolean expanded,
  330. boolean leaf, int row, boolean hasFocus)
  331. {
  332. super.getTreeCellRendererComponent(tree,value,
  333. selected,expanded,leaf,row,hasFocus);
  334. String name = null;
  335. if (value instanceof OptionGroup)
  336. {
  337. name = ((OptionGroup)value).getName();
  338. this.setFont(groupFont);
  339. }
  340. else if (value instanceof OptionPane)
  341. {
  342. name = ((OptionPane)value).getName();
  343. this.setFont(paneFont);
  344. }
  345. if (name == null)
  346. {
  347. setText(null);
  348. }
  349. else
  350. {
  351. String label = jEdit.getProperty("options." +
  352. name + ".label");
  353. if (label == null)
  354. {
  355. setText("NO LABEL PROPERTY: " + name);
  356. }
  357. else
  358. {
  359. setText(label);
  360. }
  361. }
  362. setIcon(null);
  363. return this;
  364. }
  365. private Font paneFont;
  366. private Font groupFont;
  367. } //}}}
  368. //{{{ OptionTreeModel class
  369. public class OptionTreeModel implements TreeModel
  370. {
  371. public void addTreeModelListener(TreeModelListener l)
  372. {
  373. listenerList.add(TreeModelListener.class, l);
  374. }
  375. public void removeTreeModelListener(TreeModelListener l)
  376. {
  377. listenerList.remove(TreeModelListener.class, l);
  378. }
  379. public Object getChild(Object parent, int index)
  380. {
  381. if (parent instanceof OptionGroup)
  382. {
  383. return ((OptionGroup)parent).getMember(index);
  384. }
  385. else
  386. {
  387. return null;
  388. }
  389. }
  390. public int getChildCount(Object parent)
  391. {
  392. if (parent instanceof OptionGroup)
  393. {
  394. return ((OptionGroup)parent).getMemberCount();
  395. }
  396. else
  397. {
  398. return 0;
  399. }
  400. }
  401. public int getIndexOfChild(Object parent, Object child)
  402. {
  403. if (parent instanceof OptionGroup)
  404. {
  405. return ((OptionGroup)parent)
  406. .getMemberIndex(child);
  407. }
  408. else
  409. {
  410. return -1;
  411. }
  412. }
  413. public Object getRoot()
  414. {
  415. return root;
  416. }
  417. public boolean isLeaf(Object node)
  418. {
  419. return node instanceof OptionPane;
  420. }
  421. public void valueForPathChanged(TreePath path, Object newValue)
  422. {
  423. // this model may not be changed by the TableCellEditor
  424. }
  425. protected void fireNodesChanged(Object source, Object[] path,
  426. int[] childIndices, Object[] children)
  427. {
  428. Object[] listeners = listenerList.getListenerList();
  429. TreeModelEvent modelEvent = null;
  430. for (int i = listeners.length - 2; i >= 0; i -= 2)
  431. {
  432. if (listeners[i] != TreeModelListener.class)
  433. continue;
  434. if (modelEvent == null)
  435. {
  436. modelEvent = new TreeModelEvent(source,
  437. path, childIndices, children);
  438. }
  439. ((TreeModelListener)listeners[i + 1])
  440. .treeNodesChanged(modelEvent);
  441. }
  442. }
  443. protected void fireNodesInserted(Object source, Object[] path,
  444. int[] childIndices, Object[] children)
  445. {
  446. Object[] listeners = listenerList.getListenerList();
  447. TreeModelEvent modelEvent = null;
  448. for (int i = listeners.length - 2; i >= 0; i -= 2)
  449. {
  450. if (listeners[i] != TreeModelListener.class)
  451. continue;
  452. if (modelEvent == null)
  453. {
  454. modelEvent = new TreeModelEvent(source,
  455. path, childIndices, children);
  456. }
  457. ((TreeModelListener)listeners[i + 1])
  458. .treeNodesInserted(modelEvent);
  459. }
  460. }
  461. protected void fireNodesRemoved(Object source, Object[] path,
  462. int[] childIndices, Object[] children)
  463. {
  464. Object[] listeners = listenerList.getListenerList();
  465. TreeModelEvent modelEvent = null;
  466. for (int i = listeners.length - 2; i >= 0; i -= 2)
  467. {
  468. if (listeners[i] != TreeModelListener.class)
  469. continue;
  470. if (modelEvent == null)
  471. {
  472. modelEvent = new TreeModelEvent(source,
  473. path, childIndices, children);
  474. }
  475. ((TreeModelListener)listeners[i + 1])
  476. .treeNodesRemoved(modelEvent);
  477. }
  478. }
  479. protected void fireTreeStructureChanged(Object source,
  480. Object[] path, int[] childIndices, Object[] children)
  481. {
  482. Object[] listeners = listenerList.getListenerList();
  483. TreeModelEvent modelEvent = null;
  484. for (int i = listeners.length - 2; i >= 0; i -= 2)
  485. {
  486. if (listeners[i] != TreeModelListener.class)
  487. continue;
  488. if (modelEvent == null)
  489. {
  490. modelEvent = new TreeModelEvent(source,
  491. path, childIndices, children);
  492. }
  493. ((TreeModelListener)listeners[i + 1])
  494. .treeStructureChanged(modelEvent);
  495. }
  496. }
  497. private OptionGroup root = new OptionGroup(null);
  498. private EventListenerList listenerList = new EventListenerList();
  499. } //}}}
  500. }