⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 optionizer.java

📁 ErGo是一个很早的Java通用围棋服务器(IGS/NNGS)客户端程序。有全部源码和文档
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
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 + -