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