c6c6a47bd166b783a8b110c2dd520b877d4275e3
[org.ibex.core.git] / src / org / xwt / Trap.java
1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
2 package org.xwt;
3
4 import java.util.*;
5 import org.xwt.js.*;
6 import org.xwt.util.*;
7
8 /**
9  *  This class encapsulates a single trap placed on a given node. The
10  *  traps for a given property name on a given box are maintained as a
11  *  linked list stack, with the most recently placed trap at the head
12  *  of the list.
13  */
14 public class Trap {
15
16     // Static Data //////////////////////////////////////////////////////////////
17
18     /** List of properties that cannot be trapped */
19     private static final Hash PROHIBITED = new Hash(120, 3);
20
21     static {
22         // FIXME: review
23         String[] p = new String[] {
24             "sizetoimage", "shrink", "hshrink", "vshrink", "x", "y",
25             "width", "height", "flex", "hflex", "vflex", "cols",
26             "rows", "align", "invisible", "absolute", "globalx",
27             "globaly", "minwidth", "minheight", "height", "width",
28             "maxwidth", "maxheight", "numchildren", "hpad", "vpad",
29             "doublebuffered", "cursor", "mousex", "mousey", "xwt",
30             "static", "mouseinside", "root", "thisbox", "indexof",
31             "path"
32         };
33         for(int i=0; i<p.length; i++) PROHIBITED.put(p[i], Boolean.TRUE);
34     };
35
36
37     // Instance Members ////////////////////////////////////////////////////////
38
39     /** the box on which this trap was placed */
40     private Box trapee = null;
41
42     /** the function for this trap */
43     JS.CompiledFunction f = null;
44
45     /** the next trap down the trap stack */
46     private Trap next = null;
47
48     /** the property that the trap was placed on */
49     private Object name = null;
50
51
52     // Static Methods //////////////////////////////////////////////////////////////////////////
53
54     /**
55      *  adds a trap.
56      *  @param trapee the box to place the trap on
57      *  @param name the name of the property to trap on
58      *  @param f the function to place as a trap
59      */
60     static void addTrap(Box trapee, Object name, JS.CompiledFunction f) {
61
62         // check if this script has already placed a trap on this property
63         for(Trap t = (Trap)trapee.get(name, Trap.class); t != null; t = t.next)
64             if (t.f == f) return;
65         
66         // actually place the trap
67         Trap t = new Trap();
68         t.next = (Trap)trapee.get(name, Trap.class);
69         trapee.put(name, Trap.class, t);
70         t.trapee = trapee;
71         t.name = name;
72         t.f = f;
73     }
74
75
76     /**
77      *  deletes a trap.
78      *  @param trapee the box to remove the trap from
79      *  @param name the name of the property to trap on
80      *  @param f the function to remove
81      */
82     static void delTrap(Box trapee, Object name, JS.CompiledFunction f) {
83         Trap t = (Trap)trapee.get(name, Trap.class);
84         if (t.f == f) {
85             trapee.put(name, Trap.class, t.next);
86             return;
87         }
88         for(; t.next != null; t = t.next)
89             if (t.next.f == f) {
90                 t.next = t.next.next;
91                 return;
92             }
93         Log.logJS("warning: tried to remove a trap that had not been placed");
94     }
95
96
97     // Instance Methods //////////////////////////////////////////////////////////////////////////
98
99     private Trap() { }
100
101     public Object perform() throws JS.Exn {
102         if (f.getNumFormalArgs() > 0) return cascade();
103         return f.call(new TrapArgs(this));
104     }
105     
106     public void perform(Object val) throws JS.Exn {
107         if (f.getNumFormalArgs()== 0) cascade(val);
108         f.call(new TrapArgs(this, val));
109     }
110     
111     public Object cascade() {
112         if (next != null) return next.perform();
113         return trapee.get(name, true);
114     }
115
116     public void cascade(Object val) {
117         if (next != null) next.perform(val);
118         trapee.put(name, val, true);
119     }
120
121     private static class TrapArgs extends JS.Array {
122         private Trap t;
123         public TrapArgs(Trap t) { this.t = t; }
124         public TrapArgs(Trap t, Object value) { this.t = t; addElement(value); }
125         
126         public void put(Object key, Object val) {
127             if (key.equals("cascade")) t.cascade(val);
128             else super.put(key, val);
129         }
130
131         public Object get(Object key) {
132             // common case
133             if(!(key instanceof String)) return super.get(key);
134             if (key.equals("trapee")) return t.trapee;
135             if (key.equals("trapname")) return t.name;
136             if (key.equals("cascade")) return t.cascade();
137             return super.get(key);
138         }
139     }
140 }
141