PageRenderTime 137ms CodeModel.GetById 92ms app.highlight 39ms RepoModel.GetById 0ms app.codeStats 1ms

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

#
Java | 683 lines | 523 code | 97 blank | 63 comment | 96 complexity | 67c8a6e02ba02c29e9a44a06396c817f 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 4965 2004-02-04 00:07:34Z 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		try
226		{
227			optionPane.init();
228		}
229		catch(Throwable t)
230		{
231			Log.log(Log.ERROR,this,"Error initializing options:");
232			Log.log(Log.ERROR,this,t);
233		}
234
235		if(currentPane != null)
236			stage.remove(currentPane.getComponent());
237		currentPane = optionPane;
238		stage.add(BorderLayout.CENTER,currentPane.getComponent());
239		stage.revalidate();
240		stage.repaint();
241
242		if(!isShowing())
243			addNotify();
244
245		updateSize();
246
247		currentPane = optionPane;
248	} //}}}
249
250	//{{{ Protected members
251	protected abstract OptionTreeModel createOptionTreeModel();
252	protected abstract OptionGroup getDefaultGroup();
253	//}}}
254
255	//{{{ Private members
256
257	//{{{ Instance variables
258	private String name;
259	private JSplitPane splitter;
260	private JTree paneTree;
261	private JPanel stage;
262	private JButton ok;
263	private JButton cancel;
264	private JButton apply;
265	private OptionPane currentPane;
266	private Map deferredOptionPanes;
267	//}}}
268
269	//{{{ init() method
270	private void init(String name, String pane)
271	{
272		this.name = name;
273
274		deferredOptionPanes = new HashMap();
275
276		JPanel content = new JPanel(new BorderLayout(12,12));
277		content.setBorder(new EmptyBorder(12,12,12,12));
278		setContentPane(content);
279
280		stage = new JPanel(new BorderLayout());
281
282		paneTree = new JTree(createOptionTreeModel());
283		paneTree.setVisibleRowCount(1);
284		paneTree.setCellRenderer(new PaneNameRenderer());
285
286		// looks bad with the OS X L&F, apparently...
287		if(!OperatingSystem.isMacOSLF())
288			paneTree.putClientProperty("JTree.lineStyle", "Angled");
289
290		paneTree.setShowsRootHandles(true);
291		paneTree.setRootVisible(false);
292
293		JScrollPane scroller = new JScrollPane(paneTree,
294			JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
295			JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
296		splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
297			scroller,stage);
298		content.add(splitter, BorderLayout.CENTER);
299
300		Box buttons = new Box(BoxLayout.X_AXIS);
301		buttons.add(Box.createGlue());
302
303		ok = new JButton(jEdit.getProperty("common.ok"));
304		ok.addActionListener(this);
305		buttons.add(ok);
306		buttons.add(Box.createHorizontalStrut(6));
307		getRootPane().setDefaultButton(ok);
308		cancel = new JButton(jEdit.getProperty("common.cancel"));
309		cancel.addActionListener(this);
310		buttons.add(cancel);
311		buttons.add(Box.createHorizontalStrut(6));
312		apply = new JButton(jEdit.getProperty("common.apply"));
313		apply.addActionListener(this);
314		buttons.add(apply);
315
316		buttons.add(Box.createGlue());
317
318		content.add(buttons, BorderLayout.SOUTH);
319
320		// register the Options dialog as a TreeSelectionListener.
321		// this is done before the initial selection to ensure that the
322		// first selected OptionPane is displayed on startup.
323		paneTree.getSelectionModel().addTreeSelectionListener(this);
324
325		OptionGroup rootNode = (OptionGroup)paneTree.getModel().getRoot();
326		for(int i = 0; i < rootNode.getMemberCount(); i++)
327		{
328			paneTree.expandPath(new TreePath(
329			new Object[] { rootNode, rootNode.getMember(i) }));
330		}
331
332		// returns false if no such pane exists; calling with null
333		// param selects first option pane found
334		if(!selectPane(rootNode,pane))
335			selectPane(rootNode,null);
336
337		splitter.setDividerLocation(paneTree.getPreferredSize().width
338			+ scroller.getVerticalScrollBar().getPreferredSize()
339			.width);
340
341		GUIUtilities.loadGeometry(this,name);
342		int dividerLocation = jEdit.getIntegerProperty(name + ".splitter",-1);
343		if(dividerLocation != -1)
344			splitter.setDividerLocation(dividerLocation);
345
346		// in case saved geometry is too small
347		updateSize();
348
349		show();
350	} //}}}
351
352	//{{{ selectPane() method
353	private boolean selectPane(OptionGroup node, String name)
354	{
355		return selectPane(node,name,new ArrayList());
356	} //}}}
357
358	//{{{ selectPane() method
359	private boolean selectPane(OptionGroup node, String name, ArrayList path)
360	{
361		path.add(node);
362
363		Enumeration e = node.getMembers();
364		while(e.hasMoreElements())
365		{
366			Object obj = e.nextElement();
367			if(obj instanceof OptionGroup)
368			{
369				OptionGroup grp = (OptionGroup)obj;
370				if(grp.getName().equals(name))
371				{
372					path.add(grp);
373					path.add(grp.getMember(0));
374					TreePath treePath = new TreePath(
375						path.toArray());
376					paneTree.scrollPathToVisible(treePath);
377					paneTree.setSelectionPath(treePath);
378					return true;
379				}
380				else if(selectPane((OptionGroup)obj,name,path))
381					return true;
382			}
383			else if(obj instanceof OptionPane)
384			{
385				OptionPane pane = (OptionPane)obj;
386				if(pane.getName().equals(name)
387					|| name == null)
388				{
389					path.add(pane);
390					TreePath treePath = new TreePath(
391						path.toArray());
392					paneTree.scrollPathToVisible(treePath);
393					paneTree.setSelectionPath(treePath);
394					return true;
395				}
396			}
397			else if(obj instanceof String)
398			{
399				String pane = (String)obj;
400				if(pane.equals(name)
401					|| name == null)
402				{
403					path.add(pane);
404					TreePath treePath = new TreePath(
405						path.toArray());
406					paneTree.scrollPathToVisible(treePath);
407					paneTree.setSelectionPath(treePath);
408					return true;
409				}
410			}
411		}
412
413		path.remove(node);
414
415		return false;
416	} //}}}
417
418	//{{{ save() method
419	private void save(Object obj)
420	{
421		if(obj instanceof OptionGroup)
422		{
423			OptionGroup grp = (OptionGroup)obj;
424			Enumeration members = grp.getMembers();
425			while(members.hasMoreElements())
426			{
427				save(members.nextElement());
428			}
429		}
430		else if(obj instanceof OptionPane)
431		{
432			try
433			{
434				((OptionPane)obj).save();
435			}
436			catch(Throwable t)
437			{
438				Log.log(Log.ERROR,this,"Error saving options:");
439				Log.log(Log.ERROR,this,t);
440			}
441		}
442		else if(obj instanceof String)
443		{
444			save(deferredOptionPanes.get(obj));
445		}
446	} //}}}
447
448	//{{{ updateSize() method
449	private void updateSize()
450	{
451		Dimension currentSize = getSize();
452		Dimension requestedSize = getPreferredSize();
453		Dimension newSize = new Dimension(
454			Math.max(currentSize.width,requestedSize.width),
455			Math.max(currentSize.height,requestedSize.height)
456		);
457		if(newSize.width < 300)
458			newSize.width = 300;
459		if(newSize.height < 200)
460			newSize.height = 200;
461		setSize(newSize);
462		validate();
463	} //}}}
464
465	//}}}
466
467	//{{{ PaneNameRenderer class
468	class PaneNameRenderer extends DefaultTreeCellRenderer
469	{
470		public PaneNameRenderer()
471		{
472			paneFont = UIManager.getFont("Tree.font");
473			if(paneFont == null)
474				paneFont = jEdit.getFontProperty("metal.secondary.font");
475			groupFont = paneFont.deriveFont(Font.BOLD);
476		}
477
478		public Component getTreeCellRendererComponent(JTree tree,
479			Object value, boolean selected, boolean expanded,
480			boolean leaf, int row, boolean hasFocus)
481		{
482			super.getTreeCellRendererComponent(tree,value,
483				selected,expanded,leaf,row,hasFocus);
484
485			String name = null;
486
487			if (value instanceof OptionGroup)
488			{
489				setText(((OptionGroup)value).getLabel());
490				this.setFont(groupFont);
491			}
492			else if (value instanceof OptionPane)
493			{
494				name = ((OptionPane)value).getName();
495				this.setFont(paneFont);
496			}
497			else if (value instanceof String)
498			{
499				name = ((String)value);
500				this.setFont(paneFont);
501			}
502
503			if (name != null)
504			{
505				String label = jEdit.getProperty("options." +
506					name + ".label");
507
508				if (label == null)
509				{
510					setText("NO LABEL PROPERTY: " + name);
511				}
512				else
513				{
514					setText(label);
515				}
516			}
517
518			setIcon(null);
519
520			return this;
521		}
522
523		private Font paneFont;
524		private Font groupFont;
525	} //}}}
526
527	//{{{ OptionTreeModel class
528	public class OptionTreeModel implements TreeModel
529	{
530		public void addTreeModelListener(TreeModelListener l)
531		{
532			listenerList.add(TreeModelListener.class, l);
533		}
534
535		public void removeTreeModelListener(TreeModelListener l)
536		{
537			listenerList.remove(TreeModelListener.class, l);
538		}
539
540		public Object getChild(Object parent, int index)
541		{
542			if (parent instanceof OptionGroup)
543			{
544				return ((OptionGroup)parent).getMember(index);
545			}
546			else
547			{
548				return null;
549			}
550		}
551
552		public int getChildCount(Object parent)
553		{
554			if (parent instanceof OptionGroup)
555			{
556				return ((OptionGroup)parent).getMemberCount();
557			}
558			else
559			{
560				return 0;
561			}
562		}
563
564		public int getIndexOfChild(Object parent, Object child)
565		{
566			if (parent instanceof OptionGroup)
567			{
568				return ((OptionGroup)parent)
569					.getMemberIndex(child);
570			}
571			else
572			{
573				return -1;
574			}
575		}
576
577		public Object getRoot()
578		{
579			return root;
580		}
581
582		public boolean isLeaf(Object node)
583		{
584			return !(node instanceof OptionGroup);
585		}
586
587		public void valueForPathChanged(TreePath path, Object newValue)
588		{
589			// this model may not be changed by the TableCellEditor
590		}
591
592		protected void fireNodesChanged(Object source, Object[] path,
593			int[] childIndices, Object[] children)
594		{
595			Object[] listeners = listenerList.getListenerList();
596
597			TreeModelEvent modelEvent = null;
598			for (int i = listeners.length - 2; i >= 0; i -= 2)
599			{
600				if (listeners[i] != TreeModelListener.class)
601					continue;
602
603				if (modelEvent == null)
604				{
605					modelEvent = new TreeModelEvent(source,
606						path, childIndices, children);
607				}
608
609				((TreeModelListener)listeners[i + 1])
610					.treeNodesChanged(modelEvent);
611			}
612		}
613
614		protected void fireNodesInserted(Object source, Object[] path,
615			int[] childIndices, Object[] children)
616		{
617			Object[] listeners = listenerList.getListenerList();
618
619			TreeModelEvent modelEvent = null;
620			for (int i = listeners.length - 2; i >= 0; i -= 2)
621			{
622				if (listeners[i] != TreeModelListener.class)
623					continue;
624
625				if (modelEvent == null)
626				{
627					modelEvent = new TreeModelEvent(source,
628						path, childIndices, children);
629				}
630
631				((TreeModelListener)listeners[i + 1])
632					.treeNodesInserted(modelEvent);
633			}
634		}
635
636		protected void fireNodesRemoved(Object source, Object[] path,
637			int[] childIndices, Object[] children)
638		{
639			Object[] listeners = listenerList.getListenerList();
640
641			TreeModelEvent modelEvent = null;
642			for (int i = listeners.length - 2; i >= 0; i -= 2)
643			{
644				if (listeners[i] != TreeModelListener.class)
645					continue;
646
647				if (modelEvent == null)
648				{
649					modelEvent = new TreeModelEvent(source,
650						path, childIndices, children);
651				}
652
653				((TreeModelListener)listeners[i + 1])
654					.treeNodesRemoved(modelEvent);
655			}
656		}
657
658		protected void fireTreeStructureChanged(Object source,
659			Object[] path, int[] childIndices, Object[] children)
660		{
661			Object[] listeners = listenerList.getListenerList();
662
663			TreeModelEvent modelEvent = null;
664			for (int i = listeners.length - 2; i >= 0; i -= 2)
665			{
666				if (listeners[i] != TreeModelListener.class)
667					continue;
668
669				if (modelEvent == null)
670				{
671					modelEvent = new TreeModelEvent(source,
672						path, childIndices, children);
673				}
674
675				((TreeModelListener)listeners[i + 1])
676					.treeStructureChanged(modelEvent);
677			}
678		}
679
680		private OptionGroup root = new OptionGroup(null);
681		private EventListenerList listenerList = new EventListenerList();
682	} //}}}
683}