view src/samer/core_/X.java @ 0:bf79fb79ee13

Initial Mercurial check in.
author samer
date Tue, 17 Jan 2012 17:50:20 +0000
parents
children
line wrap: on
line source
/*
 *	X.java	
 *
 *	Copyright (c) 2001, Samer Abdallah, King's College London.
 *	All rights reserved.
 *
 *	This software is provided AS IS and WITHOUT ANY WARRANTY; 
 *	without even the implied warranty of MERCHANTABILITY or
 *	FITNESS FOR A PARTICULAR PURPOSE.
 */

package samer.core;
import  java.io.StringWriter;
import  java.util.StringTokenizer;
import  java.awt.Font;
import  java.awt.Rectangle;
import  java.awt.Color;
import  java.awt.SystemColor;

import  samer.core.Environment.Datum;
import  samer.core.Environment.Codec;
import  samer.core.Environment.Autocoder;

/**
	Static methods for converting objects and extracting correctly typed
	values from Environments. Short name
	because of expected frequent use! Also, contains
	several Codec classes.
	@see samer.core.Environment
	@see samer.core.Environment.Datum
	@see samer.core.Environment.Autocoder
 */

public class X
{
	/** Tries to extract an Object from the given Datum, throws Exception in failure */
	public static Object object(Datum b) throws Exception {
		Object ret=b.get(ObjectCodec,null);
		if (ret==null) throw new Exception("no data");
		return ret;
	}

	/** Tries to extract a String given Datum */
	public static String string(Datum b) throws Exception {
		String ret=(String)b.get(StringCodec,null);
		if (ret==null) throw new Exception("datum has no value");
		return ret;
	}

	/** Tries to extract a Font given Datum. If this fails, tries
		to decode def using FontCodec. def can be a Font or a String. */
	public static Font font(Datum b, Object def) {
		return (Font)b.get(FontCodec,def);
	}

	/** Tries to extract a Rectangle from given Datum. If this fails, tries
		to decode def as a rectangle. */
	public static Rectangle rect(Datum b, Rectangle def) {
		return (Rectangle)b.get(RectangleCodec,def);
	}

	/** Get String from Datum, returning def if this fails */
	public static String string(Datum b,String def) {
		return (String)b.get(StringCodec,def);
	}

	/** Get Color from Datum, decoding def if this fails. def can
		be a Color or a String. See ColorCodec. */
	public static Color	color(Datum b, Object def) {
		return (Color)b.get(ColorCodec,def);
	}

	/** Extract int from Datum */
	public static int _int(Datum b,int def) {
		return ((Integer)b.get(IntegerCodec,new Integer(def))).intValue();
	}
	/** Extract double from Datum */
	public static double _double(Datum b,double def) {
		return ((Double)b.get(DoubleCodec,new Double(def))).doubleValue();
	}
	/** Extract boolean from Datum */
	public static boolean _bool(Datum b,boolean def) {
		return ((Boolean)b.get(BooleanCodec,new Boolean(def))).booleanValue();
	}

	/** store given object to current environment */
	public static void store(String name, Object value) {
		Shell.env().store(name,value,codec(value));
	}

	/** Extracts an integer array from a string. Valid strings are, eg
		"(1,2,3)", "(4 5 6)", "7 8 9", "10, 11, 12" */
	public static int[] parseIntArray(String s, int n)
	{
		StringTokenizer token = new StringTokenizer(s,"(), ");
		int[] a=new int[n];

		for (int i=0; i<n; i++) {
			a[i]=Integer.parseInt(token.nextToken());
		}
		return a;
	}

	/** @see samer.core.X.parseIntArray */
	public static double[] doubleArray(String s, int n)
	{
		StringTokenizer token = new StringTokenizer(s,"(), ");
		double[] a=new double[n];

		for (int i=0; i<n; i++) {
			a[i]=parseDouble(token.nextToken());
		}
		return a;
	}

	/** Sets each integer in the int array to the numeric value of the corresponding
		Objects in the Object array (they have to be subclasses of Numbe).
	 */
	public static void setIntArray(int[] a, Object[] b) {
		for (int i=0; i<a.length; i++)
			a[i]=((Number)b[i]).intValue();
	}

	/** Base class for objects that can convert some type to and from String or
		Object. @see samer.core.Environment.Codec */
	public static class BaseCodec implements Codec
	{
		public Class targetClass() { return Object.class; }

		/** convert to string using object's toString() method (a reasonable default) */
		public String string(Object o) { return o.toString(); }

		/** Convert to object by returning original object. This might be OK for
		 *  immutable objects, but should be overriden for mutable ones, perhaps
		 *	returning a clone of the original or an object of a different class altogether.
		 */
		public Object object(Object o) { return o; }

		/** Decode given object to by return it the given object itself. */
		public Object decode(Object o) {	return o; }
	};

	public static Codec ObjectCodec = new BaseCodec();

