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
This commit is contained in:
mdb
2003-01-15 00:46:49 +00:00
parent 496252158d
commit 0daf5da468
@@ -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.
*
* <p> Adjustments are bound to a {@link Config} property which can be
* changed through the config interface or through the bound runtime
* adjust.
*
* <p> <em>Note:</em> adjusts are meant to be arranged in a two level
* hierarchy. An adjust's name, therefore, should be of the form:
* <code>library.package.adjustment</code>. The <code>package</code>
* component can consist of multiple words joined with a period, but the
* <code>library</code> will always be the first word before the first
* period and the <code>adjustment</code> 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();
}