From 0daf5da4682de20670f9640f063884e2a4a3c843 Mon Sep 17 00:00:00 2001 From: mdb Date: Wed, 15 Jan 2003 00:46:49 +0000 Subject: [PATCH] Created services for creating debug "variables" that can be toggled at runtime (and automatically persist via the Config services). This can additionally be used to make visible an interface for editing existing Config preferences, but bearing in mind that this is purely for programmer handyness and not intended as an end user interface. git-svn-id: https://samskivert.googlecode.com/svn/trunk@1015 6335cc39-0255-0410-8fd6-9bcaacd3b74c --- .../com/samskivert/util/RuntimeAdjust.java | 363 ++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100644 projects/samskivert/src/java/com/samskivert/util/RuntimeAdjust.java diff --git a/projects/samskivert/src/java/com/samskivert/util/RuntimeAdjust.java b/projects/samskivert/src/java/com/samskivert/util/RuntimeAdjust.java new file mode 100644 index 00000000..43630db6 --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/util/RuntimeAdjust.java @@ -0,0 +1,363 @@ +// +// $Id: RuntimeAdjust.java,v 1.1 2003/01/15 00:46:49 mdb Exp $ + +package com.samskivert.util; + +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Iterator; + +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.JTextField; + +import com.samskivert.Log; +import com.samskivert.swing.CollapsiblePanel; +import com.samskivert.swing.GroupLayout; +import com.samskivert.swing.MultiLineLabel; +import com.samskivert.swing.ScrollablePanel; +import com.samskivert.swing.VGroupLayout; + +/** + * Provides a service where named variables can be registered as + * adjustable by the developer at runtime. Generally a special key is + * configured (via {@link DebugChords}) to pop up the adjustable variables + * interface which can then be used to toggle booleans, change integer + * values and generally adjust debugging and tuning parameters. This is + * not meant to be an interface for end-user configurable parameters, but + * to allow the developer to tweak runtime parameters more easily. + * + *

Adjustments are bound to a {@link Config} property which can be + * changed through the config interface or through the bound runtime + * adjust. + * + *

