]> source.dussan.org Git - vaadin-framework.git/commitdiff
refactored default icons, now uses ThemeResources properly and renders without captio...
authorMatti Tahvonen <matti.tahvonen@itmill.com>
Fri, 16 Nov 2007 11:21:24 +0000 (11:21 +0000)
committerMatti Tahvonen <matti.tahvonen@itmill.com>
Fri, 16 Nov 2007 11:21:24 +0000 (11:21 +0000)
svn changeset:2845/svn branch:trunk

src/com/itmill/toolkit/terminal/gwt/client/Caption.java
src/com/itmill/toolkit/terminal/gwt/client/CaptionWrapper.java
src/com/itmill/toolkit/terminal/gwt/client/ui/ICustomLayout.java
src/com/itmill/toolkit/terminal/gwt/client/ui/IFormLayout.java
src/com/itmill/toolkit/terminal/gwt/client/ui/IGridLayout.java
src/com/itmill/toolkit/terminal/gwt/client/ui/IOrderedLayout.java

index 0669524de8d057ee5dc3ec9b68b78d45d4305d2b..a07d1871c22710796f6aaea625f4d62217aa0b2b 100644 (file)
@@ -4,134 +4,146 @@ import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.PopupPanel;
+import com.itmill.toolkit.terminal.gwt.client.ui.Icon;
 
 public class Caption extends HTML {
 
-       public static final String CLASSNAME = "i-caption";
-
-       private Paintable owner;
-
-       private Element errorIndicatorElement;
-
-       private Element icon;
-
-       private Element captionText;
-
-       private ErrorMessage errorMessage;
-
-       /* Caption must be attached to a Paintable */
-       private Caption() {
-       };
-
-       public Caption(Paintable component) {
-               super();
-               owner = component;
-               setStyleName(CLASSNAME);
-       }
-
-       public void updateCaption(UIDL uidl) {
-               setVisible(!uidl.getBooleanAttribute("invisible"));
-
-               if (uidl.hasAttribute("error")) {
-                       UIDL errorUidl = uidl.getErrors();
-
-                       if (errorIndicatorElement == null) {
-                               errorIndicatorElement = DOM.createDiv();
-                               DOM.setElementProperty(errorIndicatorElement, "className",
-                                               "i-errorindicator");
-                               DOM.insertChild(getElement(), errorIndicatorElement, 0);
-                       }
-                       if (errorMessage == null)
-                               errorMessage = new ErrorMessage();
-                       errorMessage.updateFromUIDL(errorUidl);
-
-               } else if (errorIndicatorElement != null) {
-                       DOM.setStyleAttribute(errorIndicatorElement, "display", "none");
-               }
-
-               if (uidl.hasAttribute("icon")) {
-                       if (icon == null) {
-                               icon = DOM.createImg();
-                               DOM.appendChild(getElement(), icon);
-                       }
-                       DOM.setElementAttribute(icon, "src", uidl
-                                       .getStringAttribute("icon"));
-               } else {
-                       if (icon != null)
-                               DOM.removeChild(getElement(), icon);
-               }
-
-               if (uidl.hasAttribute("caption")) {
-                       if (captionText == null) {
-                               captionText = DOM.createSpan();
-                               DOM.appendChild(getElement(), captionText);
-                       }
-                       DOM.setInnerText(captionText, uidl.getStringAttribute("caption"));
-               } else {
-                       // TODO should span also be removed
-               }
-
-               if (uidl.hasAttribute("description")) {
-                       if (captionText != null) {
-                               DOM.setElementProperty(captionText, "title", uidl
-                                               .getStringAttribute("description"));
-                       } else {
-                               setTitle(uidl.getStringAttribute("description"));
-                       }
-               }
-
-       }
-
-       public void onBrowserEvent(Event event) {
-               Element target = DOM.eventGetTarget(event);
-               if (errorIndicatorElement != null
-                               && DOM.compare(target, errorIndicatorElement)) {
-                       switch (DOM.eventGetType(event)) {
-                       case Event.ONMOUSEOVER:
-                               showErrorMessage();
-                               break;
-                       case Event.ONMOUSEOUT:
-                               hideErrorMessage();
-                               break;
-                       case Event.ONCLICK:
-                               ApplicationConnection.getConsole().log(
-                                               DOM.getInnerHTML(errorMessage.getElement()));
-                       default:
-                               break;
-                       }
-               }
-       }
-
-       private void hideErrorMessage() {
-               if (errorMessage != null) {
-                       errorMessage.hide();
-               }
-       }
-
-       private void showErrorMessage() {
-               if (errorMessage != null) {
-                       errorMessage.showAt(errorIndicatorElement);
-               }
-       }
-
-       public static boolean isNeeded(UIDL uidl) {
-               if (uidl.getStringAttribute("caption") != null)
-                       return true;
-               if (uidl.hasAttribute("error"))
-                       return true;
-
-               // TODO Description ??
-
-               return false;
-       }
-
-       /**
-        * Returns Paintable for which this Caption belongs to.
-        * 
-        * @return owner Widget
-        */
-       public Paintable getOwner() {
-               return owner;
-       }
+    public static final String CLASSNAME = "i-caption";
+
+    private Paintable owner;
+
+    private Element errorIndicatorElement;
+
+    private Icon icon;
+
+    private Element captionText;
+
+    private ErrorMessage errorMessage;
+
+    private ApplicationConnection client;
+
+    /* Caption must be attached to a Paintable */
+    private Caption() {
+    };
+
+    public Caption(Paintable component, ApplicationConnection client) {
+        super();
+        this.client = client;
+        owner = component;
+        setStyleName(CLASSNAME);
+    }
+
+    public void updateCaption(UIDL uidl) {
+        setVisible(!uidl.getBooleanAttribute("invisible"));
+
+        if (uidl.hasAttribute("error")) {
+            UIDL errorUidl = uidl.getErrors();
+
+            if (errorIndicatorElement == null) {
+                errorIndicatorElement = DOM.createDiv();
+                DOM.setElementProperty(errorIndicatorElement, "className",
+                        "i-errorindicator");
+                DOM.insertChild(getElement(), errorIndicatorElement, 0);
+            }
+            if (errorMessage == null) {
+                errorMessage = new ErrorMessage();
+            }
+            errorMessage.updateFromUIDL(errorUidl);
+
+        } else if (errorIndicatorElement != null) {
+            DOM.setStyleAttribute(errorIndicatorElement, "display", "none");
+        }
+
+        if (uidl.hasAttribute("icon")) {
+            if (icon == null) {
+                icon = new Icon(client);
+
+                DOM.appendChild(getElement(), icon.getElement());
+            }
+            icon.setUri(uidl.getStringAttribute("icon"));
+        } else {
+            if (icon != null) {
+                DOM.removeChild(getElement(), icon.getElement());
+                icon = null;
+            }
+
+        }
+
+        if (uidl.hasAttribute("caption")) {
+            if (captionText == null) {
+                captionText = DOM.createSpan();
+                DOM.appendChild(getElement(), captionText);
+            }
+            DOM.setInnerText(captionText, uidl.getStringAttribute("caption"));
+        } else {
+            // TODO should span also be removed
+        }
+
+        if (uidl.hasAttribute("description")) {
+            if (captionText != null) {
+                DOM.setElementProperty(captionText, "title", uidl
+                        .getStringAttribute("description"));
+            } else {
+                setTitle(uidl.getStringAttribute("description"));
+            }
+        }
+
+    }
+
+    public void onBrowserEvent(Event event) {
+        Element target = DOM.eventGetTarget(event);
+        if (errorIndicatorElement != null
+                && DOM.compare(target, errorIndicatorElement)) {
+            switch (DOM.eventGetType(event)) {
+            case Event.ONMOUSEOVER:
+                showErrorMessage();
+                break;
+            case Event.ONMOUSEOUT:
+                hideErrorMessage();
+                break;
+            case Event.ONCLICK:
+                ApplicationConnection.getConsole().log(
+                        DOM.getInnerHTML(errorMessage.getElement()));
+            default:
+                break;
+            }
+        }
+    }
+
+    private void hideErrorMessage() {
+        if (errorMessage != null) {
+            errorMessage.hide();
+        }
+    }
+
+    private void showErrorMessage() {
+        if (errorMessage != null) {
+            errorMessage.showAt(errorIndicatorElement);
+        }
+    }
+
+    public static boolean isNeeded(UIDL uidl) {
+        if (uidl.getStringAttribute("caption") != null) {
+            return true;
+        }
+        if (uidl.hasAttribute("error")) {
+            return true;
+        }
+        if (uidl.hasAttribute("icon")) {
+            return true;
+        }
+
+        // TODO Description ??
+
+        return false;
+    }
+
+    /**
+     * Returns Paintable for which this Caption belongs to.
+     * 
+     * @return owner Widget
+     */
+    public Paintable getOwner() {
+        return owner;
+    }
 }
