diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/X.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,317 @@
+/*
+ *	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
+	};
+}
+