-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 < 0\r
- * @return baseline or a value < 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 < 0
+ * @return baseline or a value < 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));
+ }
+}