index a4e05f0283d5983aa3678793aae89a1a76bdb59b..5b61a40ecd8ddb6b218fd8b3e1b8bd082eff97bf 100644 (file)
@@ -5,24 +5,24 @@ import com.google.gwt.user.client.ui.Widget;
 
 public class CaptionWrapper extends FlowPanel {
 
-       public static final String CLASSNAME = "i-captionwrapper";
-       Caption caption;
-       Paintable widget;
+    public static final String CLASSNAME = "i-captionwrapper";
+    Caption caption;
+    Paintable widget;
 
-       public CaptionWrapper(Paintable toBeWrapped) {
-               caption = new Caption(toBeWrapped);
-               add(caption);
-               widget = toBeWrapped;
-               add((Widget) widget);
-               setStyleName(CLASSNAME);
-       }
+    public CaptionWrapper(Paintable toBeWrapped, ApplicationConnection client) {
+        caption = new Caption(toBeWrapped, client);
+        add(caption);
+        widget = toBeWrapped;
+        add((Widget) widget);
+        setStyleName(CLASSNAME);
+    }
 
-       public void updateCaption(UIDL uidl) {
-               caption.updateCaption(uidl);
-               setVisible(!uidl.getBooleanAttribute("invisible"));
-       }
+    public void updateCaption(UIDL uidl) {
+        caption.updateCaption(uidl);
+        setVisible(!uidl.getBooleanAttribute("invisible"));
+    }
 
-       public Paintable getPaintable() {
-               return widget;
-       }
+    public Paintable getPaintable() {
+        return widget;
+    }
 }
index b8e2da7e8b904332717c0d17d6ab80ff0965fbf6..3924f1ba5e9aa1c19bac6c2ee7672bc300c412e6 100644 (file)
@@ -23,399 +23,406 @@ import com.itmill.toolkit.terminal.gwt.client.Util;
  * 
  */
 public class ICustomLayout extends ComplexPanel implements Paintable,
