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