📄 optionizer.java
字号:
package ergo.ui;
// $Id: Optionizer.java,v 1.5 1999/08/13 01:20:09 sigue Exp $
/*
* Copyright (C) 1999 Carl L. Gay and Antranig M. Basman.
* See the file copyright.txt, distributed with this software,
* for further information.
*/
import ergo.*;
import ergo.server.GoServer;
import ergo.util.Debug;
import ergo.util.ErgoException;
import ergo.util.ParseException;
import ergo.util.ParsedMessage;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
// This class manages storage for multiple-valued options, i.e.
// it corresponds to exactly one keyword.
class OptionStorage {
// list of targets to be informed when this option changes.
public OptionizableVector targets;
// indeed, a type field, but with a difference.
// Optionizer.TYPE_UNKNOWN indicates we do not know the type yet....!
public int type;
// vector of SingleOptionStorage. nulls may be stored here.
private Vector data;
// used when rewriting file: highest option number seen.
public int highestseen;
// was this option (only 0 can be set here) supplied as an internal
// application default?
public boolean internaldefault = true; // default until hit by updateOption().
public String originalkeyword;
public OptionStorage (String ok1) {
originalkeyword = ok1;
targets = new OptionizableVector();
data = new Vector(1,2);
type = Optionizer.TYPE_UNKNOWN;
}
public int size () { return data.size(); }
public Object dataAt (int i) {
if (i < data.size())
return ((SingleOptionStorage) data.elementAt(i)).data;
else
return null;
}
public boolean flagAt (int i) {
return ((SingleOptionStorage) data.elementAt(i)).writeflag;
}
public SingleOptionStorage sosAt (int i) {
return (SingleOptionStorage) data.elementAt(i);
}
// get the highest set writeflag for this option
public int calchighestseen () {
int highest = 0;
for (int i = 0; i < data.size(); ++i) {
if (data.elementAt(i) != null && sosAt(i).writeflag) highest = i;
}
highestseen = highest;
return highestseen;
}
// unset all the flags for this option.
public void unsetAllFlags () {
for (int i = 0; i<data.size(); ++i) {
if (data.elementAt(i) != null) sosAt(i).writeflag = false;
}
}
public void setFlagAt (int i) {
if (data.elementAt(i) != null) sosAt(i).writeflag = true;
}
// "Internal" function for updating options. Does not cause broadcast.
// Merely manages blanks in vector, and its size.
public void applyData(int where, Object what) {
// fill in blanks in vector - Vectors are not so hot.
if (where > data.size()) {
for (int wheres = data.size(); wheres < where; ++wheres)
data.addElement(new SingleOptionStorage(null));
}
// fall through to here, and hopefully slap data on the end.
if (where == data.size()) {
SingleOptionStorage sos = new SingleOptionStorage(what);
data.addElement(sos);
}
// finally fall through to here.
sosAt(where).data = what;
}
/* Maintains a vector of Optionizable targets for an option. Wouldn't
* limited types be nice.
*/
class OptionizableVector {
private Vector v;
public OptionizableVector () {
v = new Vector(1,2);
}
public Optionizable optionizableAt (int i) {
return (Optionizable)(v.elementAt(i));
}
public int size () {
return v.size();
}
public void removeElement (Optionizable o) {
v.removeElement(o);
}
public void addElement (Optionizable o) {
v.addElement(o);
}
} // end inner class OptionizableVector
/* Each key is associated with multiple values. A single value is
* represented by instance of SOS.
*/
class SingleOptionStorage {
public Object data;
public boolean writeflag = false; // used when rewriting ini file.
public SingleOptionStorage (Object data1) {
data = data1;
}
} // end inner class SingleOptionStorage
} // end class OptionStorage
/* Parent class of all option type handlers. It is not an interface,
* since it supplies default functionality for the render() method,
* which regenerates the textual form of an option from its storage.
*/
abstract class OptionHandler {
public abstract Object handle (String keyword, String value) throws ParseException;
String render (Object value) { // default renderer.
return value.toString();
}
}
/* Class Optionizer manages a pool of options indexed by
* (canonicalised) strings. Each option may have multiple values
* stored - this allows us to implement multiple option sets, by use
* of the value currentset (also an option), which is a default
* parameter to getOption() and updateOption(), and also multi-valued
* options, such as servers.
*
* Optionizer can read in values from an INI file (each option value
* must lie on a separate line), and rewrite the INI file with
* updated options, when requested.
*
* Whenever an option changes, a collection of Optionizable observers
* receive a call to optionEvent to inform them of the change.
*/
// Note: only Ergo dependence in Optionizer is now TYPE_SERVER. Only practical
// way to get rid of it would be subclassing, which would be a bit crummy.
public class Optionizer implements Optionizable {
public static final int TYPE_UNKNOWN = -1; // unknown
public static final int TYPE_INTEGER = 1; // Class Integer
public static final int TYPE_BOOLEAN = 2; // Class Boolean
public static final int TYPE_SERVER = 3; // Class GoServer
public static final int TYPE_COLOR = 4; // Class ColorSpec/Color
public static final int TYPE_FONT = 5; // Class FontSpec/Font
public static final int TYPE_SIZE = 6; // Class Dimension
public static final int TYPE_POSITION = 7; // Class Point
public static final int TYPE_BOUNDS = 8; // Class Rectangle
public static final int TYPE_STRING = 9; // Class String
// public static final int C_TYPES=8;
public static final String s = " ";
private static final String specialLine =
"### User Editable Options are probably all above this line";
private OptionHandler[] handlers = {
null,
new handleInteger(),
new handleBoolean(),
new handleServer(),
new handleColor(),
new handleFont(),
new handleSize(),
new handlePosition(),
new handleRectangle(),
new handleString()
};
public static final String currentString = "Current Option Set";
private Hashtable optionmap = new Hashtable(); // associates string
// keys with their
// storage
// get enumeration of all storages.
class osEnumeration {
Enumeration e;
boolean hasMoreElements () { return e.hasMoreElements(); }
OptionStorage nextElement () { return (OptionStorage) e.nextElement(); }
osEnumeration (Enumeration e1) { e = e1; }
}
private osEnumeration storages () {
return new osEnumeration(optionmap.elements());
}
private int currentset = 0;
private String initFile = null;
// for handleBoolean
private static Boolean T = new Boolean(true);
private static Boolean F = new Boolean(false);
// for handleSize and handleRectangle
// +++ This has package scope to work around a bug: can't reference
// private field in outer class from inner class. Bug shows up
// only when running as applet (in NS 4.0.2 + 1.1 patch).
Dimension desktopSize = new Dimension(800, 600);
private Rectangle desktopRect;
private String defaultString = "Default Font";
private String formatString = "Format";
// fake option to be broadcast when options saved, so we may gather
// at last minute.
public final String savingString = ":Saving";
public String textcolString = "Text Window Color";
public String textbackString = "Text Window Background Color";
public String texthighbackString = "Text Window Highlight Background Color";
public String texthighString = "Text Window Highlight Color";
public Optionizer () {
expressOwnership(currentString, TYPE_INTEGER, this, new Integer(0));
expressOwnership(defaultString, TYPE_FONT, null, null);
expressOwnership(formatString, TYPE_INTEGER, this, new Integer(1));
expressOwnership(savingString, TYPE_BOOLEAN, null, T);
try {
desktopSize = Toolkit.getDefaultToolkit().getScreenSize();
}
catch (Exception e) {
Debug.backtrace(e);
desktopSize = new Dimension(800,600);
}
desktopRect = new Rectangle(desktopSize);
}
public void optionEvent (String keyword, Object value) {
if (isSameKey(keyword, currentString)) {
currentset = ((Integer)value).intValue();
}
else if (isSameKey(keyword, formatString)) {
int thisformat = ((Integer)value).intValue();
if (thisformat != 1) {
System.out.println("Error: Invalid init file format: " + value);
}
if (thisformat == 0) {
System.out.println
("To migrate from format 0, make the following changes:");
System.out.println
("1. Place numbers ascending from 0 in square brackets after server names,");
System.out.println
(" -- e.g. server[2]: NNGS nngs.cosmic.org 9696 NNGS");
System.out.println("You may also remove hyphens from key names.");
}
}
}
public void setInitFile (String ifn) {
initFile = ifn;
}
// Within code, canonical is wrt. case.
// Incoming from Ini file also get further cononocolosed by hyphenMap.
public boolean isSameKey (String s1, String s2) {
return s1.equalsIgnoreCase(s2);
}
// return option storage for a particular key.
private OptionStorage lookup (String key) {
return (OptionStorage) optionmap.get(key.toLowerCase());
}
// Canonicalise INI keyword from file by mapping hyphens to spaces.
private String hyphenMap (String in) {
StringBuffer t = new StringBuffer(in);
for (int i = 0; i < t.length(); ++i) {
if (t.charAt(i) == '-') t.setCharAt(i, ' ');
}
return t.toString().toLowerCase();
}
/** Parses and stores details of an init file line.
*/
class iniParse {
String keyword;
String originalkeyword;
String value;
int number;
/** Parse a line in the init file.
* @return false for lines without keywords, true otherwise.
*/
boolean parseLine (String line) throws Exception {
int hashchar = line.indexOf('#');
int colchar = line.indexOf(':');
int brakchar = line.indexOf('[');
int cbrakchar = line.indexOf(']');
boolean numbered = false;
// System.out.println("Line: #:"+hashchar+" ::"+colchar+" [:"+brakchar+" ]:"+cbrakchar);
if (colchar == -1) return false; // no colon found.
if (hashchar > -1) { // comment found.
if (hashchar < colchar) return false; // colon commented out.
if (brakchar > colchar) numbered = true;
}
else {
if (brakchar > -1)
numbered = true;
}
int esp = 0; // end seek position for keyword
if (numbered) {
if (cbrakchar < brakchar) {
Debug.println("Incorrect option number in ini file: " +line);
return false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -