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

/jEdit/tags/jedit-4-2-pre4/org/gjt/sp/jedit/gui/OptionsDialog.java

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