Note: adjusts are meant to be arranged in a two level + * hierarchy. An adjust's name, therefore, should be of the form: + * library.package.adjustment. The package + * component can consist of multiple words joined with a period, but the + * library will always be the first word before the first + * period and the adjustment always the last word after the + * final period. This is mainly only important for organizing the runtime + * adjustment editing interface. + */ +public class RuntimeAdjust +{ + /** + * Creates a Swing user interface that can be used to adjust all + * registered runtime adjustments. + */ + public static JPanel createAdjustEditor () + { + VGroupLayout layout = new VGroupLayout( + VGroupLayout.NONE, VGroupLayout.STRETCH, + 3, VGroupLayout.TOP); + layout.setOffAxisJustification(VGroupLayout.LEFT); + ScrollablePanel panel = new ScrollablePanel(layout); + panel.setTracksViewportWidth(true); + + Font font = panel.getFont(); + Font smaller = font.deriveFont(font.getSize()-1f); + Font bigger = font.deriveFont(Font.BOLD, font.getSize()+2f); + + String library = null; + String pkgname = null; + CollapsiblePanel pkgpanel = null; + + int acount = _adjusts.size(); + for (int ii = 0; ii < acount; ii++) { + Adjust adjust = (Adjust)_adjusts.get(ii); + + // create a new library label if necessary + if (!adjust.getLibrary().equals(library)) { + library = adjust.getLibrary(); + pkgname = null; + JLabel label = new JLabel(library, JLabel.CENTER); + label.setFont(bigger); + panel.add(label); + } + + // create a new package panel if necessary + if (!adjust.getPackage().equals(pkgname)) { + pkgname = adjust.getPackage(); + pkgpanel = new CollapsiblePanel(); + JCheckBox pkgcheck = new JCheckBox(pkgname); + pkgcheck.setSelected(true); + pkgpanel.setTrigger(pkgcheck, null, null); + pkgpanel.setTriggerContainer(pkgcheck); + pkgpanel.getContent().setLayout(layout); + pkgpanel.setCollapsed(false); + panel.add(pkgpanel); + } + + // add an entry for this adjustment + pkgpanel.getContent().add(new JSeparator()); + JPanel editor = adjust.getEditor(); + editor.setFont(smaller); + pkgpanel.getContent().add(editor); + } + + return panel; + } + + public static class BooleanAdjust extends Adjust + implements ActionListener + { + public BooleanAdjust (String descrip, String name, + Config config, boolean defval) + { + super(descrip, name, config); + _value = _config.getValue(_name, defval); + } + + public boolean getValue () + { + return _value; + } + + public void setValue (boolean value) + { + _config.setValue(_name, value); + } + + protected void populateEditor (JPanel editor) + { + editor.add(_valbox = new JCheckBox(), GroupLayout.FIXED); + _valbox.setSelected(getValue()); + _valbox.addActionListener(this); + } + + public void actionPerformed (ActionEvent e) + { + setValue(_valbox.isSelected()); + } + + public void propertyChange (PropertyChangeEvent evt) + { + _value = ((Boolean)evt.getNewValue()).booleanValue(); + adjusted(_value); + if (_valbox != null) { + _valbox.setSelected(_value); + } + } + + protected void adjusted (boolean newValue) + { +// Log.info(_name + " => " + newValue); + } + + protected boolean _value; + protected JCheckBox _valbox; + } + + public static class IntAdjust extends Adjust + implements ActionListener + { + public IntAdjust (String descrip, String name, + Config config, int defval) + { + super(descrip, name, config); + _value = _config.getValue(_name, defval); + } + + public int getValue () + { + return _value; + } + + public void setValue (int value) + { + _config.setValue(_name, value); + } + + protected void populateEditor (JPanel editor) + { + editor.add(_valbox = new JTextField(), GroupLayout.FIXED); + _valbox.addActionListener(this); + _valbox.setText("" + getValue()); + } + + public void actionPerformed (ActionEvent e) + { + try { + setValue(Integer.parseInt(_valbox.getText())); + } catch (NumberFormatException nfe) { + _valbox.setText("" + getValue()); + } + } + + public void propertyChange (PropertyChangeEvent evt) + { + _value = ((Integer)evt.getNewValue()).intValue(); + adjusted(_value, ((Integer)evt.getOldValue()).intValue()); + if (_valbox != null) { + _valbox.setText("" + _value); + } + } + + protected void adjusted (int newValue, int oldValue) + { +// Log.info(_name + " => " + newValue); + } + + protected int _value; + protected JTextField _valbox; + } + + public static class EnumAdjust extends Adjust + implements ActionListener + { + public EnumAdjust (String descrip, String name, + Config config, String[] values, String defval) + { + super(descrip, name, config); + _values = values; + _value = _config.getValue(_name, defval); + } + + public String getValue () + { + return _value; + } + + public void setValue (String value) + { + if (!ListUtil.containsEqual(_values, value)) { + Log.warning("Refusing invalid adjustment [name=" + _name + + ", values=" + StringUtil.toString(_values) + + ", value=" + value + "]."); + } else { + _config.setValue(_name, value); + } + } + + protected void populateEditor (JPanel editor) + { + editor.add(_valbox = new JComboBox(_values), GroupLayout.FIXED); + _valbox.addActionListener(this); + _valbox.setSelectedItem(getValue()); + } + + public void actionPerformed (ActionEvent e) + { + setValue((String)_valbox.getSelectedItem()); + } + + public void propertyChange (PropertyChangeEvent evt) + { + _value = (String)evt.getNewValue(); + adjusted(_value, (String)evt.getOldValue()); + if (_valbox != null) { + _valbox.setSelectedItem(_value); + } + } + + protected void adjusted (String newValue, String oldValue) + { +// Log.info(_name + " => " + newValue); + } + + protected String _value; + protected String[] _values; + protected JComboBox _valbox; + } + + protected abstract static class Adjust + implements PropertyChangeListener, Comparable + { + public Adjust (String descrip, String name, Config config) + { + _name = name; + _descrip = descrip; + _config = config; + _config.addPropertyChangeListener(_name, this); + + // validate the structure of the name + int fdidx = _name.indexOf("."), ldidx = _name.lastIndexOf("."); + if (fdidx == -1 || ldidx == -1) { + Log.warning("Invalid adjustment name '" + _name + + "', must be of the form " + + "'library.package.adjustment'."); + return; + } + + // make sure there isn't another with the same name + int idx = _adjusts.binarySearch(this); + if (idx >= 0) { + Log.warning("Error: duplicate adjust registration " + + "[new=" + this + + ", old=" + _adjusts.get(idx) + "]."); + return; + } + + _adjusts.insertSorted(this); // keep 'em sorted + } + + public boolean equals (Object other) + { + return _name.equals(((Adjust)other)._name); + } + + public int compareTo (Object other) + { + return _name.compareTo(((Adjust)other)._name); + } + + public String getName () + { + return _name; + } + + public String getDescription () + { + return _descrip; + } + + public String getLibrary () + { + return _name.substring(0, _name.indexOf(".")); + } + + public String getPackage () + { + return _name.substring(_name.indexOf(".")+1, + _name.lastIndexOf(".")); + } + + public String getAdjustment () + { + return _name.substring(_name.lastIndexOf(".")+1); + } + + public JPanel getEditor () + { + if (_editor == null) { + _editor = GroupLayout.makeHBox(GroupLayout.STRETCH); + _editor.add(new MultiLineLabel(_descrip, MultiLineLabel.LEFT, + MultiLineLabel.VERTICAL, 25)); + populateEditor(_editor); + } + return _editor; + } + + protected abstract void populateEditor (JPanel editor); + + public String toString () + { + return StringUtil.shortClassName(this) + + "[name=" + _name + ", desc=" + _descrip + "]"; + } + + protected String _name, _descrip; + protected Config _config; + protected JPanel _editor; + } + + protected static SortableArrayList _adjusts = new SortableArrayList(); +}