-               Container, ContainerResizedListener {
-
-       /** Location-name to containing element in DOM map */
-       private HashMap locationToElement = new HashMap();
-
-       /** Location-name to contained widget map */
-       private HashMap locationToWidget = new HashMap();
-
-       /** Widget to captionwrapper map */
-       private HashMap widgetToCaptionWrapper = new HashMap();
-
-       /** Currently rendered style */
-       String currentTemplate;
-
-       /** Unexecuted scripts loaded from the template */
-       private String scripts = "";
-
-       /** Paintable ID of this paintable */
-       private String pid;
-
-       private ApplicationConnection client;
-
-       public ICustomLayout() {
-               setElement(DOM.createDiv());
-               DOM.setStyleAttribute(getElement(), "height", "100%");
-       }
-
-       /**
-        * Sets widget to given location.
-        * 
-        * If location already contains a widget it will be removed.
-        * 
-        * @param widget
-        *            Widget to be set into location.
-        * @param location
-        *            location name where widget will be added
-        * 
-        * @throws IllegalArgumentException
-        *             if no such location is found in the layout.
-        */
-       public void setWidget(Widget widget, String location) {
-
-               if (widget == null)
-                       return;
-
-               // If no given location is found in the layout, and exception is throws
-               Element elem = (Element) locationToElement.get(location);
-               if (elem == null && hasTemplate()) {
-                       throw new IllegalArgumentException("No location " + location
-                                       + " found");
-               }
-
-               // Get previous widget
-               Widget previous = (Widget) locationToWidget.get(location);
-               // NOP if given widget already exists in this location
-               if (previous == widget)
-                       return;
-               remove(previous);
-
-               // if template is missing add element in order
-               if (!hasTemplate())
-                       elem = getElement();
-
-               // Add widget to location
-               super.add(widget, elem);
-               locationToWidget.put(location, widget);
-       }
-
-       /** Update the layout from UIDL */
-       public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-               this.client = client;
-               // Client manages general cases
-               if (client.updateComponent(this, uidl, false))
-                       return;
-
-               // Update PID
-               pid = uidl.getId();
-               if (!hasTemplate()) {
-                       // Update HTML template only once
-                       initializeHTML(uidl, client);
-               }
-
-               // Evaluate scripts
-               eval(scripts);
-               scripts = null;
-               
-               // For all contained widgets
-               for (Iterator i = uidl.getChildIterator(); i.hasNext();) {
-                       UIDL uidlForChild = (UIDL) i.next();
-                       if (uidlForChild.getTag().equals("location")) {
-                               String location = uidlForChild.getStringAttribute("name");
-                               Widget child = client.getWidget(uidlForChild.getChildUIDL(0));
-                               try {
-                                       setWidget(child, location);
-                                       ((Paintable) child).updateFromUIDL(uidlForChild
-                                                       .getChildUIDL(0), client);
-                               } catch (IllegalArgumentException e) {
-                                       // If no location is found, this component is not visible
-                               }
-                       }
-               }
-
-               iLayout();
-       }
-
-       /** Initialize HTML-layout. */
-       private void initializeHTML(UIDL uidl, ApplicationConnection client) {
-
-               String newTemplate = uidl.getStringAttribute("template");
-
-               // Get the HTML-template from client
-               String template = client
-                               .getResource("layouts/" + newTemplate + ".html");
-               if (template == null) {
-                       template = "<em>Layout file layouts/"
-                                       + newTemplate
-                                       + ".html is missing. Components will be drawn for debug purposes.</em>";
-               } else {
-                       currentTemplate = newTemplate;
-               }
-
-               // Connect body of the template to DOM
-               template = extractBodyAndScriptsFromTemplate(template);
-               DOM.setInnerHTML(getElement(), template);
-
-               // Remap locations to elements
-               locationToElement.clear();
-               scanForLocations(getElement());
-
-               // Remap image srcs in layout
-               Widget parent = getParent();
-               while (parent != null && !(parent instanceof IView))
-                       parent = parent.getParent();
-               if (parent != null && ((IView) parent).getTheme() != null) {
-                       String prefix;
-                       if(uriEndsWithSlash()) {
-                               prefix = "../ITMILL/themes/";
-                       } else {
-                               prefix = "ITMILL/themes/";
-                       }
-                       prefixImgSrcs(getElement(), prefix
-                                       + ((IView) parent).getTheme() + "/layouts/");
-               } else {
-                       throw (new IllegalStateException(
-                                       "Could not find IView; maybe updateFromUIDL() was called before attaching the widget?"));
-               }
-               
-               publishResizedFunction(DOM.getFirstChild(getElement()));
-               
-       }
-
-       private native boolean uriEndsWithSlash() /*-{
-               var path =  $wnd.location.pathname;
-               if(path.charAt(path.length - 1) == "/")
-                       return true;
-               return false;
-       }-*/;
-
-       private boolean hasTemplate() {
-               if (currentTemplate == null)
-                       return false;
-               else
-                       return true;
-       }
-
-       /** Collect locations from template */
-       private void scanForLocations(Element elem) {
-
-               String location = getLocation(elem);
-               if (location != null) {
-                       locationToElement.put(location, elem);
-                       DOM.setInnerHTML(elem, "");
-               } else {
-                       int len = DOM.getChildCount(elem);
-                       for (int i = 0; i < len; i++) {
-                               scanForLocations(DOM.getChild(elem, i));
-                       }
-               }
-       }
-
-       /** Get the location attribute for given element */
-       private static native String getLocation(Element elem) /*-{
-        return elem.getAttribute("location");
-        }-*/;
-
-       /** Evaluate given script in browser document */
-       private static native void eval(String script) /*-{
-        try {
-        if (script != null) 
-        eval("{ var document = $doc; var window = $wnd; "+ script + "}");
-        } catch (e) {
-        }
-        }-*/;
-
-       /** Prefix all img tag srcs with given prefix. */
-       private static native void prefixImgSrcs(Element e, String srcPrefix) /*-{
-        try {
-        var divs = e.getElementsByTagName("img"); 
-        var base = "" + $doc.location;
-        var l = base.length-1;
-        while (l >= 0 && base.charAt(l) != "/") l--;
-        base = base.substring(0,l+1);
-        for (var i = 0; i < divs.length; i++) {
-        var div = divs[i];
-        var src = div.getAttribute("src");
-        if (src.indexOf(base) == 0) div.setAttribute("src",base + srcPrefix + src.substring(base.length));
-        else if (src.indexOf("http") != 0) div.setAttribute("src",srcPrefix + src);
-        }                      
-        } catch (e) { alert(e + " " + srcPrefix);}
-        }-*/;
-
-       /**
-        * Extract body part and script tags from raw html-template.
-        * 
-        * Saves contents of all script-tags to private property: scripts. Returns
-        * contents of the body part for the html without script-tags. Also replaces
-        * all _UID_ tags with an unique id-string.
-        * 
-        * @param html
-        *            Original HTML-template received from server
-        * @return html that is used to create the HTMLPanel.
-        */
-       private String extractBodyAndScriptsFromTemplate(String html) {
-
-               // Replace UID:s
-               html = html.replaceAll("_UID_", pid + "__");
-
-               // Exctract script-tags
-               scripts = "";
-               int endOfPrevScript = 0;
-               int nextPosToCheck = 0;
-               String lc = html.toLowerCase();
-               String res = "";
-               int scriptStart = lc.indexOf("<script", nextPosToCheck);
-               while (scriptStart > 0) {
-                       res += html.substring(endOfPrevScript, scriptStart);
-                       scriptStart = lc.indexOf(">", scriptStart);
-                       int j = lc.indexOf("</script>", scriptStart);
-                       scripts += html.substring(scriptStart + 1, j) + ";";
-                       nextPosToCheck = endOfPrevScript = j + "</script>".length();
-                       scriptStart = lc.indexOf("<script", nextPosToCheck);
-               }
-               res += html.substring(endOfPrevScript);
-
-               // Extract body
-               html = res;
-               lc = html.toLowerCase();
-               int startOfBody = lc.indexOf("<body");
-               if (startOfBody < 0) {
-                       res = html;
-               } else {
-                       res = "";
-                       startOfBody = lc.indexOf(">", startOfBody) + 1;
-                       int endOfBody = lc.indexOf("</body>", startOfBody);
-                       if (endOfBody > startOfBody)
-                               res = html.substring(startOfBody, endOfBody);
-                       else
-                               res = html.substring(startOfBody);
-               }
-
-               return res;
-       }
-
-       protected void onAttach() {
-               super.onAttach();
-       }
-
-       /** Replace child components */
-       public void replaceChildComponent(Widget from, Widget to) {
-               String location = getLocation(from);
-               if (location == null)
-                       throw new IllegalArgumentException();
-               setWidget(to, location);
-       }
-
-       /** Does this layout contain given child */
-       public boolean hasChildComponent(Widget component) {
-               return locationToWidget.containsValue(component);
-       }
-
-       /** Update caption for given widget */
-       public void updateCaption(Paintable component, UIDL uidl) {
-               CaptionWrapper wrapper = (CaptionWrapper) widgetToCaptionWrapper
-                               .get(component);
-               if (Caption.isNeeded(uidl)) {
-                       if (wrapper == null) {
-                               String loc = getLocation((Widget) component);
-                               super.remove((Widget) component);
-                               wrapper = new CaptionWrapper(component);
-                               super.add(wrapper, (Element) locationToElement.get(loc));
-                               widgetToCaptionWrapper.put(component, wrapper);
-                       }
-                       wrapper.updateCaption(uidl);
-               } else {
-                       if (wrapper != null) {
-                               String loc = getLocation((Widget) component);
-                               super.remove(wrapper);
-                               super.add((Widget) wrapper.getPaintable(),
-                                               (Element) locationToElement.get(loc));
-                               widgetToCaptionWrapper.remove(component);
-                       }
-               }
-       }
-
-       /** Get the location of an widget */
-       public String getLocation(Widget w) {
-               for (Iterator i = locationToWidget.keySet().iterator(); i.hasNext();) {
-                       String location = (String) i.next();
-                       if (locationToWidget.get(location) == w)
-                               return location;
-               }
-               return null;
-       }
-
-       /** Removes given widget from the layout */
-       public boolean remove(Widget w) {
-               client.unregisterPaintable((Paintable) w);
-               String location = getLocation(w);
-               if (location != null)
-                       locationToWidget.remove(location);
-               CaptionWrapper cw = (CaptionWrapper) widgetToCaptionWrapper.get(w);
-               if (cw != null) {
-                       widgetToCaptionWrapper.remove(w);
-                       return super.remove(cw);
-               } else if (w != null)
-                       return super.remove(w);
-               return false;
-       }
-
-       /** Adding widget without specifying location is not supported */
-       public void add(Widget w) {
-               throw new UnsupportedOperationException();
-       }
-
-       /** Clear all widgets from the layout */
-       public void clear() {
-               super.clear();
-               locationToWidget.clear();
-               widgetToCaptionWrapper.clear();
-       }
-
-       public void iLayout() {
-               if (!iLayoutJS(DOM.getFirstChild(getElement()))) {
-                       Util.runDescendentsLayout(this);
-               }
-       }
-
-       /**
-        * This method is published to JS side with the same name into first DOM
-        * node of custom layout. This way if one implements some resizeable
-        * containers in custom layout he/she can notify children after resize.
-        */
-       public void notifyChildrenOfSizeChange() {
-               Util.runDescendentsLayout(this);
-       }
-
-       public void onDetach() {
-               detachResizedFunction(DOM.getFirstChild(getElement()));
-       }
-
-       private native void detachResizedFunction(Element element)
-       /*-{
-               element.notifyChildrenOfSizeChange = null;
-       }-*/;
-
-       private native void publishResizedFunction(Element element)
-       /*-{
-               var self = this;
-               element.notifyChildrenOfSizeChange = function() {
-                       self.@com.itmill.toolkit.terminal.gwt.client.ui.ICustomLayout::notifyChildrenOfSizeChange()();
-               };
-       }-*/;
-
-       /**
-        * In custom layout one may want to run layout functions made with
-        * JavaScript. This function tests if one exists (with name "iLayoutJS" in
-        * layouts first DOM node) and runs if it. Return value is used to determine
-        * is children needs to be notified of size changes.
-        * 
-        * @param el
-        * @return true if layout function was run and it returned true.
-        */
-       private native boolean iLayoutJS(Element el)
-       /*-{
-               if(el && el.iLayoutJS) {
-                       try {
-                               el.iLayoutJS();
-                               return true;
-                       } catch (e) {
-                               return false;
-                       }
-               } else {
-                       return false;
-               }
-       }-*/;
+        Container, ContainerResizedListener {
+
+    /** Location-name to containing element in DOM map */
+    private HashMap locationToElement = new HashMap();
+
+    /** Location-name to contained widget map */
+    private HashMap locationToWidget = new HashMap();
+
+    /** Widget to captionwrapper map */
+    private HashMap widgetToCaptionWrapper = new HashMap();
+
+    /** Currently rendered style */
+    String currentTemplate;
+
+    /** Unexecuted scripts loaded from the template */
+    private String scripts = "";
+
+    /** Paintable ID of this paintable */
+    private String pid;
+
+    private ApplicationConnection client;
+
+    public ICustomLayout() {
+        setElement(DOM.createDiv());
+        DOM.setStyleAttribute(getElement(), "height", "100%");
+    }
+
+    /**
+     * Sets widget to given location.
+     * 
+     * If location already contains a widget it will be removed.
+     * 
+     * @param widget
+     *                Widget to be set into location.
+     * @param location
+     *                location name where widget will be added
+     * 
+     * @throws IllegalArgumentException
+     *                 if no such location is found in the layout.
+     */
+    public void setWidget(Widget widget, String location) {
+
+        if (widget == null) {
+            return;
+        }
+
+        // If no given location is found in the layout, and exception is throws
+        Element elem = (Element) locationToElement.get(location);
+        if (elem == null && hasTemplate()) {
+            throw new IllegalArgumentException("No location " + location
+                    + " found");
+        }
+
+        // Get previous widget
+        Widget previous = (Widget) locationToWidget.get(location);
+        // NOP if given widget already exists in this location
+        if (previous == widget) {
+            return;
+        }
+        remove(previous);
+
+        // if template is missing add element in order
+        if (!hasTemplate()) {
+            elem = getElement();
+        }
+
+        // Add widget to location
+        super.add(widget, elem);
+        locationToWidget.put(location, widget);
+    }
+
+    /** Update the layout from UIDL */
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        this.client = client;
+        // Client manages general cases
+        if (client.updateComponent(this, uidl, false)) {
+            return;
+        }
+
+        // Update PID
+        pid = uidl.getId();
+        if (!hasTemplate()) {
+            // Update HTML template only once
+            initializeHTML(uidl, client);
+        }
+
+        // Evaluate scripts
+        eval(scripts);
+        scripts = null;
+
+        // For all contained widgets
+        for (Iterator i = uidl.getChildIterator(); i.hasNext();) {
+            UIDL uidlForChild = (UIDL) i.next();
+            if (uidlForChild.getTag().equals("location")) {
+                String location = uidlForChild.getStringAttribute("name");
+                Widget child = client.getWidget(uidlForChild.getChildUIDL(0));
+                try {
+                    setWidget(child, location);
+                    ((Paintable) child).updateFromUIDL(uidlForChild
+                            .getChildUIDL(0), client);
+                } catch (IllegalArgumentException e) {
+                    // If no location is found, this component is not visible
+                }
+            }
+        }
+
+        iLayout();
+    }
+
+    /** Initialize HTML-layout. */
+    private void initializeHTML(UIDL uidl, ApplicationConnection client) {
+
+        String newTemplate = uidl.getStringAttribute("template");
+
+        // Get the HTML-template from client
+        String template = client
+                .getResource("layouts/" + newTemplate + ".html");
+        if (template == null) {
+            template = "<em>Layout file layouts/"
+                    + newTemplate
+                    + ".html is missing. Components will be drawn for debug purposes.</em>";
+        } else {
+            currentTemplate = newTemplate;
+        }
+
+        // Connect body of the template to DOM
+        template = extractBodyAndScriptsFromTemplate(template);
+        DOM.setInnerHTML(getElement(), template);
+
+        // Remap locations to elements
+        locationToElement.clear();
+        scanForLocations(getElement());
+
+        // Remap image srcs in layout
+        Widget parent = getParent();
+        while (parent != null && !(parent instanceof IView)) {
+            parent = parent.getParent();
+        }
+        if (parent != null && ((IView) parent).getTheme() != null) {
+            String prefix;
+            if (uriEndsWithSlash()) {
+                prefix = "../ITMILL/themes/";
+            } else {
+                prefix = "ITMILL/themes/";
+            }
+            prefixImgSrcs(getElement(), prefix + ((IView) parent).getTheme()
+                    + "/layouts/");
+        } else {
+            throw (new IllegalStateException(
+                    "Could not find IView; maybe updateFromUIDL() was called before attaching the widget?"));
+        }
+
+        publishResizedFunction(DOM.getFirstChild(getElement()));
+
+    }
+
+    private native boolean uriEndsWithSlash() /*-{
+       var path =  $wnd.location.pathname;
+       if(path.charAt(path.length - 1) == "/")
+               return true;
+       return false;
+    }-*/;
+
+    private boolean hasTemplate() {
+        if (currentTemplate == null) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /** Collect locations from template */
+    private void scanForLocations(Element elem) {
+
+        String location = getLocation(elem);
+        if (location != null) {
+            locationToElement.put(location, elem);
+            DOM.setInnerHTML(elem, "");
+        } else {
+            int len = DOM.getChildCount(elem);
+            for (int i = 0; i < len; i++) {
+                scanForLocations(DOM.getChild(elem, i));
+            }
+        }
+    }
+
+    /** Get the location attribute for given element */
+    private static native String getLocation(Element elem) /*-{
+     return elem.getAttribute("location");
+     }-*/;
+
+    /** Evaluate given script in browser document */
+    private static native void eval(String script) /*-{
+     try {
+        if (script != null) 
+     eval("{ var document = $doc; var window = $wnd; "+ script + "}");
+     } catch (e) {
+     }
+     }-*/;
+
+    /** Prefix all img tag srcs with given prefix. */
+    private static native void prefixImgSrcs(Element e, String srcPrefix) /*-{
+     try {
+     var divs = e.getElementsByTagName("img"); 
+     var base = "" + $doc.location;
+     var l = base.length-1;
+     while (l >= 0 && base.charAt(l) != "/") l--;
+     base = base.substring(0,l+1);
+     for (var i = 0; i < divs.length; i++) {
+     var div = divs[i];
+     var src = div.getAttribute("src");
+     if (src.indexOf(base) == 0) div.setAttribute("src",base + srcPrefix + src.substring(base.length));
+     else if (src.indexOf("http") != 0) div.setAttribute("src",srcPrefix + src);
+     }                 
+     } catch (e) { alert(e + " " + srcPrefix);}
+     }-*/;
+
+    /**
+     * Extract body part and script tags from raw html-template.
+     * 
+     * Saves contents of all script-tags to private property: scripts. Returns
+     * contents of the body part for the html without script-tags. Also replaces
+     * all _UID_ tags with an unique id-string.
+     * 
+     * @param html
+     *                Original HTML-template received from server
+     * @return html that is used to create the HTMLPanel.
+     */
+    private String extractBodyAndScriptsFromTemplate(String html) {
+
+        // Replace UID:s
+        html = html.replaceAll("_UID_", pid + "__");
+
+        // Exctract script-tags
+        scripts = "";
+        int endOfPrevScript = 0;
+        int nextPosToCheck = 0;
+        String lc = html.toLowerCase();
+        String res = "";
+        int scriptStart = lc.indexOf("<script", nextPosToCheck);
+        while (scriptStart > 0) {
+            res += html.substring(endOfPrevScript, scriptStart);
+            scriptStart = lc.indexOf(">", scriptStart);
+            int j = lc.indexOf("</script>", scriptStart);
+            scripts += html.substring(scriptStart + 1, j) + ";";
+            nextPosToCheck = endOfPrevScript = j + "</script>".length();
+            scriptStart = lc.indexOf("<script", nextPosToCheck);
+        }
+        res += html.substring(endOfPrevScript);
+
+        // Extract body
+        html = res;
+        lc = html.toLowerCase();
+        int startOfBody = lc.indexOf("<body");
+        if (startOfBody < 0) {
+            res = html;
+        } else {
+            res = "";
+            startOfBody = lc.indexOf(">", startOfBody) + 1;
+            int endOfBody = lc.indexOf("</body>", startOfBody);
+            if (endOfBody > startOfBody) {
+                res = html.substring(startOfBody, endOfBody);
+            } else {
+                res = html.substring(startOfBody);
+            }
+        }
+
+        return res;
+    }
+
+    /** Replace child components */
+    public void replaceChildComponent(Widget from, Widget to) {
+        String location = getLocation(from);
+        if (location == null) {
+            throw new IllegalArgumentException();
+        }
+        setWidget(to, location);
+    }
+
+    /** Does this layout contain given child */
+    public boolean hasChildComponent(Widget component) {
+        return locationToWidget.containsValue(component);
+    }
+
+    /** Update caption for given widget */
+    public void updateCaption(Paintable component, UIDL uidl) {
+        CaptionWrapper wrapper = (CaptionWrapper) widgetToCaptionWrapper
+                .get(component);
+        if (Caption.isNeeded(uidl)) {
+            if (wrapper == null) {
+                String loc = getLocation((Widget) component);
+                super.remove((Widget) component);
+                wrapper = new CaptionWrapper(component, client);
+                super.add(wrapper, (Element) locationToElement.get(loc));
+                widgetToCaptionWrapper.put(component, wrapper);
+            }
+            wrapper.updateCaption(uidl);
+        } else {
+            if (wrapper != null) {
+                String loc = getLocation((Widget) component);
+                super.remove(wrapper);
+                super.add((Widget) wrapper.getPaintable(),
+                        (Element) locationToElement.get(loc));
+                widgetToCaptionWrapper.remove(component);
+            }
+        }
+    }
+
+    /** Get the location of an widget */
+    public String getLocation(Widget w) {
+        for (Iterator i = locationToWidget.keySet().iterator(); i.hasNext();) {
+            String location = (String) i.next();
+            if (locationToWidget.get(location) == w) {
+                return location;
+            }
+        }
+        return null;
+    }
+
+    /** Removes given widget from the layout */
+    public boolean remove(Widget w) {
+        client.unregisterPaintable((Paintable) w);
+        String location = getLocation(w);
+        if (location != null) {
+            locationToWidget.remove(location);
+        }
+        CaptionWrapper cw = (CaptionWrapper) widgetToCaptionWrapper.get(w);
+        if (cw != null) {
+            widgetToCaptionWrapper.remove(w);
+            return super.remove(cw);
+        } else if (w != null) {
+            return super.remove(w);
+        }
+        return false;
+    }
+
+    /** Adding widget without specifying location is not supported */
+    public void add(Widget w) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** Clear all widgets from the layout */
+    public void clear() {
+        super.clear();
+        locationToWidget.clear();
+        widgetToCaptionWrapper.clear();
+    }
+
+    public void iLayout() {
+        if (!iLayoutJS(DOM.getFirstChild(getElement()))) {
+            Util.runDescendentsLayout(this);
+        }
+    }
+
+    /**
+     * This method is published to JS side with the same name into first DOM
+     * node of custom layout. This way if one implements some resizeable
+     * containers in custom layout he/she can notify children after resize.
+     */
+    public void notifyChildrenOfSizeChange() {
+        Util.runDescendentsLayout(this);
+    }
+
+    public void onDetach() {
+        detachResizedFunction(DOM.getFirstChild(getElement()));
+    }
+
+    private native void detachResizedFunction(Element element)
+    /*-{
+       element.notifyChildrenOfSizeChange = null;
+    }-*/;
+
+    private native void publishResizedFunction(Element element)
+    /*-{
+       var self = this;
+       element.notifyChildrenOfSizeChange = function() {
+               self.@com.itmill.toolkit.terminal.gwt.client.ui.ICustomLayout::notifyChildrenOfSizeChange()();
+       };
+    }-*/;
+
+    /**
+     * In custom layout one may want to run layout functions made with
+     * JavaScript. This function tests if one exists (with name "iLayoutJS" in
+     * layouts first DOM node) and runs if it. Return value is used to determine
+     * is children needs to be notified of size changes.
+     * 
+     * @param el
+     * @return true if layout function was run and it returned true.
+     */
+    private native boolean iLayoutJS(Element el)
+    /*-{
+       if(el && el.iLayoutJS) {
+               try {
+                       el.iLayoutJS();
+                       return true;
+               } catch (e) {
+                       return false;
+               }
+       } else {
+               return false;
+       }
+    }-*/;
 }
