added Form, other minor changes
[org.ibex.xt.git] / src / org / ibex / xt / Form.java
1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
4
5 package org.ibex.xt;
6 import org.ibex.js.*;
7 import org.ibex.util.*;
8 import org.ibex.io.*;
9 import java.lang.reflect.*;
10 import java.io.*;
11 import java.net.*;
12 import java.util.*;
13 import javax.servlet.*;
14 import javax.servlet.http.*;
15
16 // tabbing order?  accessability key?
17 // the 'name' property is taken from the field name, with underscores converted to spaces
18 // the way I'm doing Radio() { ... } right now is how multi-select menus ought to work
19 // autogenerate <LABEL> elements?
20 //     <TD><LABEL for="fname">First Name</LABEL>
21 //     <TD><INPUT type="text" name="firstname" id="fname">
22
23 public abstract class Form extends HttpServlet {
24
25     final String action;
26     public Form(String action) { this.action = action; }
27
28     public static class TestForm extends Form {
29         public TestForm() { super("/foo"); }
30         public boolean[]  poo        = new boolean[] { true, false, true, true };
31         public String[]   poo3       = new String[] { "a", "b", "c" };
32         public boolean    poo2       = true;
33         public String     myName     = "blarg";
34         public Radio      day        = new Radio() { public boolean sun, mon, tue, wed, thu, fri, sat; };
35         public CheckBox   vegetarian = new CheckBox();                     // label taken from field name
36         public CheckBox   vegan      = new CheckBox("are you vegan?");
37         public Text       firstName  = new Text("First Name");
38         public Text       lastName   = new Text();
39         public Password   pass;
40         public CheckBox[] checkboxes = new CheckBox[] {
41             new CheckBox("foo"),
42             new CheckBox("bar"),
43             new CheckBox("baz")
44         };
45         //public Option[] options    = new Option[] { new Option("foo"); }
46     }
47     public static void main(String[] s) throws Exception {
48         Form sample = new TestForm();
49         System.out.println(sample.emit());
50     }
51
52     public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { doGet(request, response); }
53     public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
54         Field[] fields = this.getClass().getFields();
55         for(int i=0; i<fields.length; i++) {
56             Field f     = fields[i];
57             Class c     = f.getType();
58             String name = f.getName();
59             Log.warn("param", name + " = " + request.getParameter(name));
60         }        
61     }
62
63     //public abstract void validate(HttpServletRequest req);
64     //public abstract void go(HttpServletRequest req, HttpServletResponse resp);
65
66     public JS fields() {
67         JSArray ret = new JSArray();
68         Field[] fields = this.getClass().getFields();
69         for(int i=0; i<fields.length; i++) {
70             Field f     = fields[i];
71             String name = f.getName();
72             ret.add(JSU.S(name));
73         }
74         return ret;
75     }
76
77     public String emit() throws Exception { return emit(null); }
78     public String emit(String fieldName) throws Exception {
79         Field[] fields = this.getClass().getFields();
80         StringBuffer ret = new StringBuffer();
81         if (fieldName==null) ret.append("<form xmlns='http://www.w3.org/1999/xhtml'"+q("action",action)+">\n");
82         for(int i=0; i<fields.length; i++) {
83             Field f     = fields[i];
84             Class c     = f.getType();
85             String name = f.getName();
86             if (fieldName != null && !fieldName.equals(name)) continue;
87             if (c == Boolean.TYPE) {
88                 boolean b = ((Boolean)f.get(this)).booleanValue();
89                 ret.append("    <input type='checkbox'"+q("name",name)+(b?" checked='on'":"")+"/>\n");
90             } else if (c == String.class) {
91                 ret.append("    ");
92                 Text t = new Text(f.getName());
93                 t.value = ((String)f.get(this));
94                 ret.append(t.emit());
95                 ret.append('\n');
96             } else if (c.isArray()) {
97                 Class c2 = c.getComponentType();
98                 int len = Array.getLength(f.get(this));
99                 for(int j=0; j<len; j++) {
100                     ret.append("      ");
101                     if (c2 == Boolean.TYPE) {
102                         boolean b = ((Boolean)Array.get(f.get(this),j)).booleanValue();
103                         ret.append("    <input type='checkbox'"+q("name",name+"_"+j)+(b?" checked='on'":"")+"/>\n");
104                     } else if (c2 == String.class) {
105                         Text t = new Text(f.getName()+"_"+j);
106                         t.value = (String)Array.get(f.get(this),j);
107                         ret.append(t.emit());
108                     } else {
109                         Element[] o = (Element[])f.get(this);
110                         o[j].name = name+"_"+j;
111                         ret.append(o[j].emit());
112                     }
113                     ret.append('\n');
114                 }
115             } else if (!Element.class.isAssignableFrom(c)) {  // nothing
116             } else {
117                 Element e = (Element)f.get(this);
118                 if (e==null) {
119                     e = (Element)c.newInstance();
120                     f.set(this, e);
121                 }
122                 if (e.name==null) e.name = name;
123                 ret.append("    ");
124                 ret.append(e.emit());
125                 ret.append('\n');
126             }
127         }
128         if (fieldName==null) ret.append("</form>\n");
129         return ret.toString();
130     }
131
132     public static String q(String key, String val)  { return val==null ? "" : " "+key+"='"+val+"'"; }
133     public static String q(String key, int val)     { return key+" ='"+val+"'"; }
134     public static String q(String key, boolean val) { return val ? " "+key+"=true" : ""; }
135     public static String escape(String s) { return s.replaceAll("&","&amp;").replaceAll("<","&gt;").replaceAll("'","&apos;"); }
136
137     public static abstract class Element {
138         public String  name     = null;
139         public boolean disabled = false;
140         public String  id       = null;
141         public int     size     = -1;
142         public String  alt      = null;
143         public Element() { }
144         public Element(String name) { this.name = name; }
145         public String fields() { return q("id",id)+q("disabled", disabled)+q("alt", alt); }
146         public String emit() { return "<input"+q("name",name)+q("type",type())+fields()+"/>"; }
147         public String type() {
148             String t = this.getClass().getName().toLowerCase();
149             if (t.indexOf('.') != -1) t = t.substring(t.lastIndexOf('.')+1);
150             if (t.indexOf('$') != -1) t = t.substring(t.lastIndexOf('$')+1);
151             return t;
152         }
153     }
154
155     public static class Text extends Element{
156         public String  value     = null;
157         public boolean ro        = false;
158         public char    maxLength = 0;
159         public String  fields(){return super.fields()+q("value",value)+q("readonly",ro)+(maxLength>0?q("maxlength",maxLength):"");}
160         public Text()                { super(); }
161         public Text(String name)     { super(name); }
162     }
163     public static class Password extends Text { }
164     public static class Hidden   extends Text { }
165     public static class TextArea extends Text {
166         int rows; // relation to 'size'?
167         int cols;
168         private TextArea() { }
169         public  TextArea(int rows, int cols) { this.rows=rows; this.cols=cols; }
170         public  String fields() { return super.fields()+q("rows",rows)+q("cols",cols); }
171         public  String emit()   { return "<textarea"+fields()+">\n"+escape(value)+"</textarea>"; }
172     }
173
174     public static class Radio extends Element {
175         public String emit() {
176             StringBuffer ret = new StringBuffer();
177             try {
178                 Class c = this.getClass();
179                 Field[] f = c.getFields();
180                 for(int i=0; i<f.length; i++) {
181                     if (f[i].getType() != Boolean.TYPE) continue;
182                     if (f[i].getDeclaringClass().isAssignableFrom(Radio.class)) continue;
183                     boolean b = ((Boolean)f[i].get(this)).booleanValue();
184                     ret.append("        ");
185                     ret.append("<input type='radio'"+q("name",name)+q("value",f[i].getName())+(b?" checked='true'":"")+"/>");
186                     ret.append('\n');
187                 }
188             } catch (Exception e) { e.printStackTrace(); }
189             return ret.toString();
190         }
191     }
192
193     public static class Submit extends Element { public Submit(String label) { super(label); } }
194     public static class Reset extends Element  { public Reset(String label)  { super(label); } }
195     public static class Upload extends Element {
196         String filename;
197         public Upload(String label) { super(label); }
198         public Upload(String label, String filename) { super(label); this.filename=filename; }
199     }
200
201     public static class CheckBox extends Element {
202         boolean on = false;
203         public String fields()        { return super.fields()+q("on",on); }
204         public CheckBox()             { super(); }
205         public CheckBox(String label) { super(label); }
206     }
207
208     /*
209     public static class Image extends Element {
210         // usemap, ismap
211         private Image() { }
212         public  Image(String url, String alt) { }
213         public  String url;
214         public  int x;
215         public  int y;
216     }
217
218
219     // Option[] -> Menu
220
221     // size == number of visible rows
222     public static class Menu extends Element {
223         // force a pre-selected option
224         public static class Item {
225             String label;
226             String value;
227             boolean selected = false;
228         }
229         public static class Group extends Item { }
230         public Menu(Item[] items) { }
231         public boolean multipleSelect;
232     }
233     */
234 }