	/** Can decode numbers in Integer, Number, or String form */
	public static Codec IntegerCodec = new BaseCodec()
	{
		public Class targetClass() { return Integer.class; }

		/** If given object is any subclass of java.lang.Number, then its
			numerical value is returned as an Integer. If it is a string,
			the string is parsed to extract an integer value. Any other
			class will probably cause this function to barf.
		*/
		
		public Object decode(Object o) {
//			if (o==null) return null;
			if (o instanceof Integer) return o;
			if (o instanceof String)  return Integer.decode(o.toString());
			return new Integer(((Number)o).intValue());
		}
	};

	private static DoubleFormat fmt=new DoubleFormat(3);

	/** Convert double to string using the (private) current DoubleFormat object */
	public static String string(double v) { return fmt._format(v); }

	/** Convert string to double */
	public static double parseDouble(String s) {
		return Double.valueOf(s).doubleValue();
	}

	/** Can decode numbers in Double, Number, or String form */
	public static Codec DoubleCodec = new BaseCodec()
	{
		public Class targetClass() { return Double.class; }

		public String string(Object o) { return fmt._format(((Number)o).doubleValue()); }

		/** Can decode String or any subclass of Number */
		public Object decode(Object o) {
//			if (o==null) return null;
			if (o instanceof Double) return o;
			if (o instanceof String) return Double.valueOf(o.toString());
			return new Double(((Number)o).doubleValue());
		}

	};

	/** Can decode Boolean or String ("true" or "false") form */
	public static Codec BooleanCodec = new BaseCodec()
	{
		public Class  targetClass() { return Boolean.class; }
		public Object decode(Object o) {
//			if (o==null) return null;
			if (o instanceof Boolean) return o;
			return Boolean.valueOf(o.toString());
		}
	};

	public static Codec StringCodec = new BaseCodec()
	{
		public Class  targetClass() { return String.class; }
		public Object decode(Object o) {
//			if (o==null) return null;
			if (o instanceof String) return o;
			else return o.toString();
		}
	};


	/** Can decode Color or String form
		String can be "#rrggbb" where rrggbb are hex,
		or "(r,g,b)" or "(r g b)" where r, g, b are integers,
		or "$bg", which evaluates to SystemColor.control, the
		default background color for components,
		or "$fg", which evaluates to SystemColor.controlText,
		the default foreground color.
	*/

	public static Codec ColorCodec = new Codec()
	{
		public Class  targetClass() { return Color.class; }
		public Object object(Object o) { return o; }
		public String string(Object o) {
			StringBuffer buf=new StringBuffer("#");
			buf.append(Integer.toHexString(((Color)o).getRGB() & 0xffffff));
			return buf.toString();
		}
		public Object decode(Object o) {	
//			if (o==null) return null;
			if (o instanceof Color) return o;

			String s=o.toString();
			if (s.startsWith("(")) {
				int[] a=parseIntArray(s,3);
				return new Color(a[0],a[1],a[2]);
			}
			if (s.equals("$bg"))	return SystemColor.control;
			if (s.equals("$fg"))	return SystemColor.controlText;
			return Color.decode(s);
		}
	};

	/** Can decode Font or String, using Font.decode(),
		eg "Helvetica-PLAIN-12" */
	public static Codec FontCodec = new Codec()
	{
		public Class  targetClass() { return Font.class; }
		public Object object(Object o) { return o; }
		public String string(Object o) { return o.toString(); }
		public Object decode(Object o) {
//			if (o==null) return null;
			if (o instanceof Font)   return o;
			return Font.decode(o.toString());
		}
	};

	public static Codec RectangleCodec = new Codec()
	{
		public Class  targetClass() { return Font.class; }
		public Object object(Object o) { return o; }
		public String string(Object o) {
			Rectangle      r=(Rectangle)o;
			StringBuffer	buf=new StringBuffer();

			buf.append('(');
			buf.append(String.valueOf(r.x));			buf.append(',');
			buf.append(String.valueOf(r.y));			buf.append(',');
			buf.append(String.valueOf(r.width));	buf.append(',');
			buf.append(String.valueOf(r.height));
			buf.append(')');
			return buf.toString();
		}

		public Object decode(Object o) {
//			if (o==null) return null;
			if (o instanceof Rectangle) return o;

			int[] a=parseIntArray(o.toString(),4);
			return new Rectangle(a[0],a[1],a[2],a[3]);
		}
	};

	public static Codec codec(Object o) { return codec(o.getClass()); }
	public static Codec codec(Class c)
	{
		for (int i=classes.length-1; i>0; i--) {
			if (classes[i].isAssignableFrom(c)) return codecs[i];
		}
		return codecs[0];
	}

	private static Class[] classes = {
		Object.class,
		Font.class,
		Rectangle.class,
		Color.class,
		String.class,
		Boolean.class,
		Integer.class,
		Double.class
	};

	private static Codec[] codecs = {
		ObjectCodec,
		FontCodec,
		RectangleCodec,
		ColorCodec,
		StringCodec,
		BooleanCodec,
		IntegerCodec,
		DoubleCodec
	};
}