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