index fe1fffd49794c7328fd68a90564ce06f33930a6c..7aa87bfc1eac674a874342b73dbba36795a880f6 100644 (file)
@@ -16,64 +16,66 @@ import com.itmill.toolkit.terminal.gwt.client.UIDL;
  */
 public class IFormLayout extends FlexTable implements Container {
 
-       HashMap componentToCaption = new HashMap();
-       private ApplicationConnection client;
+    HashMap componentToCaption = new HashMap();
+    private ApplicationConnection client;
 
-       public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-               this.client = client;
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        this.client = client;
 
-               if (client.updateComponent(this, uidl, false))
-                       return;
+        if (client.updateComponent(this, uidl, false)) {
+            return;
+        }
 
-               int i = 0;
-               for (Iterator it = uidl.getChildIterator(); it.hasNext(); i++) {
-                       prepareCell(i, 1);
-                       UIDL childUidl = (UIDL) it.next();
-                       Paintable p = (Paintable) client.getWidget(childUidl);
-                       Caption c = (Caption) componentToCaption.get(p);
-                       if (c == null) {
-                               c = new Caption(p);
-                               componentToCaption.put(p, c);
-                       }
-                       Paintable oldComponent = (Paintable) getWidget(i, 1);
-                       if (oldComponent == null) {
-                               setWidget(i, 1, (Widget) p);
-                       } else if (oldComponent != p) {
-                               client.unregisterPaintable(oldComponent);
-                               setWidget(i, 1, (Widget) p);
-                       }
-                       setWidget(i, 0, c);
-                       p.updateFromUIDL(childUidl, client);
-               }
-               i++;
-               while (getRowCount() > i) {
-                       Paintable p = (Paintable) getWidget(i, 1);
-                       client.unregisterPaintable(p);
-                       componentToCaption.remove(p);
-                       removeRow(i);
-               }
-       }
+        int i = 0;
+        for (Iterator it = uidl.getChildIterator(); it.hasNext(); i++) {
+            prepareCell(i, 1);
+            UIDL childUidl = (UIDL) it.next();
+            Paintable p = (Paintable) client.getWidget(childUidl);
+            Caption c = (Caption) componentToCaption.get(p);
+            if (c == null) {
+                c = new Caption(p, client);
+                componentToCaption.put(p, c);
+            }
+            Paintable oldComponent = (Paintable) getWidget(i, 1);
+            if (oldComponent == null) {
+                setWidget(i, 1, (Widget) p);
+            } else if (oldComponent != p) {
+                client.unregisterPaintable(oldComponent);
+                setWidget(i, 1, (Widget) p);
+            }
+            setWidget(i, 0, c);
+            p.updateFromUIDL(childUidl, client);
+        }
+        i++;
+        while (getRowCount() > i) {
+            Paintable p = (Paintable) getWidget(i, 1);
+            client.unregisterPaintable(p);
+            componentToCaption.remove(p);
+            removeRow(i);
+        }
+    }
 
