2003/09/24 07:33:32
[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         String[] p = new String[] {
23             "shrink", "hshrink", "vshrink", "x", "y",
24             "width", "height", "flex", "colspan", "rowspan", "cols",
25             "rows", "align", "invisible", "absolute", "globalx",
26             "globaly", "minwidth", "minheight", "height", "width",
27             "maxwidth", "maxheight", "numchildren", "hpad", "vpad",
28             "buffered", "cursor", "mousex", "mousey",
29             "mouseinside", "thisbox", "indexof", "path", "font", "fontsize"
30         };
31         for(int i=0; i<p.length; i++) PROHIBITED.put(p[i], Boolean.TRUE);
32     };
33
34
35     // Instance Members ////////////////////////////////////////////////////////
36
37     /** the box on which this trap was placed */
38     private Box trapee = null;
39
40     /** the function for this trap */
41     JS.CompiledFunction f = null;
42
43     /** the next trap down the trap stack */
44     private Trap next = null;
45
46     /** the property that the trap was placed on */
47     private Object name = null;
48
49
50     // Static Methods //////////////////////////////////////////////////////////////////////////
51
52     /**
53      *  adds a trap.
54      *  @param trapee the box to place the trap on
55      *  @param name the name of the property to trap on
56      *  @param f the function to place as a trap
57      */
58     static void addTrap(Box trapee, Object name, JS.CompiledFunction f) {
59
60         // check if this script has already placed a trap on this property
61         for(Trap t = (Trap)trapee.get(name, Trap.class); t != null; t = t.next)
62             if (t.f == f) return;
63         
64         // actually place the trap
65         Trap t = new Trap();
66         t.next = (Trap)trapee.get(name, Trap.class);
67         trapee.put(name, Trap.class, t);
68         t.trapee = trapee;
69         t.name = name;
70         t.f = f;
71     }
72
73
74     /**
75      *  deletes a trap.
76      *  @param trapee the box to remove the trap from
77      *  @param name the name of the property to trap on
78      *  @param f the function to remove
79      */
80     static void delTrap(Box trapee, Object name, JS.CompiledFunction f) {
81         Trap t = (Trap)trapee.get(name, Trap.class);
82         if (t.f == f) {
83             trapee.put(name, Trap.class, t.next);
84             return;
85         }
86         for(; t.next != null; t = t.next)
87             if (t.next.f == f) {
88                 t.next = t.next.next;
89                 return;
90             }
91         Log.logJS("warning: tried to remove a trap that had not been placed");
92     }
93
94
95     // Instance Methods //////////////////////////////////////////////////////////////////////////
96
97     private Trap() { }
98
99     public Object perform() throws JS.Exn {
100         if (f.getNumFormalArgs() > 0) return cascade();
101         return f.call(new TrapArgs(this));
102     }
103     
104     public void perform(Object val) throws JS.Exn {
105         if (f.getNumFormalArgs()== 0) cascade(val);
106         f.call(new TrapArgs(this, val));
107     }
108     
109     public Object cascade() {
110         if (next != null) return next.perform();
111         return trapee.get(name, true);
112     }
113
114     public void cascade(Object val) {
115         if (next != null) next.perform(val);
116         trapee.put(name, val, true);
117     }
118
119     private static class TrapArgs extends JS.Array {
120         private Trap t;
121         public TrapArgs(Trap t) { this.t = t; }
122         public TrapArgs(Trap t, Object value) { this.t = t; addElement(value); }
123         
124         public void put(Object key, Object val) {
125             if (key.equals("cascade")) t.cascade(val);
126             else super.put(key, val);
127         }
128
129         public Object get(Object key) {
130             // common case
131             if(!(key instanceof String)) return super.get(key);
132             if (key.equals("trapee")) return t.trapee;
133             if (key.equals("trapname")) return t.name;
134             if (key.equals("cascade")) return t.cascade();
135             return super.get(key);
136         }
137     }
138 }
139