Merge branch 'master' of https://source.jalview.org/git/jalviewjs.git
[jalviewjs.git] / site / j2s / swingjs / plaf / JSComponentUI.java
index 39c5253..d4f6419 100644 (file)
-package swingjs.plaf;\r
-\r
-import jsjava.awt.AWTEvent;\r
-import jsjava.awt.Color;\r
-import jsjava.awt.Component;\r
-import jsjava.awt.Dimension;\r
-import jsjava.awt.Font;\r
-import jsjava.awt.FontMetrics;\r
-import jsjava.awt.Graphics;\r
-import jsjava.awt.GraphicsConfiguration;\r
-import jsjava.awt.Image;\r
-import jsjava.awt.Insets;\r
-import jsjava.awt.Point;\r
-import jsjava.awt.Rectangle;\r
-import jsjava.awt.Toolkit;\r
-import jsjava.awt.event.FocusEvent;\r
-import jsjava.awt.event.PaintEvent;\r
-import jsjava.awt.image.ColorModel;\r
-import jsjava.awt.image.ImageObserver;\r
-import jsjava.awt.image.ImageProducer;\r
-import jsjava.awt.image.VolatileImage;\r
-import jsjava.awt.peer.ContainerPeer;\r
-import jsjava.awt.peer.LightweightPeer;\r
-import jsjavax.swing.AbstractButton;\r
-import jsjavax.swing.JComponent;\r
-import jsjavax.swing.JRootPane;\r
-import jsjavax.swing.plaf.ComponentUI;\r
-import jssun.awt.CausedFocusEvent.Cause;\r
-import swingjs.JSToolkit;\r
-import swingjs.api.DOMNode;\r
-import swingjs.api.JQueryObject;\r
-\r
-/**\r
- * The JSComponentUI subclasses are where all the detailed HTML5 implementation is \r
- * carried out. These subclasses mirror the subclasses found in the actual javax.swing.plaf\r
- * but have an important difference in that that effectively act as both the UI (a single\r
- * implementation for a given AppContext in Swing) and a peer (one implementation per component).\r
- * \r
- * So here we store both the constants for the HTML5 "LookAndFeel", but also\r
- * HTML5 objects that really are on the page. \r
- * \r
- * Essentially, at least for now, we are not implementing the HTML5LookAndFeel as such. We'll see how that goes. \r
- * \r
- *  \r
- *   \r
- * @author Bob Hanson\r
- *\r
- */\r
-public abstract class JSComponentUI extends ComponentUI implements JSEventHandler {\r
-\r
-       /**\r
-        * provides a unique id for any component; set on instantiation\r
-        */\r
-       protected static int incr;  \r
-\r
-       \r
-       /**\r
-        * a unique id\r
-        */\r
-       protected String id;\r
-       \r
-       /**\r
-        * the associated JComponent; for which this is c.ui\r
-        * \r
-        */\r
-       protected JComponent c;\r
-\r
-\r
-       /**\r
-        * the outermost div holding a component -- left, top, and for a container width and height\r
-        */\r
-       protected DOMNode outerNode; \r
-\r
-       /**\r
-        * the main object for the component, possibly containing others, such as radio button with its label\r
-        */\r
-       protected DOMNode domNode;\r
-       \r
-       /**\r
-        * a component or subcomponent that can be enabled/disabled \r
-        */\r
-       protected DOMNode enableNode; \r
-       \r
-       /**\r
-        * the part of a component that can hold text\r
-        */\r
-       protected DOMNode textNode;\r
-       \r
-       /**\r
-        * the subcomponent with the value field\r
-        */\r
-       protected DOMNode valueNode;\r
-\r
-       /**\r
-        * a component that is being scrolled by a JScrollPane\r
-        */\r
-       protected DOMNode scrollNode;\r
-\r
-\r
-       /**\r
-        * a component that is focusable\r
-        */\r
-       protected DOMNode focusNode;\r
-\r
-\r
-       /**\r
-        * DOM components pre-defined (JScrollPane)\r
-        * \r
-        */\r
-       protected Component[] components;\r
-\r
-       /**\r
-        * a numerical reference for an ID\r
-        */\r
-       protected int num;\r
-       \r
-       /**\r
-        * not implemented/needed currently. Java handles this nicely \r
-        * \r
-        */\r
-       protected boolean isTainted = true;\r
-       \r
-       /**\r
-        * left and top coordinates\r
-        */\r
-       protected int x, y;\r
-       \r
-       /**\r
-        * preferred dimension set by user\r
-        * \r
-        */\r
-       protected Dimension preferredSize;\r
-       \r
-       \r
-       /**\r
-        * panels \r
-        * \r
-        */\r
-       protected boolean isContainer;\r
-       \r
-       /**\r
-        * linked nodes of this class\r
-        * \r
-        */\r
-       protected JSComponentUI parent;\r
-\r
-\r
-       String currentText;\r
-\r
-\r
-       /**\r
-        * the scroller for a text area\r
-        */\r
-       protected JSScrollPaneUI scrollerNode;\r
-\r
-\r
-       /**\r
-        * uiClassID for this component\r
-        */\r
-       protected String classID;\r
-       \r
-\r
-       private DOMNode document, body;\r
-\r
-\r
-       protected boolean needPreferred;\r
-\r
-\r
-       \r
-       public JSComponentUI() {\r
-               setDoc();\r
-       }\r
-\r
-       protected void setDoc() {\r
-               /**\r
-                * @j2sNative\r
-                * \r
-                * this.document = document;\r
-                * this.body = document.body;\r
-                */\r
-               {}\r
-       }\r
-\r
-       protected abstract void installJSUI();\r
-       protected abstract void uninstallJSUI();\r
-       \r
-       public void installUI(JComponent c) {\r
-               // already done installJSUI();\r
-       }\r
-\r
-       public void uninstallUI(JComponent c) {\r
-               uninstallJSUI();\r
-       }\r
-\r
-       protected JQueryObject $(DOMNode node) {\r
-               return JSToolkit.getJQuery().$(node);\r
-       }\r
-       \r
-       /**\r
-        * mark this component as in need of update; \r
-        * maybe not necessary, though. It comes after the value  callback \r
-        */\r
-  public void setTainted() {\r
-       isTainted = true;\r
-  }\r
-  \r
-  public abstract DOMNode getDOMObject();\r
-\r
-       public JSComponentUI set(JComponent target) {\r
-               c = target;\r
-               newID();\r
-               if (needPreferred)\r
-                       getPreferredSize(c);\r
-               installJSUI(); // need to do this immediately, not later\r
-               return this;\r
-       }\r
-\r
-       protected void newID() {\r
-               classID = c.getUIClassID();\r
-               if (id == null) {\r
-                       num = ++incr;\r
-                       id = c.getHTMLName(classID) + "_" + num;\r
-               }\r
-       }\r
-\r
-       protected DOMNode setCssFont(DOMNode obj, Font font) {\r
-               if (font != null) {\r
-                       int istyle = font.getStyle();\r
-                       String name = font.getFamily();\r
-                       if (name == "Dialog")\r
-                               name = "Arial";\r
-                       DOMNode.setStyles(obj, "font-family", name, "font-size",\r
-                                       font.getSize() + "px", "font-style",\r
-                                       ((istyle & Font.ITALIC) == 0 ? "normal" : "italic"), "font-weight",\r
-                                       ((istyle & Font.BOLD) == 0 ? "normal" : "bold"));\r
-               }\r
-               if (c.isBackgroundSet())\r
-                       setBackground(c.getBackground());\r
-    setForeground(c.getForeground());\r
-               return obj;\r
-       }\r
-\r
-       protected DOMNode createDOMObject(String key, String id, String... attr) {\r
-               DOMNode obj = DOMNode.createElement(key, id);\r
-               for (int i = 0; i < attr.length;)\r
-                       DOMNode.setAttr(obj, attr[i++], attr[i++]);\r
-               if (!c.isEnabled())\r
-                       setEnabled(false);\r
-               return obj;\r
-       }\r
-\r
-       /**\r
-        * JSmolCore.js will look for  data-UI attribute  and, if found, reroute directly here \r
-        * @param node \r
-        */\r
-       protected void bindMouse(DOMNode node) {\r
-               DOMNode.setAttr(node, "data-UI", this);         \r
-       }\r
-       \r
-       /**\r
-        * called by JmolCore.js\r
-        * @return true if handled\r
-        */\r
-       public boolean handleJSEvent(Object target, int eventType, Object jQueryEvent) {\r
-               //System.out.println(id + " handling event " + eventType + jQueryEvent);\r
-               return false;\r
-       }\r
-\r
-       protected DOMNode wrap(String type, String id, DOMNode... elements) {\r
-               return append(createDOMObject(type, id + type), elements);\r
-       }\r
-\r
-       protected DOMNode append(DOMNode obj, DOMNode[] elements) {\r
-               for (int i = 0; i < elements.length; i++) {\r
-                       obj.appendChild(elements[i]);\r
-               }\r
-               return obj;\r
-       }\r
-\r
-       protected void debugDump(DOMNode d) {\r
-               System.out.println(DOMNode.getAttr(d, "outerHTML"));\r
-       }\r
-       \r
-       protected static void vCenter(DOMNode obj, int offset) {\r
-               DOMNode.setStyles(obj, \r
-                               "top", "50%", \r
-                               "transform","translateY(" + offset + "%)");\r
-       }\r
-       \r
-       /**\r
-        * overloaded to allow panel and radiobutton to handle slightly differently \r
-        * \r
-        * @param obj\r
-        * @param addCSS\r
-        * @return\r
-        */\r
-       protected Dimension setHTMLSize(DOMNode obj, boolean addCSS) {\r
-               return setHTMLSize1(obj, addCSS, true);\r
-       }\r
-\r
-       /**\r
-        * also called by JSRadioButtonUI so that it can calculate\r
-        * subset dimensions\r
-        *  \r
-        * @param node\r
-        * @param addCSS\r
-        * @param usePreferred\r
-        * @return\r
-        */\r
-       @SuppressWarnings("unused")\r
-       protected Dimension setHTMLSize1(DOMNode node, boolean addCSS, boolean usePreferred) {\r
-               if (node == null)\r
-                       return null;\r
-               int h, w;\r
-               String w0 = null, h0 = null;\r
-               DOMNode parentNode = null;\r
-\r
-               if (scrollerNode != null) {\r
-                       w = scrollerNode.c.getWidth();\r
-                       h = scrollerNode.c.getHeight();\r
-               } else if (usePreferred && preferredSize != null) {\r
-                       // user has set preferred size\r
-                       w = preferredSize.width;\r
-                       h = preferredSize.height;\r
-               } else {\r
-      // determine the natural size of this object\r
-                       // save the parent node -- we will need to reset that.\r
-                       parentNode = DOMNode.remove(node);\r
-\r
-                       // remove position, width, and height, because those are what we are\r
-                       // setting here\r
-                       /**\r
-                        * @j2sNative\r
-                        * \r
-                        * w0 = node.style.width;\r
-                        * h0 = node.style.height;\r
-                        */\r
-                       {}\r
-                       DOMNode.setStyles(node, "position", null, "width", null, "height", null);\r
-                       DOMNode div;\r
-                       if (DOMNode.getAttr(node, "tagName") == "DIV")\r
-                               div = node;\r
-                       else\r
-                               div = wrap("div", id + "_temp", node);\r
-                       DOMNode.setStyles(div, "position", "absolute");\r
-\r
-                       // process of discovering width and height is facilitated using jQuery\r
-                       // and appending to document.body.\r
-\r
-                       body.appendChild(div);\r
-                       \r
-                       //System.out.println(DOMNode.getAttr(node, "outerHTML"));\r
-                       w = (int) Math.ceil($(div).width() + 0.5);\r
-                       h = (int) Math.ceil($(div).height() + 0.5);\r
-                       body.removeChild(div);\r
-               }\r
-\r
-               Dimension size = getCSSDimension(w, h);\r
-               if (addCSS) {\r
-                       DOMNode.setStyles(node, "position", "absolute");\r
-                       DOMNode.setSize(node, size.width, size.height);\r
-               } else {\r
-                       DOMNode.setStyles(node, "position", null);\r
-                       // check to reset width/height after getPreferredSize\r
-                       if (w0 != null)\r
-                               DOMNode.setStyles(node, "width", w0, "height", h0);\r
-               }\r
-               if (parentNode != null)\r
-                       parentNode.appendChild(node);\r
-               //System.out.println("JSComponentUI " + id + " resized to " + w + "x" + h + " parent=" + DOMNode.getAttr(parentNode,"id"));     \r
-               return size;\r
-       }\r
-\r
-       /**\r
-        * can be overloaded to allow some special adjustments\r
-        * \r
-        * @param w\r
-        * @param h\r
-        * @return\r
-        */\r
-       protected Dimension getCSSDimension(int w, int h) {\r
-               return new Dimension(w, h);\r
-       }\r
-\r
-       /**\r
-        * creates the DOM node and inserts it into the tree at the correct place,\r
-        * iterating through all children if this is a container\r
-        * \r
-        * @return\r
-        * \r
-        */\r
-       protected DOMNode setHTMLElement() {\r
-               if (!isTainted)\r
-                       return outerNode;\r
-\r
-               // check for root pane -- not included in DOM\r
-               JRootPane root = (isContainer ? c.getRootPane() : null);\r
-               if (c == root) {\r
-                       isTainted = false;\r
-                       return outerNode;\r
-               }\r
-\r
-               domNode = getDOMObject();\r
-\r
-               // divObj will need recreating if a propertyChange event has occurred\r
-               // check for content pane -- needs to be added to the HTML5 content layer\r
-               // div\r
-\r
-               // needs some work for changes after applet creation\r
-\r
-               if (outerNode == null) {\r
-                       outerNode = wrap("div", id, domNode);\r
-                       if (root != null && root.getContentPane() == c)\r
-                               swingjs.JSToolkit.getHTML5Applet(c)._getContentLayer()\r
-                                               .appendChild(outerNode);\r
-               }\r
-\r
-               // set position\r
-\r
-               DOMNode.setStyles(outerNode, "position", "absolute", "left", (x = c.getX())\r
-                               + "px", "top", (y = c.getY()) + "px");\r
-\r
-               if (isContainer) {\r
-\r
-                       // set width from component\r
-\r
-                       System.out.println("JSComponentUI container " + id + " " + c.getBounds());\r
-                       DOMNode.setSize(outerNode, c.getWidth(), c.getHeight());\r
-\r
-                       // add all children\r
-                       Component[] children = (components == null ? c.getComponents()\r
-                                       : components);\r
-                       for (int i = children.length; --i >= 0;) {\r
-                               JSComponentUI ui = JSToolkit.getUI(children[i], false);\r
-                               if (ui == null) {\r
-                                       // Box.Filler has no ui.\r
-                                       continue;\r
-                               }\r
-                               if (ui.outerNode == null)\r
-                                       ui.setHTMLElement();\r
-                               if (ui.outerNode == null) {\r
-                                       System.out.println("JSCUI could not add " + ui.c.getName() + " to "\r
-                                                       + c.getName());\r
-                               } else {\r
-                                       outerNode.appendChild(ui.outerNode);\r
-                               }\r
-                               ui.parent = this;\r
-                       }\r
-               }\r
-\r
-               // mark as not tainted\r
-               // debugDump(divObj);\r
-               isTainted = false;\r
-               return outerNode;\r
-       }\r
-\r
-       /**\r
-        * c ignored because JSComponentUI is one per component\r
-        */\r
-       public Dimension getPreferredSize(JComponent c) {\r
-               //System.out.println("getPreferredSize for " + id + " " + c.getName());\r
-               Dimension d = setHTMLSize(getDOMObject(), false);\r
-               //System.out.println("JSComponentUI " + id + " getting preferred size as " + d);\r
-       return d;\r
-  }\r
-\r
-       public void paint(Graphics g, JComponent c) {\r
-    // Note that for now, button graphics \r
-               // are BEHIND the button. We will need to paint onto the\r
-               // glass pane for this to work, and then also manage\r
-               // mouse clicks and key clicks with that in mind. \r
-               if (c.isOpaque()) {\r
-                       g.setColor(c.getBackground());\r
-                       g.fillRect(0, 0, c.getWidth(), c.getHeight());\r
-               }\r
-       }\r
-\r
-       public void update(Graphics g, JComponent c) {\r
-               // called from JComponent.paintComponent\r
-               boolean testing = false;//true;\r
-               if (testing) {\r
-                       g.setColor(Color.red);\r
-                       g.drawRect(0, 0, c.getWidth(), c.getHeight());\r
-                       System.out.println("drawing " + c.getWidth() + " " + c.getHeight());\r
-               }\r
-               setHTMLElement();\r
-               paint(g, c);\r
-       }\r
-\r
-       public Dimension getMinimumSize(JComponent c) {\r
-               return getPreferredSize(c);\r
-       }\r
-\r
-       public Dimension getMaximumSize(JComponent c) {\r
-               return null;// getPreferredSize(c);\r
-       }\r
-\r
-  /**\r
-   * Returns <code>true</code> if the specified <i>x,y</i> location is\r
-   * contained within the look and feel's defined shape of the specified\r
-   * component. <code>x</code> and <code>y</code> are defined to be relative\r
-   * to the coordinate system of the specified component.  Although\r
-   * a component's <code>bounds</code> is constrained to a rectangle,\r
-   * this method provides the means for defining a non-rectangular\r
-   * shape within those bounds for the purpose of hit detection.\r
-   *\r
-   * @param c the component where the <i>x,y</i> location is being queried;\r
-   *          this argument is often ignored,\r
-   *          but might be used if the UI object is stateless\r
-   *          and shared by multiple components\r
-   * @param x the <i>x</i> coordinate of the point\r
-   * @param y the <i>y</i> coordinate of the point\r
-   *\r
-   * @see jsjavax.swing.JComponent#contains\r
-   * @see jsjava.awt.Component#contains\r
-   */\r
-  public boolean contains(JComponent c, int x, int y) {\r
-      return c.inside(x, y);\r
-  }\r
-\r
-  /**\r
-   * Returns an instance of the UI delegate for the specified component.\r
-   * Each subclass must provide its own static <code>createUI</code>\r
-   * method that returns an instance of that UI delegate subclass.\r
-   * If the UI delegate subclass is stateless, it may return an instance\r
-   * that is shared by multiple components.  If the UI delegate is\r
-   * stateful, then it should return a new instance per component.\r
-   * The default implementation of this method throws an error, as it\r
-   * should never be invoked.\r
-   */\r
-  public static ComponentUI createUI(JComponent c) {\r
-       // SwingJS  so, actually, we don't do this. This class is NOT stateless.\r
-       // Instead, what we do is to create a unique instance \r
-       // right in UIManager. The sequence is:\r
-       // JRadioButton.updateUI() \r
-       // --> jsjavax.swing.UIManager.getUI(this)\r
-       // --> jsjavax.swing.UIManager.getDefaults().getUI(target) \r
-       // --> JSToolkit.getComponentUI(target)\r
-       // --> creates an instance of JRadioButtonUI and returns\r
-       // that instance as JRadioButton.ui, which is NOT static.\r
-       // \r
-//      throw new Error("ComponentUI.createUI not implemented.");\r
-       return null;\r
-  }\r
-\r
-  /**\r
-   * Returns the baseline.  The baseline is measured from the top of\r
-   * the component.  This method is primarily meant for\r
-   * <code>LayoutManager</code>s to align components along their\r
-   * baseline.  A return value less than 0 indicates this component\r
-   * does not have a reasonable baseline and that\r
-   * <code>LayoutManager</code>s should not align this component on\r
-   * its baseline.\r
-   * <p>\r
-   * This method returns -1.  Subclasses that have a meaningful baseline\r
-   * should override appropriately.\r
-   *\r
-   * @param c <code>JComponent</code> baseline is being requested for\r
-   * @param width the width to get the baseline for\r
-   * @param height the height to get the baseline for\r
-   * @throws NullPointerException if <code>c</code> is <code>null</code>\r
-   * @throws IllegalArgumentException if width or height is &lt; 0\r
-   * @return baseline or a value &lt; 0 indicating there is no reasonable\r
-   *                  baseline\r
-   * @see jsjavax.swing.JComponent#getBaseline(int,int)\r
-   * @since 1.6\r
-   */\r
-  public int getBaseline(JComponent c, int width, int height) {\r
-      if (c == null) {\r
-          throw new NullPointerException("Component must be non-null");\r
-      }\r
-      if (width < 0 || height < 0) {\r
-          throw new IllegalArgumentException(\r
-                  "Width and height must be >= 0");\r
-      }\r
-      return -1;\r
-  }\r
-\r
-  /**\r
-   * Returns an enum indicating how the baseline of he component\r
-   * changes as the size changes.  This method is primarily meant for\r
-   * layout managers and GUI builders.\r
-   * <p>\r
-   * This method returns <code>BaselineResizeBehavior.OTHER</code>.\r
-   * Subclasses that support a baseline should override appropriately.\r
-   *\r
-   * @param c <code>JComponent</code> to return baseline resize behavior for\r
-   * @return an enum indicating how the baseline changes as the component\r
-   *         size changes\r
-   * @throws NullPointerException if <code>c</code> is <code>null</code>\r
-   * @see jsjavax.swing.JComponent#getBaseline(int, int)\r
-   * @since 1.6\r
-   */\r
-  public Component.BaselineResizeBehavior getBaselineResizeBehavior(\r
-          JComponent c) {\r
-      if (c == null) {\r
-          throw new NullPointerException("Component must be non-null");\r
-      }\r
-      return Component.BaselineResizeBehavior.OTHER;\r
-  }\r
-\r
-  /**\r
-   * overridden in JSPasswordFieldUI\r
-   * @return texat\r
-   */\r
-  public String getJSTextValue() {\r
-       return (String) DOMNode.getAttr(domNode, valueNode == null ? "innerHTML" : "value");\r
-  }\r
-  \r
-       public void notifyPropertyChanged(String prop) {\r
-               DOMNode obj = null;\r
-               String val = null;\r
-               if (prop == "text") {\r
-                       val = ((AbstractButton) c).getText();\r
-                       if (val.equals(currentText)) // we set it here, then fired the property change\r
-                               return;\r
-                       currentText = val;\r
-                       if (textNode != null) {\r
-                               prop = "innerHTML";\r
-                               obj = textNode;\r
-                       } else if (valueNode != null) {\r
-                               prop = "value";\r
-                               obj = valueNode;\r
-                       }\r
-               } else if (prop == "preferredSize") {\r
-                       preferredSize = c.getPreferredSize(); // may be null\r
-                       getPreferredSize();\r
-                       return;\r
-               }\r
-               if (obj == null) {\r
-                       System.out.println("JSComponentUI: unrecognized prop: " + prop);\r
-               } else {\r
-                       System.out.println("JSComponentUI: setting " + id + " " + prop);// + " " + val);\r
-                       setProp(obj, prop, val);\r
-               }\r
-       }\r
-\r
-       protected DOMNode setProp(DOMNode obj, String prop, String val) {\r
-               return DOMNode.setAttr(obj, prop, val);\r
-       }\r
-\r
-       @Override\r
-       public boolean isObscured() {\r
-               JSToolkit.notImplemented("");\r
-               return false;\r
-       }\r
-\r
-       @Override\r
-       public boolean canDetermineObscurity() {\r
-               JSToolkit.notImplemented("");\r
-               return false;\r
-       }\r
-\r
-       @Override\r
-       public void setVisible(boolean b) {\r
-               DOMNode.setStyles(outerNode, "display", b ? "block" : "none");\r
-       }\r
-\r
-       @Override\r
-       public void setEnabled(boolean b) {     \r
-               if (enableNode != null)\r
-                 DOMNode.setAttr(enableNode, "disabled", (b ? null : "TRUE"));\r
-       }\r
-\r
-       @Override\r
-       public void paint(Graphics g) {\r
-               // nothing to do here\r
-       }\r
-\r
-       @Override\r
-       public void repaint(long tm, int x, int y, int width, int height) {\r
-               // nothing to do here\r
-       }\r
-\r
-       @Override\r
-       public void print(Graphics g) {\r
-               JSToolkit.notImplemented("");           \r
-       }\r
-\r
-       @Override\r
-       public void setBounds(int x, int y, int width, int height, int op) {\r
-               switch (op) {\r
-               case SET_SIZE:\r
-               case SET_BOUNDS:\r
-               case SET_CLIENT_SIZE:\r
-                       if (scrollerNode != null) {\r
-                               width = Math.min(width, scrollerNode.c.getWidth());\r
-                               height = Math.min(height, scrollerNode.c.getHeight());                  \r
-                       }\r
-                       System.out.println(id + " setBounds " + x + " " + y + " " + width + " " + height + " op=" + op);\r
-                       if (domNode != null)\r
-                               DOMNode.setSize(domNode, width, height);\r
-                       break;\r
-               }\r
-       }\r
-\r
-       @Override\r
-       public void handleEvent(AWTEvent e) {\r
-               JSToolkit.notImplemented("");\r
-               \r
-       }\r
-\r
-       @Override\r
-       public void coalescePaintEvent(PaintEvent e) {\r
-               JSToolkit.notImplemented("");\r
-               \r
-       }\r
-\r
-       /**\r
-        * Coordinates relative to the document\r
-        * \r
-        */\r
-       @Override\r
-       public Point getLocationOnScreen() {\r
-               Insets offset = (Insets) $(outerNode).offset();\r
-               return new Point(offset.left, offset.top);\r
-       }\r
-\r
-       @Override\r
-       public Dimension getPreferredSize() {\r
-               return getPreferredSize(c);\r
-       }\r
-\r
-       @Override\r
-       public Dimension getMinimumSize() {\r
-               JSToolkit.notImplemented("");\r
-               return getPreferredSize(c);\r
-       }\r
-\r
-       @Override\r
-       public ColorModel getColorModel() {\r
-               return Toolkit.getDefaultToolkit().getColorModel();\r
-       }\r
-\r
-       @Override\r
-       public Toolkit getToolkit() {\r
-               return Toolkit.getDefaultToolkit();\r
-       }\r
-\r
-       @Override\r
-       public Graphics getGraphics() {\r
-               // n/a  -- called from java.awt.Component when NOT a LightweightPeer.\r
-               return null;\r
-       }\r
-\r
-       @Override\r
-       public FontMetrics getFontMetrics(Font font) {\r
-               return c.getFontMetrics(font);\r
-       }\r
-\r
-       @Override\r
-       public void dispose() {\r
-               JSToolkit.notImplemented("");\r
-       }\r
-\r
-       @Override\r
-       public void setForeground(Color color) {\r
-               if (domNode != null)\r
-                       DOMNode.setStyles(domNode, "color", JSToolkit.getCSSColor(color == null ? Color.black : color));\r
-       }\r
-\r
-       @Override\r
-       public void setBackground(Color color) {\r
-               if (domNode != null)\r
-                       DOMNode.setStyles(domNode, "background-color", JSToolkit.getCSSColor(color == null ? Color.white : color));\r
-       }\r
-\r
-       @Override\r
-       public void setFont(Font f) {\r
-               if (domNode != null)\r
-                       setCssFont(domNode, f);\r
-       }\r
-\r
-       @Override\r
-       public void updateCursorImmediately() {\r
-               JSToolkit.notImplemented("");           \r
-       }\r
-\r
-       @Override\r
-       public boolean requestFocus(Component lightweightChild, boolean temporary,\r
-                       boolean focusedWindowChangeAllowed, long time, Cause cause) {\r
-               if (focusNode == null)\r
-                       return false;\r
-               $(focusNode).focus();\r
-               if (textNode != null)\r
-                       $(textNode).select();\r
-               return true;\r
-       }\r
-\r
-       @Override\r
-       public boolean isFocusable() {\r
-               return (focusNode != null);\r
-       }\r
-\r
-       @Override\r
-       public Image createImage(ImageProducer producer) {\r
-               JSToolkit.notImplemented("");\r
-               return null;\r
-       }\r
-\r
-       @Override\r
-       public Image createImage(int width, int height) {\r
-               JSToolkit.notImplemented("");\r
-               return null;\r
-       }\r
-\r
-       @Override\r
-       public VolatileImage createVolatileImage(int width, int height) {\r
-               JSToolkit.notImplemented("");\r
-               return null;\r
-       }\r
-\r
-       @Override\r
-       public boolean prepareImage(Image img, int w, int h, ImageObserver o) {\r
-               JSToolkit.notImplemented("");\r
-               return false;\r
-       }\r
-\r
-       @Override\r
-       public int checkImage(Image img, int w, int h, ImageObserver o) {\r
-               JSToolkit.notImplemented("");\r
-               return 0;\r
-       }\r
-\r
-       @Override\r
-       public GraphicsConfiguration getGraphicsConfiguration() {\r
-               JSToolkit.notImplemented("");\r
-               return null;\r
-       }\r
-\r
-       @Override\r
-       public boolean handlesWheelScrolling() {\r
-               JSToolkit.notImplemented("");\r
-               return false;\r
-       }\r
-\r
-       @Override\r
-       public Image getBackBuffer() {\r
-               JSToolkit.notImplemented("");\r
-               return null;\r
-       }\r
-\r
-       @Override\r
-       public void destroyBuffers() {\r
-               JSToolkit.notImplemented("");\r
-               \r
-       }\r
-\r
-       @Override\r
-       public void reparent(ContainerPeer newContainer) {\r
-               JSToolkit.notImplemented("");\r
-               \r
-       }\r
-\r
-       @Override\r
-       public boolean isReparentSupported() {\r
-               JSToolkit.notImplemented("");\r
-               return false;\r
-       }\r
-\r
-       @Override\r
-       public void layout() {\r
-               JSToolkit.notImplemented("");\r
-               \r
-       }\r
-\r
-       @Override\r
-       public Rectangle getBounds() {\r
-               JSToolkit.notImplemented("");\r
-               return null;\r
-       }\r
-\r
-       public boolean hasFocus() {\r
-               return focusNode != null && focusNode == DOMNode.getAttr(document, "activeElement");\r
-       }\r
-\r
-       public void notifyFocus(boolean focusGained) {\r
-               Toolkit.getEventQueue().postEvent(new FocusEvent(c, focusGained ? FocusEvent.FOCUS_GAINED : FocusEvent.FOCUS_LOST));\r
-       }\r
-}\r
+package swingjs.plaf;
+
+import jsjava.awt.AWTEvent;
+import jsjava.awt.Color;
+import jsjava.awt.Component;
+import jsjava.awt.Dimension;
+import jsjava.awt.Font;
+import jsjava.awt.FontMetrics;
+import jsjava.awt.Graphics;
+import jsjava.awt.GraphicsConfiguration;
+import jsjava.awt.Image;
+import jsjava.awt.Insets;
+import jsjava.awt.Point;
+import jsjava.awt.Rectangle;
+import jsjava.awt.Toolkit;
+import jsjava.awt.event.FocusEvent;
+import jsjava.awt.event.PaintEvent;
+import jsjava.awt.image.ColorModel;
+import jsjava.awt.image.ImageObserver;
+import jsjava.awt.image.ImageProducer;
+import jsjava.awt.image.VolatileImage;
+import jsjava.awt.peer.ContainerPeer;
+import jsjava.awt.peer.LightweightPeer;
+import jsjavax.swing.AbstractButton;
+import jsjavax.swing.JComponent;
+import jsjavax.swing.JRootPane;
+import jsjavax.swing.plaf.ComponentUI;
+import jssun.awt.CausedFocusEvent.Cause;
+import swingjs.JSToolkit;
+import swingjs.api.DOMNode;
+import swingjs.api.JQueryObject;
+
+/**
+ * The JSComponentUI subclasses are where all the detailed HTML5 implementation is 
+ * carried out. These subclasses mirror the subclasses found in the actual javax.swing.plaf
+ * but have an important difference in that that effectively act as both the UI (a single
+ * implementation for a given AppContext in Swing) and a peer (one implementation per component).
+ * 
+ * So here we store both the constants for the HTML5 "LookAndFeel", but also
+ * HTML5 objects that really are on the page. 
+ * 
+ * Essentially, at least for now, we are not implementing the HTML5LookAndFeel as such. We'll see how that goes. 
+ * 
+ *  
+ *   
+ * @author Bob Hanson
+ *
+ */
+public abstract class JSComponentUI extends ComponentUI implements JSEventHandler {
+
+       /**
+        * provides a unique id for any component; set on instantiation
+        */
+       protected static int incr;  
+
+       
+       /**
+        * a unique id
+        */
+       protected String id;
+       
+       /**
+        * the associated JComponent; for which this is c.ui
+        * 
+        */
+       protected JComponent c;
+
+
+       /**
+        * the outermost div holding a component -- left, top, and for a container width and height
+        */
+       protected DOMNode outerNode; 
+
+       /**
+        * the main object for the component, possibly containing others, such as radio button with its label
+        */
+       protected DOMNode domNode;
+       
+       /**
+        * a component or subcomponent that can be enabled/disabled 
+        */
+       protected DOMNode enableNode; 
+       
+       /**
+        * the part of a component that can hold text
+        */
+       protected DOMNode textNode;
+       
+       /**
+        * the subcomponent with the value field
+        */
+       protected DOMNode valueNode;
+
+       /**
+        * a component that is being scrolled by a JScrollPane
+        */
+       protected DOMNode scrollNode;
+
+
+       /**
+        * a component that is focusable
+        */
+       protected DOMNode focusNode;
+
+
+       /**
+        * DOM components pre-defined (JScrollPane)
+        * 
+        */
+       protected Component[] components;
+
+       /**
+        * a numerical reference for an ID
+        */
+       protected int num;
+       
+       /**
+        * not implemented/needed currently. Java handles this nicely 
+        * 
+        */
+       protected boolean isTainted = true;
+       
+       /**
+        * left and top coordinates
+        */
+       protected int x, y;
+       
+       /**
+        * preferred dimension set by user
+        * 
+        */
+       protected Dimension preferredSize;
+       
+       
+       /**
+        * panels 
+        * 
+        */
+       protected boolean isContainer;
+       
+       /**
+        * linked nodes of this class
+        * 
+        */
+       protected JSComponentUI parent;
+
+
+       String currentText;
+
+
+       /**
+        * the scroller for a text area
+        */
+       protected JSScrollPaneUI scrollerNode;
+
+
+       /**
+        * uiClassID for this component
+        */
+       protected String classID;
+       
+
+       private DOMNode document, body;
+
+
+       protected boolean needPreferred;
+
+
+       
+       public JSComponentUI() {
+               setDoc();
+       }
+
+       protected void setDoc() {
+               /**
+                * @j2sNative
+                * 
+                * this.document = document;
+                * this.body = document.body;
+                */
+               {}
+       }
+
+       protected abstract void installJSUI();
+       protected abstract void uninstallJSUI();
+       
+       public void installUI(JComponent c) {
+               // already done installJSUI();
+       }
+
+       public void uninstallUI(JComponent c) {
+               uninstallJSUI();
+       }
+
+       protected JQueryObject $(DOMNode node) {
+               return JSToolkit.getJQuery().$(node);
+       }
+       
+       /**
+        * mark this component as in need of update; 
+        * maybe not necessary, though. It comes after the value  callback 
+        */
+  public void setTainted() {
+       isTainted = true;
+  }
+  
+  public abstract DOMNode getDOMObject();
+
+       public JSComponentUI set(JComponent target) {
+               c = target;
+               newID();
+               if (needPreferred)
+                       getPreferredSize(c);
+               installJSUI(); // need to do this immediately, not later
+               return this;
+       }
+
+       protected void newID() {
+               classID = c.getUIClassID();
+               if (id == null) {
+                       num = ++incr;
+                       id = c.getHTMLName(classID) + "_" + num;
+               }
+       }
+
+       protected DOMNode setCssFont(DOMNode obj, Font font) {
+               if (font != null) {
+                       int istyle = font.getStyle();
+                       String name = font.getFamily();
+                       if (name == "Dialog")
+                               name = "Arial";
+                       DOMNode.setStyles(obj, "font-family", name, "font-size",
+                                       font.getSize() + "px", "font-style",
+                                       ((istyle & Font.ITALIC) == 0 ? "normal" : "italic"), "font-weight",
+                                       ((istyle & Font.BOLD) == 0 ? "normal" : "bold"));
+               }
+               if (c.isBackgroundSet())
+                       setBackground(c.getBackground());
+    setForeground(c.getForeground());
+               return obj;
+       }
+
+       protected DOMNode createDOMObject(String key, String id, String... attr) {
+               DOMNode obj = DOMNode.createElement(key, id);
+               for (int i = 0; i < attr.length;)
+                       DOMNode.setAttr(obj, attr[i++], attr[i++]);
+               if (!c.isEnabled())
+                       setEnabled(false);
+               return obj;
+       }
+
+       /**
+        * JSmolCore.js will look for  data-UI attribute  and, if found, reroute directly here 
+        * @param node 
+        */
+       protected void bindMouse(DOMNode node) {
+               DOMNode.setAttr(node, "data-UI", this);         
+       }
+       
+       /**
+        * called by JmolCore.js
+        * @return true if handled
+        */
+       public boolean handleJSEvent(Object target, int eventType, Object jQueryEvent) {
+               //System.out.println(id + " handling event " + eventType + jQueryEvent);
+               return false;
+       }
+
+       protected DOMNode wrap(String type, String id, DOMNode... elements) {
+               return append(createDOMObject(type, id + type), elements);
+       }
+
+       protected DOMNode append(DOMNode obj, DOMNode[] elements) {
+               for (int i = 0; i < elements.length; i++) {
+                       obj.appendChild(elements[i]);
+               }
+               return obj;
+       }
+
+       protected void debugDump(DOMNode d) {
+               System.out.println(DOMNode.getAttr(d, "outerHTML"));
+       }
+       
+       protected static void vCenter(DOMNode obj, int offset) {
+               DOMNode.setStyles(obj, 
+                               "top", "50%", 
+                               "transform","translateY(" + offset + "%)");
+       }
+       
+       /**
+        * overloaded to allow panel and radiobutton to handle slightly differently 
+        * 
+        * @param obj
+        * @param addCSS
+        * @return
+        */
+       protected Dimension setHTMLSize(DOMNode obj, boolean addCSS) {
+               return setHTMLSize1(obj, addCSS, true);
+       }
+
+       /**
+        * also called by JSRadioButtonUI so that it can calculate
+        * subset dimensions
+        *  
+        * @param node
+        * @param addCSS
+        * @param usePreferred
+        * @return
+        */
+       @SuppressWarnings("unused")
+       protected Dimension setHTMLSize1(DOMNode node, boolean addCSS, boolean usePreferred) {
+               if (node == null)
+                       return null;
+               int h, w;
+               String w0 = null, h0 = null;
+               DOMNode parentNode = null;
+
+               if (scrollerNode != null) {
+                       w = scrollerNode.c.getWidth();
+                       h = scrollerNode.c.getHeight();
+               } else if (usePreferred && preferredSize != null) {
+                       // user has set preferred size
+                       w = preferredSize.width;
+                       h = preferredSize.height;
+               } else {
+      // determine the natural size of this object
+                       // save the parent node -- we will need to reset that.
+                       parentNode = DOMNode.remove(node);
+
+                       // remove position, width, and height, because those are what we are
+                       // setting here
+                       /**
+                        * @j2sNative
+                        * 
+                        * w0 = node.style.width;
+                        * h0 = node.style.height;
+                        */
+                       {}
+                       DOMNode.setStyles(node, "position", null, "width", null, "height", null);
+                       DOMNode div;
+                       if (DOMNode.getAttr(node, "tagName") == "DIV")
+                               div = node;
+                       else
+                               div = wrap("div", id + "_temp", node);
+                       DOMNode.setStyles(div, "position", "absolute");
+
+                       // process of discovering width and height is facilitated using jQuery
+                       // and appending to document.body.
+
+                       body.appendChild(div);
+                       
+                       //System.out.println(DOMNode.getAttr(node, "outerHTML"));
+                       w = (int) Math.ceil($(div).width() + 0.5);
+                       h = (int) Math.ceil($(div).height() + 0.5);
+                       body.removeChild(div);
+               }
+
+               Dimension size = getCSSDimension(w, h);
+               if (addCSS) {
+                       DOMNode.setStyles(node, "position", "absolute");
+                       DOMNode.setSize(node, size.width, size.height);
+               } else {
+                       DOMNode.setStyles(node, "position", null);
+                       // check to reset width/height after getPreferredSize
+                       if (w0 != null)
+                               DOMNode.setStyles(node, "width", w0, "height", h0);
+               }
+               if (parentNode != null)
+                       parentNode.appendChild(node);
+               //System.out.println("JSComponentUI " + id + " resized to " + w + "x" + h + " parent=" + DOMNode.getAttr(parentNode,"id"));     
+               return size;
+       }
+
+       /**
+        * can be overloaded to allow some special adjustments
+        * 
+        * @param w
+        * @param h
+        * @return
+        */
+       protected Dimension getCSSDimension(int w, int h) {
+               return new Dimension(w, h);
+       }
+
+       /**
+        * creates the DOM node and inserts it into the tree at the correct place,
+        * iterating through all children if this is a container
+        * 
+        * @return
+        * 
+        */
+       protected DOMNode setHTMLElement() {
+               if (!isTainted)
+                       return outerNode;
+
+               // check for root pane -- not included in DOM
+               JRootPane root = (isContainer ? c.getRootPane() : null);
+               if (c == root) {
+                       isTainted = false;
+                       return outerNode;
+               }
+
+               domNode = getDOMObject();
+
+               // divObj will need recreating if a propertyChange event has occurred
+               // check for content pane -- needs to be added to the HTML5 content layer
+               // div
+
+               // needs some work for changes after applet creation
+
+               if (outerNode == null) {
+                       outerNode = wrap("div", id, domNode);
+                       if (root != null && root.getContentPane() == c)
+                               swingjs.JSToolkit.getHTML5Applet(c)._getContentLayer()
+                                               .appendChild(outerNode);
+               }
+
+               // set position
+
+               DOMNode.setStyles(outerNode, "position", "absolute", "left", (x = c.getX())
+                               + "px", "top", (y = c.getY()) + "px");
+
+               if (isContainer) {
+
+                       // set width from component
+
+                       System.out.println("JSComponentUI container " + id + " " + c.getBounds());
+                       DOMNode.setSize(outerNode, c.getWidth(), c.getHeight());
+
+                       // add all children
+                       Component[] children = (components == null ? c.getComponents()
+                                       : components);
+                       for (int i = children.length; --i >= 0;) {
+                               JSComponentUI ui = JSToolkit.getUI(children[i], false);
+                               if (ui == null) {
+                                       // Box.Filler has no ui.
+                                       continue;
+                               }
+                               if (ui.outerNode == null)
+                                       ui.setHTMLElement();
+                               if (ui.outerNode == null) {
+                                       System.out.println("JSCUI could not add " + ui.c.getName() + " to "
+                                                       + c.getName());
+                               } else {
+                                       outerNode.appendChild(ui.outerNode);
+                               }
+                               ui.parent = this;
+                       }
+               }
+
+               // mark as not tainted
+               // debugDump(divObj);
+               isTainted = false;
+               return outerNode;
+       }
+
+       /**
+        * c ignored because JSComponentUI is one per component
+        */
+       public Dimension getPreferredSize(JComponent c) {
+               //System.out.println("getPreferredSize for " + id + " " + c.getName());
+               Dimension d = setHTMLSize(getDOMObject(), false);
+               //System.out.println("JSComponentUI " + id + " getting preferred size as " + d);
+       return d;
+  }
+
+       public void paint(Graphics g, JComponent c) {
+    // Note that for now, button graphics 
+               // are BEHIND the button. We will need to paint onto the
+               // glass pane for this to work, and then also manage
+               // mouse clicks and key clicks with that in mind. 
+               if (c.isOpaque()) {
+                       g.setColor(c.getBackground());
+                       g.fillRect(0, 0, c.getWidth(), c.getHeight());
+               }
+       }
+
+       public void update(Graphics g, JComponent c) {
+               // called from JComponent.paintComponent
+               boolean testing = false;//true;
+               if (testing) {
+                       g.setColor(Color.red);
+                       g.drawRect(0, 0, c.getWidth(), c.getHeight());
+                       System.out.println("drawing " + c.getWidth() + " " + c.getHeight());
+               }
+               setHTMLElement();
+               paint(g, c);
+       }
+
+       public Dimension getMinimumSize(JComponent c) {
+               return getPreferredSize(c);
+       }
+
+       public Dimension getMaximumSize(JComponent c) {
+               return null;// getPreferredSize(c);
+       }
+
+  /**
+   * Returns <code>true</code> if the specified <i>x,y</i> location is
+   * contained within the look and feel's defined shape of the specified
+   * component. <code>x</code> and <code>y</code> are defined to be relative
+   * to the coordinate system of the specified component.  Although
+   * a component's <code>bounds</code> is constrained to a rectangle,
+   * this method provides the means for defining a non-rectangular
+   * shape within those bounds for the purpose of hit detection.
+   *
+   * @param c the component where the <i>x,y</i> location is being queried;
+   *          this argument is often ignored,
+   *          but might be used if the UI object is stateless
+   *          and shared by multiple components
+   * @param x the <i>x</i> coordinate of the point
+   * @param y the <i>y</i> coordinate of the point
+   *
+   * @see jsjavax.swing.JComponent#contains
+   * @see jsjava.awt.Component#contains
+   */
+  public boolean contains(JComponent c, int x, int y) {
+      return c.inside(x, y);
+  }
+
+  /**
+   * Returns an instance of the UI delegate for the specified component.
+   * Each subclass must provide its own static <code>createUI</code>
+   * method that returns an instance of that UI delegate subclass.
+   * If the UI delegate subclass is stateless, it may return an instance
+   * that is shared by multiple components.  If the UI delegate is
+   * stateful, then it should return a new instance per component.
+   * The default implementation of this method throws an error, as it
+   * should never be invoked.
+   */
+  public static ComponentUI createUI(JComponent c) {
+       // SwingJS  so, actually, we don't do this. This class is NOT stateless.
+       // Instead, what we do is to create a unique instance 
+       // right in UIManager. The sequence is:
+       // JRadioButton.updateUI() 
+       // --> jsjavax.swing.UIManager.getUI(this)
+       // --> jsjavax.swing.UIManager.getDefaults().getUI(target) 
+       // --> JSToolkit.getComponentUI(target)
+       // --> creates an instance of JRadioButtonUI and returns
+       // that instance as JRadioButton.ui, which is NOT static.
+       // 
+//      throw new Error("ComponentUI.createUI not implemented.");
+       return null;
+  }
+
+  /**
+   * Returns the baseline.  The baseline is measured from the top of
+   * the component.  This method is primarily meant for
+   * <code>LayoutManager</code>s to align components along their
+   * baseline.  A return value less than 0 indicates this component
+   * does not have a reasonable baseline and that
+   * <code>LayoutManager</code>s should not align this component on
+   * its baseline.
+   * <p>
+   * This method returns -1.  Subclasses that have a meaningful baseline
+   * should override appropriately.
+   *
+   * @param c <code>JComponent</code> baseline is being requested for
+   * @param width the width to get the baseline for
+   * @param height the height to get the baseline for
+   * @throws NullPointerException if <code>c</code> is <code>null</code>
+   * @throws IllegalArgumentException if width or height is &lt; 0
+   * @return baseline or a value &lt; 0 indicating there is no reasonable
+   *                  baseline
+   * @see jsjavax.swing.JComponent#getBaseline(int,int)
+   * @since 1.6
+   */
+  public int getBaseline(JComponent c, int width, int height) {
+      if (c == null) {
+          throw new NullPointerException("Component must be non-null");
+      }
+      if (width < 0 || height < 0) {
+          throw new IllegalArgumentException(
+                  "Width and height must be >= 0");
+      }
+      return -1;
+  }
+
+  /**
+   * Returns an enum indicating how the baseline of he component
+   * changes as the size changes.  This method is primarily meant for
+   * layout managers and GUI builders.
+   * <p>
+   * This method returns <code>BaselineResizeBehavior.OTHER</code>.
+   * Subclasses that support a baseline should override appropriately.
+   *
+   * @param c <code>JComponent</code> to return baseline resize behavior for
+   * @return an enum indicating how the baseline changes as the component
+   *         size changes
+   * @throws NullPointerException if <code>c</code> is <code>null</code>
+   * @see jsjavax.swing.JComponent#getBaseline(int, int)
+   * @since 1.6
+   */
+  public Component.BaselineResizeBehavior getBaselineResizeBehavior(
+          JComponent c) {
+      if (c == null) {
+          throw new NullPointerException("Component must be non-null");
+      }
+      return Component.BaselineResizeBehavior.OTHER;
+  }
+
+  /**
+   * overridden in JSPasswordFieldUI
+   * @return texat
+   */
+  public String getJSTextValue() {
+       return (String) DOMNode.getAttr(domNode, valueNode == null ? "innerHTML" : "value");
+  }
+  
+       public void notifyPropertyChanged(String prop) {
+               DOMNode obj = null;
+               String val = null;
+               if (prop == "text") {
+                       val = ((AbstractButton) c).getText();
+                       if (val.equals(currentText)) // we set it here, then fired the property change
+                               return;
+                       currentText = val;
+                       if (textNode != null) {
+                               prop = "innerHTML";
+                               obj = textNode;
+                       } else if (valueNode != null) {
+                               prop = "value";
+                               obj = valueNode;
+                       }
+               } else if (prop == "preferredSize") {
+                       preferredSize = c.getPreferredSize(); // may be null
+                       getPreferredSize();
+                       return;
+               }
+               if (obj == null) {
+                       System.out.println("JSComponentUI: unrecognized prop: " + prop);
+               } else {
+                       System.out.println("JSComponentUI: setting " + id + " " + prop);// + " " + val);
+                       setProp(obj, prop, val);
+               }
+       }
+
+       protected DOMNode setProp(DOMNode obj, String prop, String val) {
+               return DOMNode.setAttr(obj, prop, val);
+       }
+
+       @Override
+       public boolean isObscured() {
+               JSToolkit.notImplemented("");
+               return false;
+       }
+
+       @Override
+       public boolean canDetermineObscurity() {
+               JSToolkit.notImplemented("");
+               return false;
+       }
+
+       @Override
+       public void setVisible(boolean b) {
+               DOMNode.setStyles(outerNode, "display", b ? "block" : "none");
+       }
+
+       @Override
+       public void setEnabled(boolean b) {     
+               if (enableNode != null)
+                 DOMNode.setAttr(enableNode, "disabled", (b ? null : "TRUE"));
+       }
+
+       @Override
+       public void paint(Graphics g) {
+               // nothing to do here
+       }
+
+       @Override
+       public void repaint(long tm, int x, int y, int width, int height) {
+               // nothing to do here
+       }
+
+       @Override
+       public void print(Graphics g) {
+               JSToolkit.notImplemented("");           
+       }
+
+       @Override
+       public void setBounds(int x, int y, int width, int height, int op) {
+               switch (op) {
+               case SET_SIZE:
+               case SET_BOUNDS:
+               case SET_CLIENT_SIZE:
+                       if (scrollerNode != null) {
+                               width = Math.min(width, scrollerNode.c.getWidth());
+                               height = Math.min(height, scrollerNode.c.getHeight());                  
+                       }
+                       System.out.println(id + " setBounds " + x + " " + y + " " + width + " " + height + " op=" + op);
+                       if (domNode != null)
+                               DOMNode.setSize(domNode, width, height);
+                       break;
+               }
+       }
+
+       @Override
+       public void handleEvent(AWTEvent e) {
+               JSToolkit.notImplemented("");
+               
+       }
+
+       @Override
+       public void coalescePaintEvent(PaintEvent e) {
+               JSToolkit.notImplemented("");
+               
+       }
+
+       /**
+        * Coordinates relative to the document
+        * 
+        */
+       @Override
+       public Point getLocationOnScreen() {
+               Insets offset = (Insets) $(outerNode).offset();
+               return new Point(offset.left, offset.top);
+       }
+
+       @Override
+       public Dimension getPreferredSize() {
+               return getPreferredSize(c);
+       }
+
+       @Override
+       public Dimension getMinimumSize() {
+               JSToolkit.notImplemented("");
+               return getPreferredSize(c);
+       }
+
+       @Override
+       public ColorModel getColorModel() {
+               return Toolkit.getDefaultToolkit().getColorModel();
+       }
+
+       @Override
+       public Toolkit getToolkit() {
+               return Toolkit.getDefaultToolkit();
+       }
+
+       @Override
+       public Graphics getGraphics() {
+               // n/a  -- called from java.awt.Component when NOT a LightweightPeer.
+               return null;
+       }
+
+       @Override
+       public FontMetrics getFontMetrics(Font font) {
+               return c.getFontMetrics(font);
+       }
+
+       @Override
+       public void dispose() {
+               JSToolkit.notImplemented("");
+       }
+
+       @Override
+       public void setForeground(Color color) {
+               if (domNode != null)
+                       DOMNode.setStyles(domNode, "color", JSToolkit.getCSSColor(color == null ? Color.black : color));
+       }
+
+       @Override
+       public void setBackground(Color color) {
+               if (domNode != null)
+                       DOMNode.setStyles(domNode, "background-color", JSToolkit.getCSSColor(color == null ? Color.white : color));
+       }
+
+       @Override
+       public void setFont(Font f) {
+               if (domNode != null)
+                       setCssFont(domNode, f);
+       }
+
+       @Override
+       public void updateCursorImmediately() {
+               JSToolkit.notImplemented("");           
+       }
+
+       @Override
+       public boolean requestFocus(Component lightweightChild, boolean temporary,
+                       boolean focusedWindowChangeAllowed, long time, Cause cause) {
+               if (focusNode == null)
+                       return false;
+               $(focusNode).focus();
+               if (textNode != null)
+                       $(textNode).select();
+               return true;
+       }
+
+       @Override
+       public boolean isFocusable() {
+               return (focusNode != null);
+       }
+
+       @Override
+       public Image createImage(ImageProducer producer) {
+               JSToolkit.notImplemented("");
+               return null;
+       }
+
+       @Override
+       public Image createImage(int width, int height) {
+               JSToolkit.notImplemented("");
+               return null;
+       }
+
+       @Override
+       public VolatileImage createVolatileImage(int width, int height) {
+               JSToolkit.notImplemented("");
+               return null;
+       }
+
+       @Override
+       public boolean prepareImage(Image img, int w, int h, ImageObserver o) {
+               JSToolkit.notImplemented("");
+               return false;
+       }
+
+       @Override
+       public int checkImage(Image img, int w, int h, ImageObserver o) {
+               JSToolkit.notImplemented("");
+               return 0;
+       }
+
+       @Override
+       public GraphicsConfiguration getGraphicsConfiguration() {
+               JSToolkit.notImplemented("");
+               return null;
+       }
+
+       @Override
+       public boolean handlesWheelScrolling() {
+               JSToolkit.notImplemented("");
+               return false;
+       }
+
+       @Override
+       public Image getBackBuffer() {
+               JSToolkit.notImplemented("");
+               return null;
+       }
+
+       @Override
+       public void destroyBuffers() {
+               JSToolkit.notImplemented("");
+               
+       }
+
+       @Override
+       public void reparent(ContainerPeer newContainer) {
+               JSToolkit.notImplemented("");
+               
+       }
+
+       @Override
+       public boolean isReparentSupported() {
+               JSToolkit.notImplemented("");
+               return false;
+       }
+
+       @Override
+       public void layout() {
+               JSToolkit.notImplemented("");
+               
+       }
+
+       @Override
+       public Rectangle getBounds() {
+               JSToolkit.notImplemented("");
+               return null;
+       }
+
+       public boolean hasFocus() {
+               return focusNode != null && focusNode == DOMNode.getAttr(document, "activeElement");
+       }
+
+       public void notifyFocus(boolean focusGained) {
+               Toolkit.getEventQueue().postEvent(new FocusEvent(c, focusGained ? FocusEvent.FOCUS_GAINED : FocusEvent.FOCUS_LOST));
+       }
+}