-       public boolean hasChildComponent(Widget component) {
-               return componentToCaption.containsKey(component);
-       }
+    public boolean hasChildComponent(Widget component) {
+        return componentToCaption.containsKey(component);
+    }
 
-       public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-               int i;
-               for (i = 0; i < getRowCount(); i++) {
-                       if (oldComponent == getWidget(i, 1)) {
-                               Caption newCap = new Caption((Paintable) newComponent);
-                               setWidget(i, 0, newCap);
-                               setWidget(i, 1, newComponent);
-                               client.unregisterPaintable((Paintable) oldComponent);
-                               break;
-                       }
-               }
-       }
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        int i;
+        for (i = 0; i < getRowCount(); i++) {
+            if (oldComponent == getWidget(i, 1)) {
+                Caption newCap = new Caption((Paintable) newComponent, client);
+                setWidget(i, 0, newCap);
+                setWidget(i, 1, newComponent);
+                client.unregisterPaintable((Paintable) oldComponent);
+                break;
+            }
+        }
+    }
 
-       public void updateCaption(Paintable component, UIDL uidl) {
-               Caption c = (Caption) componentToCaption.get(component);
-               if (c != null)
-                       c.updateCaption(uidl);
-       }
+    public void updateCaption(Paintable component, UIDL uidl) {
+        Caption c = (Caption) componentToCaption.get(component);
+        if (c != null) {
+            c.updateCaption(uidl);
+        }
+    }
 }
index 69645e047d33f1aad4784ca3fa4ae23d0853e909..e532e8b79ff78d39b907365ae594c332ccc6ddcd 100644 (file)
@@ -14,86 +14,91 @@ import com.itmill.toolkit.terminal.gwt.client.UIDL;
 
 public class IGridLayout extends FlexTable implements Paintable, Container {
 
-       /** Widget to captionwrapper map */
-       private HashMap widgetToCaptionWrapper = new HashMap();
-
-       public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-
-               if (client.updateComponent(this, uidl, false))
-                       return;
-
-               clear();
-               if (uidl.hasAttribute("caption"))
-                       setTitle(uidl.getStringAttribute("caption"));
-               int row = 0, column = 0;
-
-               ArrayList detachdedPaintables = new ArrayList();
-
-               for (Iterator i = uidl.getChildIterator(); i.hasNext();) {
-                       UIDL r = (UIDL) i.next();
-                       if ("gr".equals(r.getTag())) {
-                               row++;
-                               column = 0;
-                               for (Iterator j = r.getChildIterator(); j.hasNext();) {
-                                       UIDL c = (UIDL) j.next();
-                                       if ("gc".equals(c.getTag())) {
-                                               column++;
-                                               int w;
-                                               if (c.hasAttribute("w")) {
-                                                       w = c.getIntAttribute("w");
-                                               } else
-                                                       w = 1;
-                                               ((FlexCellFormatter) getCellFormatter()).setColSpan(
-                                                               row, column, w);
-
-                                               UIDL u = c.getChildUIDL(0);
-                                               if (u != null) {
-                                                       Widget child = client.getWidget(u);
-                                                       prepareCell(row, column);
-                                                       Widget oldChild = getWidget(row, column);
-                                                       if (child != oldChild) {
-                                                               if (oldChild != null) {
-                                                                       CaptionWrapper cw = (CaptionWrapper) oldChild;
-                                                                       detachdedPaintables.add(cw.getPaintable());
-                                                                       widgetToCaptionWrapper.remove(oldChild);
-                                                               }
-                                                               CaptionWrapper wrapper = new CaptionWrapper(
-                                                                               (Paintable) child);
-                                                               setWidget(row, column, wrapper);
-                                                               widgetToCaptionWrapper.put(child, wrapper);
-                                                       }
-                                                       ((Paintable) child).updateFromUIDL(u, client);
-                                               }
-                                               column += w - 1;
-                                       }
-                               }
-                       }
-               }
-
-               // for loop detached widgets and unregister them unless they are
-               // attached (case of widget which is moved to another cell)
-               for (Iterator it = detachdedPaintables.iterator(); it.hasNext();) {
-                       Widget w = (Widget) it.next();
-                       if (!w.isAttached())
-                               client.unregisterPaintable((Paintable) w);
-               }
-       }
-
-       public boolean hasChildComponent(Widget component) {
-               if (widgetToCaptionWrapper.containsKey(component))
-                       return true;
-               return false;
-       }
-
-       public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-               // TODO Auto-generated method stub
-
-       }
-
-       public void updateCaption(Paintable component, UIDL uidl) {
-               CaptionWrapper wrapper = (CaptionWrapper) widgetToCaptionWrapper
-                               .get(component);
-               wrapper.updateCaption(uidl);
-       }
+    /** Widget to captionwrapper map */
+    private HashMap widgetToCaptionWrapper = new HashMap();
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+        if (client.updateComponent(this, uidl, false)) {
+            return;
+        }
+
+        clear();
+        if (uidl.hasAttribute("caption")) {
+            setTitle(uidl.getStringAttribute("caption"));
+        }
+        int row = 0, column = 0;
+
+        ArrayList detachdedPaintables = new ArrayList();
+
+        for (Iterator i = uidl.getChildIterator(); i.hasNext();) {
+            UIDL r = (UIDL) i.next();
+            if ("gr".equals(r.getTag())) {
+                row++;
+                column = 0;
+                for (Iterator j = r.getChildIterator(); j.hasNext();) {
+                    UIDL c = (UIDL) j.next();
+                    if ("gc".equals(c.getTag())) {
+                        column++;
+                        int w;
+                        if (c.hasAttribute("w")) {
+                            w = c.getIntAttribute("w");
+                        } else {
+                            w = 1;
+                        }
+                        ((FlexCellFormatter) getCellFormatter()).setColSpan(
+                                row, column, w);
+
+                        UIDL u = c.getChildUIDL(0);
+                        if (u != null) {
+                            Widget child = client.getWidget(u);
+                            prepareCell(row, column);
+                            Widget oldChild = getWidget(row, column);
+                            if (child != oldChild) {
+                                if (oldChild != null) {
+                                    CaptionWrapper cw = (CaptionWrapper) oldChild;
+                                    detachdedPaintables.add(cw.getPaintable());
+                                    widgetToCaptionWrapper.remove(oldChild);
+                                }
+                                CaptionWrapper wrapper = new CaptionWrapper(
+                                        (Paintable) child, client);
+                                setWidget(row, column, wrapper);
+                                widgetToCaptionWrapper.put(child, wrapper);
+                            }
+                            ((Paintable) child).updateFromUIDL(u, client);
+                        }
+                        column += w - 1;
+                    }
+                }
+            }
+        }
+
+        // for loop detached widgets and unregister them unless they are
+        // attached (case of widget which is moved to another cell)
+        for (Iterator it = detachdedPaintables.iterator(); it.hasNext();) {
+            Widget w = (Widget) it.next();
+            if (!w.isAttached()) {
+                client.unregisterPaintable((Paintable) w);
+            }
+        }
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        if (widgetToCaptionWrapper.containsKey(component)) {
+            return true;
+        }
+        return false;
+    }
+
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        CaptionWrapper wrapper = (CaptionWrapper) widgetToCaptionWrapper
+                .get(component);
+        wrapper.updateCaption(uidl);
+    }
 
 }
