1    // Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
2    package org.xwt;
3    
4    import java.util.*;
5    import java.net.*;
6    import java.text.*;
7    import org.xwt.js.*;
8    import org.xwt.util.*;
9    
10   /** 
11    *  A helper class for properties of Box which require special
12    *  handling.
13    *
14    *  To avoid excessive use of String.equals(), the Box.get() and
15    *  Box.put() methods employ a Hash keyed on property names that
16    *  require special handling. The value stored in the Hash is an
17    *  instance of an anonymous subclass of SpecialBoxProperty, which knows
18    *  how to handle get()s and put()s for that property name. There
19    *  should be one anonymous subclass of SpecialBoxProperty for each
20    *  specially-handled property on Box.
21    */
22   class SpecialBoxProperty {
23   
24       SpecialBoxProperty() { }
25       private static final int NUMINTS = Box.NUMINTS;
26       private static final int dmax = Box.dmax;
27       private static final int dmin = Box.dmin;
28       private static final int cmin = Box.cmin;
29       private static final int abs = Box.abs;
30       private static final int pos = Box.pos;
31       private static final int size = Box.size;
32       private static final int oldpos = Box.oldpos;
33       private static final int oldsize = Box.oldsize;
34       private static final int pad = Box.pad;
35   
36       /** stores instances of SpecialBoxProperty; keyed on property name */
37       static Hash specialBoxProperties = new Hash(200, 3);
38   
39       /** this method defines the behavior when the property is get()ed from b */
40       Object get(Box b) { return null; }
41   
42       /** this method defines the behavior when the property is put() to b */
43       void put(Box b, Object value) { }
44   
45       /** this method defines the behavior when the property is put() to b, allows a single SpecialBoxProperty to serve multiple properties */
46       void put(String name, Box b, Object value) { put(b, value); }
47   
48       // 'ye olde IBM CGA colours', as defined in the XWT reference
49       static final int black = 0xFF000000;
50       static final int blue = 0xFF000088;
51       static final int green = 0xFF008800;
52       static final int cyan = 0xFF008888;
53       static final int red = 0xFF880000;
54       static final int magenta = 0xFF880088;
55       static final int brown = 0xFF888800;
56       static final int lightGray = 0xFFBDBEBD;
57       static final int darkGray = 0xFF242424;
58       static final int brightBlue = 0xFF0000FF;
59       static final int brightGreen = 0xFF00FF00;
60       static final int brightCyan = 0xFF00FFFF;
61       static final int brightRed = 0xFFFF0000;
62       static final int pink = 0xFFFF00FF;
63       static final int yellow = 0xFFFFFF00;
64       static final int white = 0xFFFFFFFF;
65   
66       static {
67           specialBoxProperties.put("color", new SpecialBoxProperty() {
68                   public Object get(Box b) {
69                       if ((b.color & 0xFF000000) == 0) return null;
70                       String red = Integer.toHexString((b.color & 0x00FF0000) >> 16);
71                       String green = Integer.toHexString((b.color & 0x0000FF00) >> 8);
72                       String blue = Integer.toHexString(b.color & 0x000000FF);
73                       if (red.length() < 2) red = "0" + red;
74                       if (blue.length() < 2) blue = "0" + blue;
75                       if (green.length() < 2) green = "0" + green;
76                       return "#" + red + green + blue;
77                   }
78                   public void put(Box b, Object value) {
79                       int newcolor = b.color;
80                       String s = value == null ? null : value.toString();
81                       if (value == null) newcolor = 0x00000000;
82                       else if (s.length() > 0 && s.charAt(0) == '#')
83                           try {
84                               newcolor = 0xFF000000 |
85                                   (Integer.parseInt(s.substring(1, 3), 16) << 16) |
86                                   (Integer.parseInt(s.substring(3, 5), 16) << 8) |
87                                   Integer.parseInt(s.substring(5, 7), 16);
88                           } catch (NumberFormatException e) {
89                               Log.log(this, "invalid color " + s);
90                               return;
91                           }
92                       else if (s.equals("black")) newcolor = black;
93                       else if (s.equals("blue")) newcolor = blue;
94                       else if (s.equals("green")) newcolor = green;
95                       else if (s.equals("cyan")) newcolor = cyan;
96                       else if (s.equals("red")) newcolor = red;
97                       else if (s.equals("magenta")) newcolor = magenta;
98                       else if (s.equals("brown")) newcolor = brown;
99                       else if (s.equals("lightGray")) newcolor = lightGray;
100                      else if (s.equals("darkGray")) newcolor = darkGray;
101                      else if (s.equals("brightBlue")) newcolor = brightBlue;
102                      else if (s.equals("brightGreen")) newcolor = brightGreen;
103                      else if (s.equals("brightCyan")) newcolor = brightCyan;
104                      else if (s.equals("brightRed")) newcolor = brightRed;
105                      else if (s.equals("pink")) newcolor = pink;
106                      else if (s.equals("yellow")) newcolor = yellow;
107                      else if (s.equals("white")) newcolor = white;
108                      else if (Log.on) Log.logJS(this, "invalid color \"" + s + "\"");
109                      if (newcolor == b.color) return;
110                      b.color = newcolor;
111                      b.dirty();
112                  } });
113          
114          
115          specialBoxProperties.put("textcolor", new SpecialBoxProperty() {
116                  public Object get(Box b) {
117                      if ((b.textcolor & 0xFF000000) == 0) return null;
118                      String red = Integer.toHexString((b.textcolor & 0x00FF0000) >> 16);
119                      String green = Integer.toHexString((b.textcolor & 0x0000FF00) >> 8);
120                      String blue = Integer.toHexString(b.textcolor & 0x000000FF);
121                      if (red.length() < 2) red = "0" + red;
122                      if (blue.length() < 2) blue = "0" + blue;
123                      if (green.length() < 2) green = "0" + green;
124                      return "#" + red + green + blue;
125                  }
126                  public void put(Box b, Object value) {
127                      int newtextcolor = b.color;
128                      if (value == null) return;
129                      String s = value.toString();
130                      if (s.length() > 0 && s.charAt(0) == '#')
131                          newtextcolor = 0xFF000000 |
132                              (Integer.parseInt(s.substring(1, 3), 16) << 16) |
133                              (Integer.parseInt(s.substring(3, 5), 16) << 8) |
134                              Integer.parseInt(s.substring(5, 7), 16);
135                      else if (s.equals("black")) newtextcolor = black;
136                      else if (s.equals("blue")) newtextcolor = blue;
137                      else if (s.equals("green")) newtextcolor = green;
138                      else if (s.equals("cyan")) newtextcolor = cyan;
139                      else if (s.equals("red")) newtextcolor = red;
140                      else if (s.equals("magenta")) newtextcolor = magenta;
141                      else if (s.equals("brown")) newtextcolor = brown;
142                      else if (s.equals("lightGray")) newtextcolor = lightGray;
143                      else if (s.equals("darkGray")) newtextcolor = darkGray;
144                      else if (s.equals("brightBlue")) newtextcolor = brightBlue;
145                      else if (s.equals("brightGreen")) newtextcolor = brightGreen;
146                      else if (s.equals("brightCyan")) newtextcolor = brightCyan;
147                      else if (s.equals("brightRed")) newtextcolor = brightRed;
148                      else if (s.equals("pink")) newtextcolor = pink;
149                      else if (s.equals("yellow")) newtextcolor = yellow;
150                      else if (s.equals("white")) newtextcolor = white;
151                      else if (Log.on) Log.logJS(this, "invalid color \"" + s + "\"");
152                      if (newtextcolor == b.textcolor) return;
153                      b.textcolor = newtextcolor;
154                      b.dirty();
155                  } });
156          
157          specialBoxProperties.put("text", new SpecialBoxProperty() {
158                  public Object get(Box b) { return b.text; }
159                  public void put(Box b, Object value) {
160                      String t = value == null ? "null" : value.toString();
161                      if (t.equals(b.text)) return;
162  
163                      for(int i=0; i<t.length(); i++)
164                          if (Character.isISOControl(t.charAt(i))) {
165                              if (Log.on) Log.log(this, 
166                                                  "ISO Control characters are not permitted in box text strings; offending character is ASCII " +
167                                                 ((int)t.charAt(i)));
168                              return;
169                          }
170  
171                      // FEATURE: try removing the following line; it appears to be redundant
172                      b.dirty();
173                      b.text = t;
174                      b.textupdate();
175                      b.dirty();
176                  } });
177          
178          specialBoxProperties.put("thisbox", new SpecialBoxProperty() {
179                  public Object get(Box b) { return b; }
180                  public void put(Box b, Object value) {
181                      if (value == null) b.remove();
182                      else if (value.equals("window") || value.equals("frame")) {
183                          if (b.redirect != b && Log.on)
184                              Log.log(this, "WARNING: you have created a surface whose root box's redirect is not itself " +
185                                      "-- this isn't usually a good idea");
186                          Platform.createSurface(b, value.equals("frame"), true);
187                      } else if (Log.on) Log.log(this, "put invalid value to 'thisbox' property: " + value);
188                  }
189              });
190  
191          specialBoxProperties.put("orient", new SpecialBoxProperty() {
192                  public Object get(Box b) {
193                      if (b.redirect == null) return "horizontal";
194                      else if (b.redirect != b) return get(b.redirect);
195                      else if (b.o == 1) return "vertical";
196                      else return "horizontal";
197                  }
198                  public void put(Box b, Object value) {
199                      if (value == null) return;
200                      if (b.redirect == null) return;
201                      if (b.redirect != b) {
202                          put(b.redirect, value);
203                          return;
204                      }
205                      if (value.equals("vertical")) {
206                          if (b.o == 1) return;
207                          b.o = 1;
208                          b.xo = 0;
209                      } else if (value.equals("horizontal")) {
210                          if (b.o == 0) return;
211                          b.o = 0;
212                          b.xo = 1;
213                      } else if (Log.on)
214                          Log.log(this, "invalid value put to orient property: " + value);
215                      b.mark_for_prerender();
216                      b.sync_cmin_to_children();
217                  } });
218  
219          specialBoxProperties.put("static", new SpecialBoxProperty() {
220                  public Object get(Box b) {
221                      String cfsn = JS.Thread.fromJavaThread(Thread.currentThread()).getCurrentCompiledFunction().getSourceName();
222                      for(int i=0; i<cfsn.length() - 1; i++)
223                          if (cfsn.charAt(i) == '.' && (cfsn.charAt(i+1) == '_' || Character.isDigit(cfsn.charAt(i+1)))) {
224                              cfsn = cfsn.substring(0, i);
225                              break;
226                          }
227                      return Static.getStatic(cfsn);
228                  }
229                  public void put(Box b, Object value) { }
230              });
231  
232          specialBoxProperties.put("sizetoimage", new SpecialBoxProperty() {
233                  public Object get(Box b) { return b.sizetoimage ? Boolean.TRUE : Boolean.FALSE; }
234                  public void put(Box b, Object value) {
235                      if (stob(value)) {
236                          if (b.sizetoimage) return;
237                          b.sizetoimage = true;
238                          b.syncSizeToImage();
239                      } else {
240                          b.sizetoimage = false;
241                      }
242                  } });
243          
244          specialBoxProperties.put("fixedaspect", new SpecialBoxProperty() {
245                  public Object get(Box b) { return b.sizetoimage ? Boolean.TRUE : Boolean.FALSE; }
246                  public void put(Box b, Object value) {
247                      boolean newval = stob(value);
248                      if (newval == b.fixedaspect) return;
249                      b.fixedaspect = newval;
250                      b.dirty();
251                  } });
252          
253          specialBoxProperties.put("shrink", new SpecialBoxProperty() {
254                  public Object get(Box b) { return (b.vshrink && b.hshrink) ? Boolean.TRUE : Boolean.FALSE; }
255                  public void put(Box b, Object value) {
256                      boolean newshrink = stob(value);
257                      if (b.hshrink == newshrink && b.vshrink == newshrink) return;
258                      b.hshrink = b.vshrink = newshrink;
259                      b.mark_for_prerender();
260                  } });
261          
262          specialBoxProperties.put("hshrink", new SpecialBoxProperty() {
263                  public Object get(Box b) { return new Boolean(b.hshrink); }
264                  public void put(Box b, Object value) {
265                      boolean newshrink = stob(value);
266                      if (b.hshrink == newshrink) return;
267                      b.hshrink = newshrink;
268                      b.mark_for_prerender();
269                  }
270              });
271          
272          specialBoxProperties.put("vshrink", new SpecialBoxProperty() {
273                  public Object get(Box b) { return b.vshrink ? Boolean.TRUE : Boolean.FALSE; }
274                  public void put(Box b, Object value) {
275                      boolean newshrink = stob(value);
276                      if (b.vshrink == newshrink) return;
277                      b.vshrink = newshrink;
278                      b.mark_for_prerender();
279                  }
280              });
281          
282          specialBoxProperties.put("x", new SpecialBoxProperty() {
283                  public Object get(Box b) {
284                      if (b.surface == null) return new Integer(0);
285                      if (b.invisible) return new Integer(0);
286                      return new Integer(b.abs(0));
287                  }
288                  public void put(Box b, Object value) {
289                      if (b.getParent() == null && b.surface != null) {
290                          b.surface.setLocation(stoi(value), b.abs(1));
291                          b.surface.centerSurfaceOnRender = false;
292                      }
293                      b.set(abs, 0, stoi(value));
294                  }
295              });
296          
297          specialBoxProperties.put("y", new SpecialBoxProperty() {
298                  public Object get(Box b) {
299                      if (b.surface == null) return new Integer(0);
300                      if (b.invisible) return new Integer(0);
301                      return new Integer(b.abs(1));
302                  }
303                  public void put(Box b, Object value) {
304                      if (b.getParent() == null && b.surface != null) {
305                          b.surface.setLocation(b.abs(0), stoi(value));
306                          b.surface.centerSurfaceOnRender = false;
307                      }
308                      b.set(abs, 1, stoi(value));
309                  }
310              });
311  
312          specialBoxProperties.put("width", new SpecialBoxProperty() {
313                  public Object get(Box b) { return new Integer(b.size(0)); }
314                  public void put(Box b, Object value) {
315                      if (b.sizetoimage) return;
316                      if (b.getParent() == null && b.surface != null) {
317                          b.set(size, 0, Box.max(Surface.scarPicture.getWidth(), stoi(value)));
318                          b.mark_for_prerender();
319                      } else {
320                          b.set(dmax, 0, stoi(value));
321                          b.set(dmin, 0, stoi(value));
322                      }
323                  } });
324          
325          specialBoxProperties.put("height", new SpecialBoxProperty() {
326                  public Object get(Box b) { return new Integer(b.size(1)); }
327                  public void put(Box b, Object value) {
328                      if (b.sizetoimage) return;
329                      if (b.getParent() == null && b.surface != null) {
330                          b.set(size, 1, Box.max(Surface.scarPicture.getHeight(), stoi(value)));
331                          b.mark_for_prerender();
332                      } else {
333                          b.set(dmax, 1, stoi(value));
334                          b.set(dmin, 1, stoi(value));
335                      }
336                  } });
337  
338          specialBoxProperties.put("flex", new SpecialBoxProperty() {
339                  public Object get(Box b) { return new Double(b.flex); }
340                  public void put(Box b, Object value) {
341                      if (value == null) return;
342                      int newflex = stoi(value);
343                      if (newflex == b.flex) return;
344                      b.flex = newflex;
345                      b.mark_for_prerender();
346                  } });
347          
348          specialBoxProperties.put("tile", new SpecialBoxProperty() {
349                  public Object get(Box b) { return b.tile ? Boolean.TRUE : Boolean.FALSE; }
350                  public void put(Box b, Object value) {
351                      boolean newtile = stob(value);
352                      if (newtile == b.tile) return;
353                      b.tile = newtile;
354                      b.dirty();
355                  } });
356          
357          specialBoxProperties.put("align", new SpecialBoxProperty() {
358                  public Object get(Box b) {
359                      if (b.align == -1) return "topleft";
360                      else if (b.align == 1) return "bottomright";
361                      else return "center";
362                  }
363                  public void put(Box b, Object value) {
364                      String s = value == null ? "" : value.toString();
365                      byte newalign = b.align;
366                      if (s.equals("topleft")) newalign = -1;
367                      else if (s.equals("bottomright")) newalign = 1;
368                      else if (s.equals("center")) newalign = 0;
369                      else if (Log.on) Log.log(this, "invalid value put to align property: " + value);
370                      if (newalign == b.align) return;
371                      b.align = newalign;
372                      if (b.getParent() != null) b.getParent().mark_for_prerender();
373                  } });
374          
375          specialBoxProperties.put("invisible", new SpecialBoxProperty() {
376                  public Object get(Box b) {
377                      for (Box cur = b; cur != null; cur = cur.getParent()) { if (cur.invisible) return Boolean.TRUE; }
378                      return Boolean.FALSE;
379                  }
380                  public void put(Box b, Object value) {
381                      boolean newinvisible = stob(value);
382                      if (newinvisible == b.invisible) return;
383                      b.invisible = newinvisible;
384                      if (b.getParent() == null) {
385                          if (b.surface != null) b.surface.setInvisible(newinvisible);
386                      } else {
387                          b.dirty();
388                          b.getParent().mark_for_prerender();
389                          b.getParent().sync_cmin_to_children();
390                          b.getParent().dirty(b.pos(0), b.pos(1), b.size(0), b.size(1));
391                          b.getParent().dirty(b.oldpos(0), b.oldpos(1), b.oldsize(0), b.oldsize(1));
392                      }
393                  }});
394          
395          specialBoxProperties.put("absolute", new SpecialBoxProperty() {
396                  public Object get(Box b) { return b.absolute ? Boolean.TRUE : Boolean.FALSE; }
397                  public void put(Box b, Object value) {
398                      boolean newabsolute = stob(value);
399                      if (newabsolute == b.absolute) return;
400                      b.absolute = newabsolute;
401                      if (b.getParent() != null) {
402                          b.getParent().mark_for_prerender();
403                          b.getParent().sync_cmin_to_children();
404                      }
405                  } });
406          
407          specialBoxProperties.put("image", new SpecialBoxProperty() {
408                  public Object get(Box b) { return b.image == null ? null : Box.imageToNameMap.get(b.image); }
409                  public void put(Box b, Object value) { b.setImage(value == null ? null : value.toString()); }
410              });
411  
412          specialBoxProperties.put("border", new SpecialBoxProperty() {
413                  public Object get(Box b) { return b.border == null ? null : Box.imageToNameMap.get(b.border); }
414                  public void put(Box b, Object value) { b.setBorder(value == null ? null : value.toString()); }
415              });
416  
417          specialBoxProperties.put("font", new SpecialBoxProperty() {
418                  public Object get(Box b) { return b.font; }
419                  public void put(Box b, Object value) {
420                      b.font = value == null ? null : value.toString();
421                      b.fontChanged();
422                      b.dirty();
423                  } });
424          
425          specialBoxProperties.put("globalx", new SpecialBoxProperty() {
426                  public Object get(Box b) { return new Integer(b.getParent() == null || b.surface == null ? 0 : b.pos(0)); }
427                  public void put(Box b, Object value) {
428                      if (b.surface == null || b.getParent() == null) return;
429                      b.put("x", new Integer(stoi(value) - stoi(get(b.getParent()))));
430                  }
431              });
432          
433          specialBoxProperties.put("globaly", new SpecialBoxProperty() {
434                  public Object get(Box b) { return new Integer(b.getParent() == null || b.surface == null ? 0 : b.pos(1)); }
435                  public void put(Box b, Object value) {
436                      if (b.surface == null || b.getParent() == null) return;
437                      b.put("y", new Integer(stoi(value) - stoi(get(b.getParent()))));
438                  }
439              });
440          
441          specialBoxProperties.put("cursor", new SpecialBoxProperty() {
442                  public Object get(Box b) { return b.cursor; } 
443                  public void put(Box b, Object value) {
444                      b.cursor = (String)value;
445                      if (b.surface == null) return;
446  
447                      // see if we need to update the surface cursor
448                      String tempcursor = b.surface.cursor;
449                      b.Move(b.surface.mousex, b.surface.mousey, b.surface.mousex, b.surface.mousey);
450                      if (b.surface.cursor != tempcursor) b.surface.syncCursor();
451                  } 
452              });
453          
454          specialBoxProperties.put("mousex", new SpecialBoxProperty() {
455                  public Object get(Box b) { return new Integer(b.surface == null ? 0 : b.surface.mousex - b.pos(0)); }
456              });
457          
458          specialBoxProperties.put("mousey", new SpecialBoxProperty() {
459                  public Object get(Box b) { return new Integer(b.surface == null ? 0 : b.surface.mousey - b.pos(1)); }
460              });
461          
462          specialBoxProperties.put("xwt", new SpecialBoxProperty() {
463                  public Object get(Box b) { return XWT.singleton; }
464              });
465          
466          specialBoxProperties.put("mouseinside", new SpecialBoxProperty() {
467                  public Object get(Box b) { return b.mouseinside ? Boolean.TRUE : Boolean.FALSE; }
468              });
469          
470          specialBoxProperties.put("numchildren", new SpecialBoxProperty() {
471                  public Object get(Box b) {
472                      if (b.redirect == null) return new Integer(0);
473                      if (b.redirect != b) return get(b.redirect);
474                      return new Integer(b.numChildren());
475                  } });
476          
477          SpecialBoxProperty mouseEventHandler = new SpecialBoxProperty() {
478                  public void put(String name, Box b, Object value) {
479                      if (b.surface == null) return;
480                      for(Box c = b.prevSibling(); c != null; c = c.prevSibling()) {
481                          Box siblingChild = c.whoIs(c.surface.mousex, c.surface.mousey);
482                          if (siblingChild != null) {
483                              siblingChild.put(name, value);
484                              return;
485                          }
486                      }
487                      if (b.getParent() != null)
488                          b.getParent().put(name, value);
489                  }};
490  
491          specialBoxProperties.put("Press1", mouseEventHandler);
492          specialBoxProperties.put("Press2", mouseEventHandler);
493          specialBoxProperties.put("Press3", mouseEventHandler);
494          specialBoxProperties.put("Release1", mouseEventHandler);
495          specialBoxProperties.put("Release2", mouseEventHandler);
496          specialBoxProperties.put("Release3", mouseEventHandler);
497          specialBoxProperties.put("Click1", mouseEventHandler);
498          specialBoxProperties.put("Click2", mouseEventHandler);
499          specialBoxProperties.put("Click3", mouseEventHandler);
500          specialBoxProperties.put("DoubleClick1", mouseEventHandler);
501          specialBoxProperties.put("DoubleClick2", mouseEventHandler);
502          specialBoxProperties.put("DoubleClick3", mouseEventHandler);
503  
504          specialBoxProperties.put("root", new SpecialBoxProperty() {
505                  public Object get(Box b) {
506                      if (b.surface == null) return null;
507                      else if (b.getRoot() == null) return null;
508                      else if (b.getParent() == null) return b;
509                      else return b.getRoot().getRootProxy();
510                  } });
511  
512          specialBoxProperties.put("Minimized", new SpecialBoxProperty() {
513                  public Object get(Box b) {
514                      if (b.getParent() == null && b.surface != null) return b.surface.minimized ? Boolean.TRUE : Boolean.FALSE;
515                      else return null;
516                  }
517                  public void put(Box b, Object value) {
518                      if (b.surface == null) return;
519                      boolean val = stob(value);
520                      if (b.getParent() == null && b.surface.minimized != val) b.surface.setMinimized(val);
521                  }
522              });
523  
524          specialBoxProperties.put("Maximized", new SpecialBoxProperty() {
525                  public Object get(Box b) {
526                      if (b.getParent() == null && b.surface != null) return b.surface.maximized ? Boolean.TRUE : Boolean.FALSE;
527                      else return null;
528                  }
529                  public void put(Box b, Object value) {
530                      if (b.surface == null) return;
531                      boolean val = stob(value);
532                      if (b.getParent() == null && b.surface.maximized != val) b.surface.setMaximized(val);
533                  }
534              });
535  
536          specialBoxProperties.put("toback", new SpecialBoxProperty() {
537                  public void put(Box b, Object value) {
538                      if (b.getParent() == null && stob(value) && b.surface != null) b.surface.toBack();
539                  }
540              });
541  
542          specialBoxProperties.put("tofront", new SpecialBoxProperty() {
543                  public void put(Box b, Object value) {
544                      if (b.getParent() == null && stob(value) && b.surface != null) b.surface.toFront();
545                  }
546              });
547  
548          specialBoxProperties.put("hscar", new SpecialBoxProperty() {
549                  public void put(Box b, Object value) {
550                      if (b.getParent() == null && b.surface != null) {
551                          b.surface.hscar = stoi(value);
552                          b.surface.dirty(0, 0, b.surface.width, b.surface.height);
553                          b.surface.Refresh();
554                      }
555                  }
556              });
557  
558          specialBoxProperties.put("vscar", new SpecialBoxProperty() {
559                  public void put(Box b, Object value) {
560                      if (b.getParent() == null && b.surface != null) {
561                          b.surface.vscar = stoi(value);
562                          b.surface.dirty(0, 0, b.surface.width, b.surface.height);
563                          b.surface.Refresh();
564                      }
565                  }
566              });
567  
568          specialBoxProperties.put("Close", new SpecialBoxProperty() {
569                  public void put(Box b, Object value) {
570                      if (b.getParent() == null && b.surface != null) b.surface.dispose(true);
571                  }
572              });
573  
574          // these are all do-nothings; just to prevent space from getting taken up in the params Hash.
575          specialBoxProperties.put("KeyPressed", new SpecialBoxProperty());
576          specialBoxProperties.put("KeyReleased", new SpecialBoxProperty());
577          specialBoxProperties.put("PosChange", new SpecialBoxProperty());
578          specialBoxProperties.put("SizeChange", new SpecialBoxProperty());
579  
580          specialBoxProperties.put("hpad", new SpecialBoxProperty() {
581                  public Object get(Box b) {
582                      if (b.redirect == null) return new Integer(0);
583                      if (b.redirect != b) return get(b.redirect);
584                      return new Integer(b.pad(0));
585                  }
586                  public void put(Box b, Object value) {
587                      if (b.redirect == null) return;
588                      if (b.redirect != b) { put(b.redirect, value); return; }
589                      int newval = stoi(value);
590                      if (newval == b.pad(0)) return;
591                      b.set(pad, 0, newval);
592                  }
593              });
594  
595          specialBoxProperties.put("vpad", new SpecialBoxProperty() {
596                  public Object get(Box b) {
597                      if (b.redirect == null) return new Integer(0);
598                      if (b.redirect != b) return get(b.redirect);
599                      return new Integer(b.pad(1));
600                  }
601                  public void put(Box b, Object value) {
602                      if (b.redirect == null) return;
603                      if (b.redirect != b) { put(b.redirect, value); return; }
604                      int newval = stoi(value);
605                      if (newval == b.pad(1)) return;
606                      b.set(pad, 1, newval);
607                  }
608              });
609  
610          specialBoxProperties.put("indexof", new SpecialBoxProperty() {
611                  public Object get(Box b) { return b.indexof(); }
612              });
613  
614          specialBoxProperties.put("minwidth", new SpecialBoxProperty() {
615                  public Object get(Box b) { return new Integer(b.dmin(0)); }
616                  public void put(Box b, Object value) {
617                      if (b.sizetoimage) return;
618                      b.set(dmin, 0, stoi(value));
619                  }
620              });
621  
622          specialBoxProperties.put("maxwidth", new SpecialBoxProperty() {
623                  public Object get(Box b) { return new Integer(b.dmax(0)); }
624                  public void put(Box b, Object value) {
625                      if (b.sizetoimage) return;
626                      b.set(dmax, 0, stoi(value));
627                  }
628              });
629  
630          specialBoxProperties.put("minheight", new SpecialBoxProperty() {
631                  public Object get(Box b) { return new Integer(b.dmin(1)); }
632                  public void put(Box b, Object value) {
633                      if (b.sizetoimage) return;
634                      b.set(dmin, 1, stoi(value));
635                  }
636              });
637  
638          specialBoxProperties.put("maxheight", new SpecialBoxProperty() {
639                  public Object get(Box b) { return new Integer(b.dmax(1)); }
640                  public void put(Box b, Object value) {
641                      if (b.sizetoimage) return;
642                      b.set(dmax, 1, stoi(value));
643                  }
644              });
645  
646          specialBoxProperties.put("redirect", new SpecialBoxProperty() {
647                  public void put(Box b, Object value) { }
648                  public Object get(Box b) {
649                      if (b.redirect == null) return null;
650                      if (b.redirect == b) return Boolean.TRUE;
651                      return get(b.redirect);
652                  }
653              });
654  
655          specialBoxProperties.put("apply", new SpecialBoxProperty() {
656                  public void put(Box b, Object value) { }
657                  public Object get(final Box b) { return new Apply(b); }
658              });
659          
660          specialBoxProperties.put("id", new SpecialBoxProperty() {
661                  public void put(Box b, Object value) { }
662                  public Object get(Box b) { return b.id; }
663              });
664      }
665  
666          
667      /** helper that converts a String to a boolean according to JavaScript coercion rules */
668      public static boolean stob(Object o) {
669          if (o == null) return false;
670          return Boolean.TRUE.equals(o) || "true".equals(o);
671      }
672  
673      /** helper that converts a String to an int according to JavaScript coercion rules */
674      public static int stoi(Object o) {
675          if (o == null) return 0;
676          if (o instanceof Integer) return ((Integer)o).intValue();
677  
678          String s;
679          if (!(o instanceof String)) s = o.toString();
680          else s = (String)o;
681  
682          try { return Integer.parseInt(s.indexOf('.') == -1 ? s : s.substring(0, s.indexOf('.'))); }
683          catch (NumberFormatException e) { return 0; }
684      }
685          
686      private static class Apply extends JS.Callable {
687          Box b;
688          public Apply(Box b) { this.b = b; }
689          public Object call(JS.Array args) throws JS.Exn {
690              if (args.elementAt(0) instanceof String) {
691                  String templatename = (String)args.elementAt(0);
692                  Template t = Template.getTemplate(templatename, null);
693                  if (t == null) {
694                      if (Log.on) Log.logJS(this, "template " + templatename + " not found");
695                  } else {
696                      if (ThreadMessage.suspendThread()) try {
697                          JS.Callable callback = args.length() < 2 ? null : (Callable)args.elementAt(1);
698                          t.apply(b, null, null, callback, 0, t.numUnits());
699                      } finally {
700                          ThreadMessage.resumeThread();
701                      }
702                  }
703                  
704              } else if (args.elementAt(0) instanceof JS && !(args.elementAt(0) instanceof Box)) {
705                  JS s = (JS)args.elementAt(0);
706                  Object[] keys = s.keys();
707                  for(int j=0; j<keys.length; j++) b.put(keys[j].toString(), s.get(keys[j]));
708              }
709              
710              return b;
711          }
712      }
713  }
714  
715          
716  
717