index 17cef81ea23876194e3e1d8b2b64388b6fbbffcf..8ffb34ef0a8f032abff00e427b89d3ee3557ad2e 100644 (file)
@@ -25,411 +25,421 @@ import com.itmill.toolkit.terminal.gwt.client.Util;
  */
 public abstract class IOrderedLayout extends ComplexPanel implements Container {
 
-       public static final String CLASSNAME = "i-orderedlayout";
-
-       public static final int ORIENTATION_VERTICAL = 0;
-       public static final int ORIENTATION_HORIZONTAL = 1;
-
-       int orientationMode = ORIENTATION_VERTICAL;
-
-       protected HashMap componentToCaption = new HashMap();
-
-       protected ApplicationConnection client;
-
-       /**
-        * Contains reference to Element where Paintables are wrapped. Normally a TR
-        * or a TBODY element.
-        */
-       protected Element childContainer;
-
-       /*
-        * Elements that provides the Layout interface implementation.
-        */
-       protected Element size;
-       protected Element margin;
-
-       protected Element topMargin = null;
-       protected Element bottomMargin = null;
-
-       private static final String structure = "<div><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"table-layout:fixed;\"><tbody></tbody></table></div>";
-
-       public IOrderedLayout(int orientation) {
-               orientationMode = orientation;
-               constructDOM();
-               setStyleName(CLASSNAME);
-       }
-
-       protected void constructDOM() {
-               size = DOM.createDiv();
-               DOM.setInnerHTML(size, structure);
-               margin = DOM.getFirstChild(size);
-               Element tBody = DOM.getFirstChild(DOM.getFirstChild(margin));
-               if (orientationMode == ORIENTATION_HORIZONTAL) {
-                       childContainer = DOM.createTR();
-                       DOM.appendChild(tBody, childContainer);
-               } else
-                       childContainer = tBody;
-               setElement(size);
-       }
-
-       public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-
-               this.client = client;
-
-               // Ensure correct implementation
-               if (client.updateComponent(this, uidl, false))
-                       return;
-
-               // Set size
-               if (uidl.hasAttribute("width")) {
-                       setWidth(uidl.getStringAttribute("width"));
-                       DOM.setStyleAttribute(DOM.getFirstChild(margin), "width", "100%");
-               } else {
-                       setWidth("");
-                       DOM.setStyleAttribute(DOM.getFirstChild(margin), "width", "");
-               }
-               if (uidl.hasAttribute("height")) {
-                       setHeight(uidl.getStringAttribute("height"));
-                       // TODO override setHeight() method and move these there
-                       DOM.setStyleAttribute(margin, "height", "100%");
-                       DOM.setStyleAttribute(DOM.getFirstChild(margin), "height", "100%");
-               } else {
-                       setHeight("");
-                       DOM.setStyleAttribute(margin, "height", "");
-                       DOM.setStyleAttribute(DOM.getFirstChild(margin), "height", "");
-               }
-
-               ArrayList uidlWidgets = new ArrayList();
-               for (Iterator it = uidl.getChildIterator(); it.hasNext();) {
-                       UIDL uidlForChild = (UIDL) it.next();
-                       Widget child = client.getWidget(uidlForChild);
-                       uidlWidgets.add(child);
-               }
-
-               ArrayList oldWidgets = getPaintables();
-
-               Iterator oldIt = oldWidgets.iterator();
-               Iterator newIt = uidlWidgets.iterator();
-               Iterator newUidl = uidl.getChildIterator();
-
-               Widget oldChild = null;
-               while (newIt.hasNext()) {
-                       Widget child = (Widget) newIt.next();
-                       UIDL childUidl = (UIDL) newUidl.next();
-
-                       if (oldChild == null && oldIt.hasNext()) {
-                               // search for next old Paintable which still exists in layout
-                               // and delete others
-                               while (oldIt.hasNext()) {
-                                       oldChild = (Widget) oldIt.next();
-                                       // now oldChild is an instance of Paintable
-                                       if (uidlWidgets.contains(oldChild))
-                                               break;
-                                       else {
-                                               removePaintable((Paintable) oldChild);
-                                               oldChild = null;
-                                       }
-                               }
-                       }
-                       if (oldChild == null) {
-                               // we are adding components to layout
-                               add(child);
-                       } else if (child == oldChild) {
-                               // child already attached and updated
-                               oldChild = null;
-                       } else if (hasChildComponent(child)) {
-                               // current child has been moved, re-insert before current
-                               // oldChild
-                               // TODO this might be optimized by moving only container element
-                               // to correct position
-                               removeCaption(child);
-                               int index = getWidgetIndex(oldChild);
-                               if (componentToCaption.containsKey(oldChild))
-                                       index--;
-                               remove(child);
-                               this.insert(child, index);
-                       } else {
-                               // insert new child before old one
-                               int index = getWidgetIndex(oldChild);
-                               insert(child, index);
-                       }
-                       ((Paintable) child).updateFromUIDL(childUidl, client);
-               }
-               // remove possibly remaining old Paintable object which were not updated
-               while (oldIt.hasNext()) {
-                       oldChild = (Widget) oldIt.next();
-                       Paintable p = (Paintable) oldChild;
-                       if (!uidlWidgets.contains(p))
-                               removePaintable(p);
-               }
-
-               // Handle component alignments
-               handleAlignments(uidl);
-
-               // Handle layout margins
-               handleMargins(uidl);
-
-       }
-
-       /**
-        * Retuns a list of Paintables currently rendered in layout
-        * 
-        * @return list of Paintable objects
-        */
-       protected ArrayList getPaintables() {
-               ArrayList al = new ArrayList();
-               Iterator it = iterator();
-               while (it.hasNext()) {
-                       Widget w = (Widget) it.next();
-                       if (w instanceof Paintable)
-                               al.add(w);
-               }
-               return al;
-       }
-
-       /**
-        * Removes Paintable from DOM and its reference from ApplicationConnection.
-        * 
-        * Also removes Paintable's Caption if one exists
-        * 
-        * @param p
-        *            Paintable to be removed
-        */
-       public boolean removePaintable(Paintable p) {
-               Caption c = (Caption) componentToCaption.get(p);
-               if (c != null) {
-                       componentToCaption.remove(c);
-                       remove(c);
-               }
-               client.unregisterPaintable(p);
-               return remove((Widget) p);
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see com.itmill.toolkit.terminal.gwt.client.Layout#replaceChildComponent(com.google.gwt.user.client.ui.Widget,
-        *      com.google.gwt.user.client.ui.Widget)
-        */
-       public void replaceChildComponent(Widget from, Widget to) {
-               client.unregisterPaintable((Paintable) from);
-               Caption c = (Caption) componentToCaption.get(from);
-               if (c != null) {
-                       remove(c);
-                       componentToCaption.remove(c);
-               }
-               int index = getWidgetIndex(from);
-               if (index >= 0) {
-                       remove(index);
-                       insert(to, index);
-               }
-       }
-
-       protected void insert(Widget w, int beforeIndex) {
-               if (w instanceof Caption) {
-                       Caption c = (Caption) w;
-                       // captions go into same container element as their
-                       // owners
-                       Element container = DOM.getParent(((UIObject) c.getOwner())
-                                       .getElement());
-                       Element captionContainer = DOM.createDiv();
-                       DOM.insertChild(container, captionContainer, 0);
-                       insert(w, captionContainer, beforeIndex, false);
-               } else {
-                       Element wrapper = createWidgetWrappper();
-                       DOM.insertChild(childContainer, wrapper, beforeIndex);
-                       insert(w, getWidgetContainerFromWrapper(wrapper), beforeIndex,
-                                       false);
-               }
-       }
-
-       protected Element getWidgetContainerFromWrapper(Element wrapper) {
-               switch (orientationMode) {
-               case ORIENTATION_HORIZONTAL:
-                       return wrapper;
-               default:
-                       return DOM.getFirstChild(wrapper);
-               }
-       }
-
-       /**
-        * creates an Element which will contain child widget
-        */
-       protected Element createWidgetWrappper() {
-               Element td = DOM.createTD();
-               // DOM.setStyleAttribute(td, "overflow", "hidden");
-               switch (orientationMode) {
-               case ORIENTATION_HORIZONTAL:
-                       return td;
-               default:
-                       Element tr = DOM.createTR();
-                       DOM.appendChild(tr, td);
-                       return tr;
-               }
-       }
-
-       public boolean hasChildComponent(Widget component) {
-               return getWidgetIndex(component) >= 0;
-       }
-
-       public void updateCaption(Paintable component, UIDL uidl) {
-
-               Caption c = (Caption) componentToCaption.get(component);
-
-               if (Caption.isNeeded(uidl)) {
-                       if (c == null) {
-                               int index = getWidgetIndex((Widget) component);
-                               c = new Caption(component);
-                               insert(c, index);
-                               componentToCaption.put(component, c);
-                       }
-                       c.updateCaption(uidl);
-               } else {
-                       if (c != null) {
-                               remove(c);
-                               componentToCaption.remove(component);
-                       }
-               }
-       }
-
-       public void removeCaption(Widget w) {
-               Caption c = (Caption) componentToCaption.get(w);
-               if (c != null) {
-                       this.remove(c);
-                       componentToCaption.remove(w);
-               }
-       }
-
-       public void add(Widget w) {
-               Element wrapper = createWidgetWrappper();
-               DOM.appendChild(childContainer, wrapper);
-               super.add(w, orientationMode == ORIENTATION_HORIZONTAL ? wrapper : DOM
-                               .getFirstChild(wrapper));
-       }
-
-       public boolean remove(int index) {
-               return remove(getWidget(index));
-       }
-
-       public boolean remove(Widget w) {
-               Element wrapper = DOM.getParent(w.getElement());
-               boolean removed = super.remove(w);
-               if (removed) {
-                       if (!(w instanceof Caption)) {
-                               DOM.removeChild(childContainer,
-                                               orientationMode == ORIENTATION_HORIZONTAL ? wrapper
-                                                               : DOM.getParent(wrapper));
-                       }
-                       return true;
-               }
-               return false;
-       }
-
-       public Widget getWidget(int index) {
-               return getChildren().get(index);
-       }
-
-       public int getWidgetCount() {
-               return getChildren().size();
-       }
-
-       public int getWidgetIndex(Widget child) {
-               return getChildren().indexOf(child);
-       }
-
-       protected void handleMargins(UIDL uidl) {
-               // Modify layout margins
-               String marginClasses = "";
-               MarginInfo margins = new MarginInfo(uidl.getIntAttribute("margins"));
-
-               // Top margin
-               if (margins.hasTop()) {
-                       marginClasses += " " + StyleConstants.LAYOUT_MARGIN_TOP;
-                       if (topMargin == null) {
-                               // We need to insert a new row in to the table
-                               topMargin = createWidgetWrappper();
-                               DOM.appendChild(getWidgetContainerFromWrapper(topMargin), DOM
-                                               .createDiv());
-                               DOM.setElementProperty(topMargin, "className", CLASSNAME
-                                               + "-toppad");
-                               if (orientationMode == ORIENTATION_HORIZONTAL) {
-                                       DOM.setElementAttribute(DOM.getFirstChild(topMargin),
-                                                       "colspan", "" + getPaintables().size());
-                               }
-                               DOM.insertChild(childContainer, topMargin, 0);
-                       }
-               } else {
-                       if (topMargin != null)
-                               DOM.removeChild(childContainer, DOM
-                                               .getFirstChild(childContainer));
-                       topMargin = null;
-               }
-
-               // Right margin
-               if (margins.hasRight())
-                       marginClasses += " " + StyleConstants.LAYOUT_MARGIN_RIGHT;
-
-               // Bottom margin
-               if (margins.hasBottom()) {
-                       marginClasses += " " + StyleConstants.LAYOUT_MARGIN_BOTTOM;
-                       if (bottomMargin == null) {
-                               // We need to insert a new row in to the table
-                               bottomMargin = createWidgetWrappper();
-                               DOM.appendChild(getWidgetContainerFromWrapper(bottomMargin),
-                                               DOM.createDiv());
-                               DOM.setElementProperty(bottomMargin, "className", CLASSNAME
-                                               + "-bottompad");
-                               if (orientationMode == ORIENTATION_HORIZONTAL) {
-                                       DOM.setElementAttribute(DOM.getFirstChild(bottomMargin),
-                                                       "colspan", "" + getPaintables().size());
-                               }
-                               DOM.appendChild(childContainer, bottomMargin);
-                       }
-               } else {
-                       if (bottomMargin != null)
-                               DOM.removeChild(childContainer, DOM.getChild(childContainer,
-                                               DOM.getChildCount(childContainer) - 1));
-                       bottomMargin = null;
-               }
-
-               // Left margin
-               if (margins.hasLeft())
-                       marginClasses += " " + StyleConstants.LAYOUT_MARGIN_LEFT;
-
-               // Add
-               DOM.setElementProperty(margin, "className", marginClasses);
-       }
-
-       protected void handleAlignments(UIDL uidl) {
-               // Component alignments as a comma separated list.
-               // See com.itmill.toolkit.terminal.gwt.client.ui.AlignmentInfo.java for
-               // possible values.
-               int[] alignments = uidl.getIntArrayAttribute("alignments");
-               int alignmentIndex = 0;
-               // Insert alignment attributes
-               Iterator it = getPaintables().iterator();
-               while (it.hasNext()) {
-
-                       // Calculate alignment info
-                       AlignmentInfo ai = new AlignmentInfo(alignments[alignmentIndex++]);
-
-                       Element td = DOM.getParent(((Widget) it.next()).getElement());
-                       if (Util.isIE()) {
-                               DOM.setElementAttribute(td, "vAlign", ai
-                                               .getVerticalAlignment());
-                       } else {
-                               DOM.setStyleAttribute(td, "verticalAlign", ai
-                                               .getVerticalAlignment());
-                       }
-                       // TODO use one-cell table to implement horizontal alignments
-                       if (Util.isIE()) {
-                               DOM.setElementAttribute(td, "align", ai
-                                               .getHorizontalAlignment());
-                       } else {
-                               DOM.setStyleAttribute(td, "textAlign", ai
-                                               .getHorizontalAlignment());
-                       }
-               }
-       }
+    public static final String CLASSNAME = "i-orderedlayout";
+
+    public static final int ORIENTATION_VERTICAL = 0;
+    public static final int ORIENTATION_HORIZONTAL = 1;
+
+    int orientationMode = ORIENTATION_VERTICAL;
+
+    protected HashMap componentToCaption = new HashMap();
+
+    protected ApplicationConnection client;
+
+    /**
+     * Contains reference to Element where Paintables are wrapped. Normally a TR
+     * or a TBODY element.
+     */
+    protected Element childContainer;
+
+    /*
+     * Elements that provides the Layout interface implementation.
+     */
+    protected Element size;
+    protected Element margin;
+
+    protected Element topMargin = null;
+    protected Element bottomMargin = null;
+
+    private static final String structure = "<div><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"table-layout:fixed;\"><tbody></tbody></table></div>";
+
+    public IOrderedLayout(int orientation) {
+        orientationMode = orientation;
+        constructDOM();
+        setStyleName(CLASSNAME);
+    }
+
+    protected void constructDOM() {
+        size = DOM.createDiv();
+        DOM.setInnerHTML(size, structure);
+        margin = DOM.getFirstChild(size);
+        Element tBody = DOM.getFirstChild(DOM.getFirstChild(margin));
+        if (orientationMode == ORIENTATION_HORIZONTAL) {
+            childContainer = DOM.createTR();
+            DOM.appendChild(tBody, childContainer);
+        } else {
+            childContainer = tBody;
+        }
+        setElement(size);
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+        this.client = client;
+
+        // Ensure correct implementation
+        if (client.updateComponent(this, uidl, false)) {
+            return;
+        }
+
+        // Set size
+        if (uidl.hasAttribute("width")) {
+            setWidth(uidl.getStringAttribute("width"));
+            DOM.setStyleAttribute(DOM.getFirstChild(margin), "width", "100%");
+        } else {
+            setWidth("");
+            DOM.setStyleAttribute(DOM.getFirstChild(margin), "width", "");
+        }
+        if (uidl.hasAttribute("height")) {
+            setHeight(uidl.getStringAttribute("height"));
+            // TODO override setHeight() method and move these there
+            DOM.setStyleAttribute(margin, "height", "100%");
+            DOM.setStyleAttribute(DOM.getFirstChild(margin), "height", "100%");
+        } else {
+            setHeight("");
+            DOM.setStyleAttribute(margin, "height", "");
+            DOM.setStyleAttribute(DOM.getFirstChild(margin), "height", "");
+        }
+
+        ArrayList uidlWidgets = new ArrayList();
+        for (Iterator it = uidl.getChildIterator(); it.hasNext();) {
+            UIDL uidlForChild = (UIDL) it.next();
+            Widget child = client.getWidget(uidlForChild);
+            uidlWidgets.add(child);
+        }
+
+        ArrayList oldWidgets = getPaintables();
+
+        Iterator oldIt = oldWidgets.iterator();
+        Iterator newIt = uidlWidgets.iterator();
+        Iterator newUidl = uidl.getChildIterator();
+
+        Widget oldChild = null;
+        while (newIt.hasNext()) {
+            Widget child = (Widget) newIt.next();
+            UIDL childUidl = (UIDL) newUidl.next();
+
+            if (oldChild == null && oldIt.hasNext()) {
+                // search for next old Paintable which still exists in layout
+                // and delete others
+                while (oldIt.hasNext()) {
+                    oldChild = (Widget) oldIt.next();
+                    // now oldChild is an instance of Paintable
+                    if (uidlWidgets.contains(oldChild)) {
+                        break;
+                    } else {
+                        removePaintable((Paintable) oldChild);
+                        oldChild = null;
+                    }
+                }
+            }
+            if (oldChild == null) {
+                // we are adding components to layout
+                add(child);
+            } else if (child == oldChild) {
+                // child already attached and updated
+                oldChild = null;
+            } else if (hasChildComponent(child)) {
+                // current child has been moved, re-insert before current
+                // oldChild
+                // TODO this might be optimized by moving only container element
+                // to correct position
+                removeCaption(child);
+                int index = getWidgetIndex(oldChild);
+                if (componentToCaption.containsKey(oldChild)) {
+                    index--;
+                }
+                remove(child);
+                this.insert(child, index);
+            } else {
+                // insert new child before old one
+                int index = getWidgetIndex(oldChild);
+                insert(child, index);
+            }
+            ((Paintable) child).updateFromUIDL(childUidl, client);
+        }
+        // remove possibly remaining old Paintable object which were not updated
+        while (oldIt.hasNext()) {
+            oldChild = (Widget) oldIt.next();
+            Paintable p = (Paintable) oldChild;
+            if (!uidlWidgets.contains(p)) {
+                removePaintable(p);
+            }
+        }
+
+        // Handle component alignments
+        handleAlignments(uidl);
+
+        // Handle layout margins
+        handleMargins(uidl);
+
+    }
+
+    /**
+     * Retuns a list of Paintables currently rendered in layout
+     * 
+     * @return list of Paintable objects
+     */
+    protected ArrayList getPaintables() {
+        ArrayList al = new ArrayList();
+        Iterator it = iterator();
+        while (it.hasNext()) {
+            Widget w = (Widget) it.next();
+            if (w instanceof Paintable) {
+                al.add(w);
+            }
+        }
+        return al;
+    }
+
+    /**
+     * Removes Paintable from DOM and its reference from ApplicationConnection.
+     * 
+     * Also removes Paintable's Caption if one exists
+     * 
+     * @param p
+     *                Paintable to be removed
+     */
+    public boolean removePaintable(Paintable p) {
+        Caption c = (Caption) componentToCaption.get(p);
+        if (c != null) {
+            componentToCaption.remove(c);
+            remove(c);
+        }
+        client.unregisterPaintable(p);
+        return remove((Widget) p);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.itmill.toolkit.terminal.gwt.client.Layout#replaceChildComponent(com.google.gwt.user.client.ui.Widget,
+     *      com.google.gwt.user.client.ui.Widget)
+     */
+    public void replaceChildComponent(Widget from, Widget to) {
+        client.unregisterPaintable((Paintable) from);
+        Caption c = (Caption) componentToCaption.get(from);
+        if (c != null) {
+            remove(c);
+            componentToCaption.remove(c);
+        }
+        int index = getWidgetIndex(from);
+        if (index >= 0) {
+            remove(index);
+            insert(to, index);
+        }
+    }
+
+    protected void insert(Widget w, int beforeIndex) {
+        if (w instanceof Caption) {
+            Caption c = (Caption) w;
+            // captions go into same container element as their
+            // owners
+            Element container = DOM.getParent(((UIObject) c.getOwner())
+                    .getElement());
+            Element captionContainer = DOM.createDiv();
+            DOM.insertChild(container, captionContainer, 0);
+            insert(w, captionContainer, beforeIndex, false);
+        } else {
+            Element wrapper = createWidgetWrappper();
+            DOM.insertChild(childContainer, wrapper, beforeIndex);
+            insert(w, getWidgetContainerFromWrapper(wrapper), beforeIndex,
+                    false);
+        }
+    }
+
+    protected Element getWidgetContainerFromWrapper(Element wrapper) {
+        switch (orientationMode) {
+        case ORIENTATION_HORIZONTAL:
+            return wrapper;
+        default:
+            return DOM.getFirstChild(wrapper);
+        }
+    }
+
+    /**
+     * creates an Element which will contain child widget
+     */
+    protected Element createWidgetWrappper() {
+        Element td = DOM.createTD();
+        // DOM.setStyleAttribute(td, "overflow", "hidden");
+        switch (orientationMode) {
+        case ORIENTATION_HORIZONTAL:
+            return td;
+        default:
+            Element tr = DOM.createTR();
+            DOM.appendChild(tr, td);
+            return tr;
+        }
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        return getWidgetIndex(component) >= 0;
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+
+        Caption c = (Caption) componentToCaption.get(component);
+
+        if (Caption.isNeeded(uidl)) {
+            if (c == null) {
+                int index = getWidgetIndex((Widget) component);
+                c = new Caption(component, client);
+                insert(c, index);
+                componentToCaption.put(component, c);
+            }
+            c.updateCaption(uidl);
+        } else {
+            if (c != null) {
+                remove(c);
+                componentToCaption.remove(component);
+            }
+        }
+    }
+
+    public void removeCaption(Widget w) {
+        Caption c = (Caption) componentToCaption.get(w);
+        if (c != null) {
+            this.remove(c);
+            componentToCaption.remove(w);
+        }
+    }
+
+    public void add(Widget w) {
+        Element wrapper = createWidgetWrappper();
+        DOM.appendChild(childContainer, wrapper);
+        super.add(w, orientationMode == ORIENTATION_HORIZONTAL ? wrapper : DOM
+                .getFirstChild(wrapper));
+    }
+
+    public boolean remove(int index) {
+        return remove(getWidget(index));
+    }
+
+    public boolean remove(Widget w) {
+        Element wrapper = DOM.getParent(w.getElement());
+        boolean removed = super.remove(w);
+        if (removed) {
+            if (!(w instanceof Caption)) {
+                DOM.removeChild(childContainer,
+                        orientationMode == ORIENTATION_HORIZONTAL ? wrapper
+                                : DOM.getParent(wrapper));
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public Widget getWidget(int index) {
+        return getChildren().get(index);
+    }
+
+    public int getWidgetCount() {
+        return getChildren().size();
+    }
+
+    public int getWidgetIndex(Widget child) {
+        return getChildren().indexOf(child);
+    }
+
+    protected void handleMargins(UIDL uidl) {
+        // Modify layout margins
+        String marginClasses = "";
+        MarginInfo margins = new MarginInfo(uidl.getIntAttribute("margins"));
+
+        // Top margin
+        if (margins.hasTop()) {
+            marginClasses += " " + StyleConstants.LAYOUT_MARGIN_TOP;
+            if (topMargin == null) {
+                // We need to insert a new row in to the table
+                topMargin = createWidgetWrappper();
+                DOM.appendChild(getWidgetContainerFromWrapper(topMargin), DOM
+                        .createDiv());
+                DOM.setElementProperty(topMargin, "className", CLASSNAME
+                        + "-toppad");
+                if (orientationMode == ORIENTATION_HORIZONTAL) {
+                    DOM.setElementAttribute(DOM.getFirstChild(topMargin),
+                            "colspan", "" + getPaintables().size());
+                }
+                DOM.insertChild(childContainer, topMargin, 0);
+            }
+        } else {
+            if (topMargin != null) {
+                DOM.removeChild(childContainer, DOM
+                        .getFirstChild(childContainer));
+            }
+            topMargin = null;
+        }
+
+        // Right margin
+        if (margins.hasRight()) {
+            marginClasses += " " + StyleConstants.LAYOUT_MARGIN_RIGHT;
+        }
+
+        // Bottom margin
+        if (margins.hasBottom()) {
+            marginClasses += " " + StyleConstants.LAYOUT_MARGIN_BOTTOM;
+            if (bottomMargin == null) {
+                // We need to insert a new row in to the table
+                bottomMargin = createWidgetWrappper();
+                DOM.appendChild(getWidgetContainerFromWrapper(bottomMargin),
+                        DOM.createDiv());
+                DOM.setElementProperty(bottomMargin, "className", CLASSNAME
+                        + "-bottompad");
+                if (orientationMode == ORIENTATION_HORIZONTAL) {
+                    DOM.setElementAttribute(DOM.getFirstChild(bottomMargin),
+                            "colspan", "" + getPaintables().size());
+                }
+                DOM.appendChild(childContainer, bottomMargin);
+            }
+        } else {
+            if (bottomMargin != null) {
+                DOM.removeChild(childContainer, DOM.getChild(childContainer,
+                        DOM.getChildCount(childContainer) - 1));
+            }
+            bottomMargin = null;
+        }
+
+        // Left margin
+        if (margins.hasLeft()) {
+            marginClasses += " " + StyleConstants.LAYOUT_MARGIN_LEFT;
+        }
+
+        // Add
+        DOM.setElementProperty(margin, "className", marginClasses);
+    }
+
+    protected void handleAlignments(UIDL uidl) {
+        // Component alignments as a comma separated list.
+        // See com.itmill.toolkit.terminal.gwt.client.ui.AlignmentInfo.java for
+        // possible values.
+        int[] alignments = uidl.getIntArrayAttribute("alignments");
+        int alignmentIndex = 0;
+        // Insert alignment attributes
+        Iterator it = getPaintables().iterator();
+        while (it.hasNext()) {
+
+            // Calculate alignment info
+            AlignmentInfo ai = new AlignmentInfo(alignments[alignmentIndex++]);
+
+            Element td = DOM.getParent(((Widget) it.next()).getElement());
+            if (Util.isIE()) {
+                DOM
+                        .setElementAttribute(td, "vAlign", ai
+                                .getVerticalAlignment());
+            } else {
+                DOM.setStyleAttribute(td, "verticalAlign", ai
+                        .getVerticalAlignment());
+            }
+            // TODO use one-cell table to implement horizontal alignments
+            if (Util.isIE()) {
+                DOM.setElementAttribute(td, "align", ai
+                        .getHorizontalAlignment());
+            } else {
+                DOM.setStyleAttribute(td, "textAlign", ai
+                        .getHorizontalAlignment());
+            }
+        }
+    }
 
 }