]> source.dussan.org Git - vaadin-framework.git/commitdiff
Major layout renewals. GridLayout now totally absolutely positioned, all scrollable...
authorMatti Tahvonen <matti.tahvonen@itmill.com>
Tue, 21 Oct 2008 13:54:04 +0000 (13:54 +0000)
committerMatti Tahvonen <matti.tahvonen@itmill.com>
Tue, 21 Oct 2008 13:54:04 +0000 (13:54 +0000)
svn changeset:5690/svn branch:trunk

src/com/itmill/toolkit/demo/featurebrowser/LabelExample.java
src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java
src/com/itmill/toolkit/terminal/gwt/client/ui/IAccordion.java
src/com/itmill/toolkit/terminal/gwt/client/ui/IGridLayout.java
src/com/itmill/toolkit/terminal/gwt/client/ui/IPanel.java
src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheet.java
src/com/itmill/toolkit/terminal/gwt/client/ui/layout/ChildComponentContainer.java

index 8f96602cdc3ec2ed963f1e464232d8b78ed78af3..2747c1fdfe81717451ecf381f557ff7f8f1ec3bd 100644 (file)
@@ -4,10 +4,10 @@
 \r
 package com.itmill.toolkit.demo.featurebrowser;\r
 \r
+import com.itmill.toolkit.ui.Component;\r
 import com.itmill.toolkit.ui.CustomComponent;\r
 import com.itmill.toolkit.ui.GridLayout;\r
 import com.itmill.toolkit.ui.Label;\r
-import com.itmill.toolkit.ui.OrderedLayout;\r
 import com.itmill.toolkit.ui.Panel;\r
 \r
 /**\r
@@ -28,68 +28,61 @@ public class LabelExample extends CustomComponent {
             + "       This is an indented row. \n       Same indentation here.";\r
 \r
     public LabelExample() {\r
-\r
-        final OrderedLayout main = new OrderedLayout();\r
-        main.setSizeFull();\r
-        main.setMargin(true);\r
-        setSizeFull();\r
-        setCompositionRoot(main);\r
-\r
         final GridLayout g = new GridLayout(2, 4);\r
-        g.setSizeFull();\r
-        main.addComponent(g);\r
+        g.setMargin(true);\r
+        setCompositionRoot(g);\r
+        g.setWidth("100%");\r
+\r
         // plain w/o caption\r
-        Panel p = new Panel("Plain");\r
-        p.setWidth("100%");\r
-        p.getLayout().setWidth("100%");\r
-        p.setStyleName(Panel.STYLE_LIGHT);\r
+        Panel p = getExpamplePanel("Plain");\r
         Label l = new Label("A plain label without caption.");\r
         p.addComponent(l);\r
         g.addComponent(p);\r
         // plain w/ caption\r
-        p = new Panel("Plain w/ caption + tooltip");\r
-        p.setWidth("100%");\r
-        p.getLayout().setWidth("100%");\r
-        p.setStyleName(Panel.STYLE_LIGHT);\r
+        p = getExpamplePanel("Plain w/ caption + tooltip");\r
         l = new Label("A plain label with caption.");\r
         l.setCaption("Label caption");\r
         l.setDescription("This is a description (tooltip) for the label.");\r
         p.addComponent(l);\r
         g.addComponent(p);\r
         // plain w/ xhtml\r
-        p = new Panel("Plain w/ XHTML content");\r
-        p.setWidth("100%");\r
-        p.getLayout().setWidth("100%");\r
-        p.setStyleName(Panel.STYLE_LIGHT);\r
+        p = getExpamplePanel("Plain w/ XHTML content");\r
         l = new Label(xhtml);\r
         p.addComponent(l);\r
         g.addComponent(p);\r
         // xhtml w/ xhtml\r
-        p = new Panel("XHTML-mode w/ XHTML content");\r
-        p.setWidth("100%");\r
-        p.getLayout().setWidth("100%");\r
-        p.setStyleName(Panel.STYLE_LIGHT);\r
+        p = getExpamplePanel("XHTML-mode w/ XHTML content");\r
         l = new Label(xhtml);\r
         l.setContentMode(Label.CONTENT_XHTML);\r
         p.addComponent(l);\r
         g.addComponent(p);\r
         // plain w/ preformatted\r
-        p = new Panel("Plain w/ preformatted content");\r
-        p.setWidth("100%");\r
-        p.getLayout().setWidth("100%");\r
-        p.setStyleName(Panel.STYLE_LIGHT);\r
+        p = getExpamplePanel("Plain w/ preformatted content");\r
         l = new Label(pre);\r
         p.addComponent(l);\r
         g.addComponent(p);\r
         // preformatted w/ preformatted\r
-        p = new Panel("Preformatted-mode w/ preformatted content");\r
-        p.setWidth("100%");\r
-        p.getLayout().setWidth("100%");\r
-        p.setStyleName(Panel.STYLE_LIGHT);\r
+        p = getExpamplePanel("Preformatted-mode w/ preformatted content");\r
         l = new Label(pre);\r
         l.setContentMode(Label.CONTENT_PREFORMATTED);\r
         p.addComponent(l);\r
         g.addComponent(p);\r
 \r
     }\r
+\r
+    private Panel getExpamplePanel(String caption) {\r
+        Panel p = new Panel(caption) {\r
+\r
+            @Override\r
+            public void addComponent(Component c) {\r
+                c.setWidth("100%");\r
+                super.addComponent(c);\r
+            }\r
+\r
+        };\r
+        p.addStyleName(Panel.STYLE_LIGHT);\r
+        p.setWidth("100%");\r
+        p.getLayout().setWidth("100%");\r
+        return p;\r
+    }\r
 }\r
index d73bbe1d74373b9ec781939b3754b9feb63a0033..e4f629180e77d664fad1c11f4c396a0fefd4a82e 100644 (file)
@@ -210,14 +210,7 @@ public class DefaultWidgetSet implements WidgetSet {
         } else if ("link".equals(tag)) {
             return "com.itmill.toolkit.terminal.gwt.client.ui.ILink";
         } else if ("gridlayout".equals(tag)) {
-            if (uidl.hasAttribute("height")) {
-                // height needs to be set to use sizeable grid layout, with
-                // width only or no size at all it fails to render properly.
-                return "com.itmill.toolkit.terminal.gwt.client.ui.absolutegrid.ISizeableGridLayout";
-            } else {
-                // Fall back to GWT FlexTable based implementation.
-                return "com.itmill.toolkit.terminal.gwt.client.ui.IGridLayout";
-            }
+            return "com.itmill.toolkit.terminal.gwt.client.ui.IGridLayout";
         } else if ("tree".equals(tag)) {
             return "com.itmill.toolkit.terminal.gwt.client.ui.ITree";
         } else if ("select".equals(tag)) {
index 01ede8079cfc37f37b27d4a039e2e130b79b240d..00788b2972985a4ed80b2c993ac61dad51a62b76 100644 (file)
@@ -246,7 +246,7 @@ public class IAccordion extends ITabsheetBase implements
 
         public void open() {
             open = true;
-            DOM.setStyleAttribute(content, "position", "");
+            DOM.setStyleAttribute(content, "position", "relative");
             DOM.setStyleAttribute(content, "top", "");
             DOM.setStyleAttribute(content, "left", "");
             DOM.setStyleAttribute(content, "visibility", "");
index e7d4dd3c82e27f80882f5dedf9489c03ab64eeff..c868cc5a1fa26434c1911b0e786dad193562c94b 100644 (file)
 
 package com.itmill.toolkit.terminal.gwt.client.ui;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Set;
+import java.util.Map.Entry;
 
-import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.DeferredCommand;
 import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.ui.FlexTable;
-import com.google.gwt.user.client.ui.HasHorizontalAlignment;
-import com.google.gwt.user.client.ui.HasVerticalAlignment;
+import com.google.gwt.user.client.ui.AbsolutePanel;
 import com.google.gwt.user.client.ui.SimplePanel;
 import com.google.gwt.user.client.ui.Widget;
-import com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant;
-import com.google.gwt.user.client.ui.HasVerticalAlignment.VerticalAlignmentConstant;
 import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
-import com.itmill.toolkit.terminal.gwt.client.BrowserInfo;
 import com.itmill.toolkit.terminal.gwt.client.Container;
-import com.itmill.toolkit.terminal.gwt.client.ContainerResizedListener;
-import com.itmill.toolkit.terminal.gwt.client.ICaptionWrapper;
 import com.itmill.toolkit.terminal.gwt.client.Paintable;
 import com.itmill.toolkit.terminal.gwt.client.RenderSpace;
 import com.itmill.toolkit.terminal.gwt.client.StyleConstants;
 import com.itmill.toolkit.terminal.gwt.client.UIDL;
+import com.itmill.toolkit.terminal.gwt.client.ui.layout.CellBasedLayout;
+import com.itmill.toolkit.terminal.gwt.client.ui.layout.ChildComponentContainer;
 
-public class IGridLayout extends SimplePanel implements Paintable, Container,
-        ContainerResizedListener {
+public class IGridLayout extends SimplePanel implements Paintable, Container {
 
     public static final String CLASSNAME = "i-gridlayout";
 
-    private Grid grid = new Grid();
-
     private boolean needsLayout = false;
 
-    private boolean needsFF2Hack = BrowserInfo.get().isFF2();
-
     private Element margin = DOM.createDiv();
 
-    private Element meterElement;
+    private final AbsolutePanel canvas = new AbsolutePanel();
+
+    private ApplicationConnection client;
+
+    protected HashMap<Widget, ChildComponentContainer> widgetToComponentContainer = new HashMap<Widget, ChildComponentContainer>();
+
+    private HashMap<Paintable, Cell> paintableToCell = new HashMap<Paintable, Cell>();
+
+    private int spacingPixels;
+
+    private int[] columnWidths;
+    private int[] rowHeights;
+
+    private String height;
 
     private String width;
 
-    private ApplicationConnection client;
+    private int[] colExpandRatioArray;
+
+    private int[] rowExpandRatioArray;
+
+    private int[] minColumnWidths;
+
+    private int[] minRowHeights;
+
+    private boolean rendering;
 
     public IGridLayout() {
         super();
-        DOM.appendChild(getElement(), margin);
-        DOM.setStyleAttribute(getElement(), "overflow", "hidden");
+        getElement().getStyle().setProperty("overflow", "hidden");
+        getElement().appendChild(margin);
         setStyleName(CLASSNAME);
-        setWidget(grid);
+        setWidget(canvas);
     }
 
     protected Element getContainerElement() {
         return margin;
     }
 
-    public void setWidth(String width) {
-        this.width = width;
-        if (width != null && !width.equals("")) {
-            needsLayout = true;
-        } else {
-            needsLayout = false;
-            grid.setWidth("");
-        }
-    }
-
     public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        rendering = true;
         this.client = client;
 
         if (client.updateComponent(this, uidl, true)) {
+            rendering = false;
             return;
         }
-        final MarginInfo margins = new MarginInfo(uidl
-                .getIntAttribute("margins"));
 
-        setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_TOP,
-                margins.hasTop());
-        setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT,
-                margins.hasRight());
-        setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM,
-                margins.hasBottom());
-        setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_LEFT,
-                margins.hasLeft());
+        handleMargins(uidl);
+        detectSpacing(uidl);
 
-        setStyleName(margin, CLASSNAME + "-" + "spacing", uidl
-                .hasAttribute("spacing"));
-        iLayout();
-        grid.updateFromUIDL(uidl, client);
-    }
+        int cols = uidl.getIntAttribute("w");
+        int rows = uidl.getIntAttribute("h");
 
-    public boolean hasChildComponent(Widget component) {
-        return grid.hasChildComponent(component);
-    }
+        columnWidths = new int[cols];
+        rowHeights = new int[rows];
 
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        grid.replaceChildComponent(oldComponent, newComponent);
-    }
+        if (cells == null) {
+            cells = new Cell[cols][rows];
+        } else if (cells.length != cols || cells[0].length != rows) {
+            LinkedList<Cell> orphaned = new LinkedList<Cell>();
+            Cell[][] newCells = new Cell[cols][rows];
+            for (int i = 0; i < cells.length; i++) {
+                for (int j = 0; j < cells[i].length; j++) {
+                    if (i < cols && j < rows) {
+                        newCells[i][j] = cells[i][j];
+                    }
+                }
+            }
+            cells = newCells;
+            // TODO clean orphaned list
+            for (Iterator iterator = orphaned.iterator(); iterator.hasNext();) {
+                Cell cell = (Cell) iterator.next();
+            }
+        }
 
-    public void updateCaption(Paintable component, UIDL uidl) {
-        grid.updateCaption(component, uidl);
-    }
+        HashMap<Widget, ChildComponentContainer> nonRenderedWidgets = (HashMap<Widget, ChildComponentContainer>) widgetToComponentContainer
+                .clone();
+
+        final int[] alignments = uidl.getIntArrayAttribute("alignments");
+        int alignmentIndex = 0;
+        int column;
+        int row = 0;
+
+        LinkedList<Cell> pendingCells = new LinkedList<Cell>();
+
+        LinkedList<Cell> relativeHeighted = new LinkedList<Cell>();
+
+        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
+            final UIDL r = (UIDL) i.next();
+            if ("gr".equals(r.getTag())) {
+                column = 0;
+                for (final Iterator j = r.getChildIterator(); j.hasNext();) {
+                    final UIDL c = (UIDL) j.next();
+                    if ("gc".equals(c.getTag())) {
+                        Cell cell = getCell(c);
+                        if (cell.hasContent()) {
+                            boolean rendered = cell.renderIfNoRelativeWidth();
+                            cell.alignment = alignments[alignmentIndex++];
+                            column += cell.colspan;
+                            if (!rendered) {
+                                pendingCells.add(cell);
+                            }
 
-    public class Grid extends FlexTable implements Paintable, Container {
+                            if (cell.colspan > 1) {
+                                storeColSpannedCell(cell);
+                            } else if (rendered) {
+                                // strore non-colspanned widths to columnWidth
+                                // array
+                                if (columnWidths[cell.col] < cell.getWidth()) {
+                                    columnWidths[cell.col] = cell.getWidth();
+                                }
+                            }
+                            if (cell.hasRelativeHeight()) {
+                                relativeHeighted.add(cell);
+                            }
+                        }
+                    }
+                }
+                row++;
+            }
+        }
 
-        /** Widget to captionwrapper map */
-        private final HashMap widgetToCaptionWrapper = new HashMap();
+        distributeColSpanWidths();
+        colExpandRatioArray = uidl.getIntArrayAttribute("colExpand");
+        rowExpandRatioArray = uidl.getIntArrayAttribute("rowExpand");
 
-        public Grid() {
-            super();
-            setStyleName(CLASSNAME + "-grid");
+        minColumnWidths = cloneArray(columnWidths);
+        expandColumns();
+
+        renderRemainingComponentsWithNoRelativeHeight(pendingCells);
+
+        detectRowHeights();
+
+        minRowHeights = cloneArray(rowHeights);
+        expandRows();
+
+        renderRemainingComponents(pendingCells);
+
+        for (Cell cell : relativeHeighted) {
+            Widget widget2 = cell.cc.getWidget();
+            client.handleComponentRelativeSize(widget2);
         }
 
-        public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        layoutCells();
+
+        for (Entry cc : nonRenderedWidgets.entrySet()) {
+            // TODO remove components
+        }
 
-            int row = 0, column = 0;
+        rendering = false;
 
-            final ArrayList oldWidgetWrappers = new ArrayList();
-            for (final Iterator iterator = iterator(); iterator.hasNext();) {
-                oldWidgetWrappers.add(iterator.next());
+        // canvas.add(uidl.print_r());
+    }
+
+    private static int[] cloneArray(int[] toBeCloned) {
+        int[] clone = new int[toBeCloned.length];
+        for (int i = 0; i < clone.length; i++) {
+            clone[i] = toBeCloned[i];
+        }
+        return clone;
+    }
+
+    private void expandRows() {
+        if (!"".equals(height)) {
+            int usedSpace = minRowHeights[0];
+            for (int i = 1; i < minRowHeights.length; i++) {
+                usedSpace += spacingPixels + minRowHeights[i];
             }
+            int availableSpace = getOffsetHeight() - marginTopAndBottom;
+            int excessSpace = availableSpace - usedSpace;
+            int distributed = 0;
+            if (excessSpace > 0) {
+                for (int i = 0; i < rowHeights.length; i++) {
+                    int ew = excessSpace * rowExpandRatioArray[i] / 1000;
+                    rowHeights[i] = minRowHeights[i] + ew;
+                    distributed += ew;
+                }
+                excessSpace -= distributed;
+                int c = 0;
+                while (excessSpace > 0) {
+                    rowHeights[c % rowHeights.length]++;
+                    excessSpace--;
+                    c++;
+                }
+            }
+        }
+    }
 
-            /* Clear() removes all widgets but leaves the tr and td tags */
-            clear();
+    @Override
+    public void setHeight(String height) {
+        super.setHeight(height);
+        this.height = height;
+        if (!rendering) {
+            expandRows();
+            layoutCells();
+        }
+    }
 
-            boolean structuralChange = uidl
-                    .getBooleanAttribute("structuralChange");
+    @Override
+    public void setWidth(String width) {
+        super.setWidth(width);
+        this.width = width;
+        if (!rendering) {
+            expandColumns();
+            layoutCells();
+        }
+    }
 
-            /*
-             * If a row has been inserted or removed at the middle of the table
-             * we need to remove all old tr and td tags.
-             */
-            if (structuralChange) {
-                while (getRowCount() > 0) {
-                    removeRow(0);
+    private void expandColumns() {
+        if (!"".equals(width)) {
+            int usedSpace = minColumnWidths[0];
+            for (int i = 1; i < minColumnWidths.length; i++) {
+                usedSpace += spacingPixels + minColumnWidths[i];
+            }
+            canvas.setWidth("");
+            int availableSpace = canvas.getOffsetWidth();
+            int excessSpace = availableSpace - usedSpace;
+            int distributed = 0;
+            if (excessSpace > 0) {
+                for (int i = 0; i < columnWidths.length; i++) {
+                    int ew = excessSpace * colExpandRatioArray[i] / 1000;
+                    columnWidths[i] = minColumnWidths[i] + ew;
+                    distributed += ew;
+                }
+                excessSpace -= distributed;
+                int c = 0;
+                while (excessSpace > 0) {
+                    columnWidths[c % columnWidths.length]++;
+                    excessSpace--;
+                    c++;
                 }
             }
+        }
+    }
 
-            final int[] alignments = uidl.getIntArrayAttribute("alignments");
-            int alignmentIndex = 0;
-
-            for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
-                final UIDL r = (UIDL) i.next();
-                if ("gr".equals(r.getTag())) {
-                    column = 0;
-                    for (final Iterator j = r.getChildIterator(); j.hasNext();) {
-                        final UIDL c = (UIDL) j.next();
-                        if ("gc".equals(c.getTag())) {
-                            prepareCell(row, column);
-
-                            // Set cell width
-                            int w;
-                            if (c.hasAttribute("w")) {
-                                w = c.getIntAttribute("w");
-                            } else {
-                                w = 1;
-                            }
+    private void layoutCells() {
+        int x = 0;
+        int y = 0;
+        for (int i = 0; i < cells.length; i++) {
+            y = 0;
+            for (int j = 0; j < cells[i].length; j++) {
+                Cell cell = cells[i][j];
+                if (cell != null) {
+                    cell.layout(x, y);
+                }
+                y += rowHeights[j] + spacingPixels;
+            }
+            x += columnWidths[i] + spacingPixels;
+        }
+        // ensure canvas is right size
+        canvas.setPixelSize(x - spacingPixels, y - spacingPixels);
+    }
 
-                            FlexCellFormatter formatter = (FlexCellFormatter) getCellFormatter();
+    private void renderRemainingComponents(LinkedList<Cell> pendingCells) {
+        for (Cell cell : pendingCells) {
+            cell.render();
+        }
+    }
 
-                            // set col span
-                            formatter.setColSpan(row, column, w);
+    private void detectRowHeights() {
 
-                            String styleNames = CLASSNAME + "-cell";
-                            if (column == 0) {
-                                styleNames += " " + CLASSNAME + "-firstcol";
-                            }
-                            if (row == 0) {
-                                styleNames += " " + CLASSNAME + "-firstrow";
-                            }
-                            formatter.setStyleName(row, column, styleNames);
-
-                            // Set cell height
-                            int h;
-                            if (c.hasAttribute("h")) {
-                                h = c.getIntAttribute("h");
-                            } else {
-                                h = 1;
-                            }
-                            ((FlexCellFormatter) getCellFormatter())
-                                    .setRowSpan(row, column, h);
-
-                            final UIDL u = c.getChildUIDL(0);
-                            if (u != null) {
-
-                                AlignmentInfo alignmentInfo = new AlignmentInfo(
-                                        alignments[alignmentIndex++]);
-
-                                VerticalAlignmentConstant va;
-                                if (alignmentInfo.isBottom()) {
-                                    va = HasVerticalAlignment.ALIGN_BOTTOM;
-                                } else if (alignmentInfo.isTop()) {
-                                    va = HasVerticalAlignment.ALIGN_TOP;
-                                } else {
-                                    va = HasVerticalAlignment.ALIGN_MIDDLE;
-                                }
+        // collect min rowheight from non-rowspanned cells
+        for (int i = 0; i < cells.length; i++) {
+            for (int j = 0; j < cells[i].length; j++) {
+                Cell cell = cells[i][j];
+                if (cell != null) {
+                    if (cell.rowspan == 1) {
+                        if (rowHeights[j] < cell.getHeight()) {
+                            rowHeights[j] = cell.getHeight();
+                        }
+                    } else {
+                        storeRowSpannedCell(cell);
+                    }
+                }
+            }
+        }
+        distributeRowSpanHeights();
 
-                                HorizontalAlignmentConstant ha;
+    }
 
-                                if (alignmentInfo.isLeft()) {
-                                    ha = HasHorizontalAlignment.ALIGN_LEFT;
-                                } else if (alignmentInfo.isHorizontalCenter()) {
-                                    ha = HasHorizontalAlignment.ALIGN_CENTER;
-                                } else {
-                                    ha = HasHorizontalAlignment.ALIGN_RIGHT;
-                                }
+    private void storeRowSpannedCell(Cell cell) {
+        SpanList l = null;
+        for (SpanList list : rowSpans) {
+            if (list.span < cell.rowspan) {
+                continue;
+            } else {
+                // insert before this
+                l = list;
+                break;
+            }
+        }
+        if (l == null) {
+            l = new SpanList(cell.rowspan);
+            rowSpans.add(l);
+        } else if (l.span != cell.rowspan) {
+            SpanList newL = new SpanList(cell.rowspan);
+            rowSpans.add(rowSpans.indexOf(l), newL);
+            l = newL;
+        }
+        l.cells.add(cell);
+    }
 
-                                formatter.setAlignment(row, column, ha, va);
-
-                                final Paintable child = client.getPaintable(u);
-                                ICaptionWrapper wr;
-                                if (widgetToCaptionWrapper.containsKey(child)) {
-                                    wr = (ICaptionWrapper) widgetToCaptionWrapper
-                                            .get(child);
-                                    oldWidgetWrappers.remove(wr);
-                                } else {
-                                    wr = new ICaptionWrapper(child, client);
-                                    widgetToCaptionWrapper.put(child, wr);
-                                }
+    private void renderRemainingComponentsWithNoRelativeHeight(
+            LinkedList<Cell> pendingCells) {
 
-                                setWidget(row, column, wr);
+        for (Iterator iterator = pendingCells.iterator(); iterator.hasNext();) {
+            Cell cell = (Cell) iterator.next();
+            if (!cell.hasRelativeHeight()) {
+                cell.render();
+                iterator.remove();
+            }
+        }
 
-                                DOM.setStyleAttribute(wr.getElement(),
-                                        "textAlign", alignmentInfo
-                                                .getHorizontalAlignment());
+    }
 
-                                if (!u.getBooleanAttribute("cached")) {
-                                    child.updateFromUIDL(u, client);
-                                }
+    /**
+     * Iterates colspanned cells, ensures cols have enough space to accommodate
+     * them
+     */
+    private void distributeColSpanWidths() {
+        for (SpanList list : colSpans) {
+            for (Cell cell : list.cells) {
+                int width = cell.getWidth();
+                int allocated = columnWidths[cell.col];
+                for (int i = 1; i < cell.colspan; i++) {
+                    allocated += spacingPixels + columnWidths[cell.col + i];
+                }
+                if (allocated < width) {
+                    // columnWidths needs to be expanded due colspanned cell
+                    int neededExtraSpace = width - allocated;
+                    int spaceForColunms = neededExtraSpace / cell.colspan;
+                    for (int i = 0; i < cell.colspan; i++) {
+                        int col = cell.col + i;
+                        columnWidths[col] += spaceForColunms;
+                        neededExtraSpace -= spaceForColunms;
+                    }
+                    if (neededExtraSpace > 0) {
+                        for (int i = 0; i < cell.colspan; i++) {
+                            int col = cell.col + i;
+                            columnWidths[col] += 1;
+                            neededExtraSpace -= 1;
+                            if (neededExtraSpace == 0) {
+                                break;
                             }
-                            column++;
                         }
                     }
-                    row++;
                 }
             }
+        }
+    }
 
-            // loop oldWidgetWrappers that where not re-attached and unregister
-            // them
-            for (final Iterator it = oldWidgetWrappers.iterator(); it.hasNext();) {
-                final ICaptionWrapper w = (ICaptionWrapper) it.next();
-                client.unregisterPaintable(w.getPaintable());
-                widgetToCaptionWrapper.remove(w.getPaintable());
-            }
-            // fix rendering bug on FF2 (#1838)
-            if (needsFF2Hack) {
-                DeferredCommand.addCommand(new Command() {
-                    public void execute() {
-                        Element firstcell = getCellFormatter().getElement(0, 0);
-                        if (firstcell != null) {
-                            String styleAttribute = DOM.getStyleAttribute(
-                                    firstcell, "verticalAlign");
-                            DOM.setStyleAttribute(firstcell, "verticalAlign",
-                                    "");
-                            int elementPropertyInt = DOM.getElementPropertyInt(
-                                    firstcell, "offsetWidth");
-                            DOM.setStyleAttribute(firstcell, "verticalAlign",
-                                    styleAttribute);
-                            if (elementPropertyInt > 0) {
-                                needsFF2Hack = false;
+    /**
+     * Iterates rowspanned cells, ensures rows have enough space to accommodate
+     * them
+     */
+    private void distributeRowSpanHeights() {
+        for (SpanList list : rowSpans) {
+            for (Cell cell : list.cells) {
+                int height = cell.getHeight();
+                int allocated = rowHeights[cell.row];
+                for (int i = 1; i < cell.rowspan; i++) {
+                    allocated += spacingPixels + rowHeights[cell.row + i];
+                }
+                if (allocated < height) {
+                    // columnWidths needs to be expanded due colspanned cell
+                    int neededExtraSpace = height - allocated;
+                    int spaceForColunms = neededExtraSpace / cell.rowspan;
+                    for (int i = 0; i < cell.rowspan; i++) {
+                        int row = cell.row + i;
+                        rowHeights[row] += spaceForColunms;
+                        neededExtraSpace -= spaceForColunms;
+                    }
+                    if (neededExtraSpace > 0) {
+                        for (int i = 0; i < cell.rowspan; i++) {
+                            int row = cell.row + i;
+                            rowHeights[row] += 1;
+                            neededExtraSpace -= 1;
+                            if (neededExtraSpace == 0) {
+                                break;
                             }
                         }
                     }
-                });
+                }
             }
         }
+    }
 
-        public boolean hasChildComponent(Widget component) {
-            if (widgetToCaptionWrapper.containsKey(component)) {
-                return true;
-            }
-            return false;
-        }
+    private LinkedList<SpanList> colSpans = new LinkedList<SpanList>();
+    private LinkedList<SpanList> rowSpans = new LinkedList<SpanList>();
 
-        public void replaceChildComponent(Widget oldComponent,
-                Widget newComponent) {
-            // TODO Auto-generated method stub
+    private int marginTopAndBottom;
 
-        }
+    private class SpanList {
+        final int span;
+        List<Cell> cells = new LinkedList<Cell>();
 
-        public void updateCaption(Paintable component, UIDL uidl) {
-            final ICaptionWrapper wrapper = (ICaptionWrapper) widgetToCaptionWrapper
-                    .get(component);
-            wrapper.updateCaption(uidl);
+        public SpanList(int span) {
+            this.span = span;
         }
+    }
 
-        public boolean requestLayout(Set<Paintable> child) {
-            // TODO Auto-generated method stub
-            return false;
+    private void storeColSpannedCell(Cell cell) {
+        SpanList l = null;
+        for (SpanList list : colSpans) {
+            if (list.span < cell.colspan) {
+                continue;
+            } else {
+                // insert before this
+                l = list;
+                break;
+            }
+        }
+        if (l == null) {
+            l = new SpanList(cell.colspan);
+            colSpans.add(l);
+        } else if (l.span != cell.colspan) {
+
+            SpanList newL = new SpanList(cell.colspan);
+            colSpans.add(colSpans.indexOf(l), newL);
+            l = newL;
         }
+        l.cells.add(cell);
+    }
 
-        public RenderSpace getAllocatedSpace(Widget child) {
-            // TODO Auto-generated method stub
-            return null;
+    private void detectSpacing(UIDL uidl) {
+        if (uidl.getBooleanAttribute("spacing")) {
+            Element spacingmeter = DOM.createDiv();
+            spacingmeter.setClassName(CLASSNAME + "-" + "spacing-element");
+            spacingmeter.getStyle().setProperty("width", "0");
+            canvas.getElement().appendChild(spacingmeter);
+            spacingPixels = spacingmeter.getOffsetWidth();
+            canvas.getElement().removeChild(spacingmeter);
+        } else {
+            spacingPixels = 0;
         }
+    }
 
+    private void handleMargins(UIDL uidl) {
+        final MarginInfo margins = new MarginInfo(uidl
+                .getIntAttribute("margins"));
+
+        setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_TOP,
+                margins.hasTop());
+        setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT,
+                margins.hasRight());
+        setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM,
+                margins.hasBottom());
+        setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_LEFT,
+                margins.hasLeft());
+
+        marginTopAndBottom = margin.getOffsetHeight()
+                - canvas.getOffsetHeight();
     }
 
-    public void iLayout() {
-        if (needsLayout) {
-            super.setWidth(width);
-            if (meterElement == null) {
-                meterElement = DOM.createDiv();
-                DOM.setStyleAttribute(meterElement, "overflow", "hidden");
-                DOM.setStyleAttribute(meterElement, "height", "0");
-                DOM.appendChild(getContainerElement(), meterElement);
-            }
-            int contentWidth = DOM.getElementPropertyInt(meterElement,
-                    "offsetWidth");
-            int offsetWidth = getOffsetWidth();
+    public boolean hasChildComponent(Widget component) {
+        return paintableToCell.containsKey(component);
+    }
 
-            grid.setWidth((offsetWidth - (offsetWidth - contentWidth)) + "px");
-        } else {
-            grid.setWidth("");
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        // TODO
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        ChildComponentContainer cc = widgetToComponentContainer.get(component);
+        if (cc != null) {
+            cc.updateCaption(uidl, client);
         }
-        client.runDescendentsLayout(this);
     }
 
     public boolean requestLayout(Set<Paintable> child) {
-        // TODO Auto-generated method stub
-        return false;
+        boolean mayNeedLayout = false;
+        int offsetHeight = canvas.getOffsetHeight();
+        int offsetWidth = canvas.getOffsetWidth();
+        if ("".equals(width) || "".equals(height)) {
+            mayNeedLayout = true;
+        } else {
+            for (Paintable paintable : child) {
+                Cell cell = paintableToCell.get(paintable);
+                if (!cell.hasRelativeHeight() || !cell.hasRelativeWidth()) {
+                    // cell sizes will only stay still if only relatively sized
+                    // components
+                    mayNeedLayout = true;
+                }
+            }
+        }
+        if (mayNeedLayout) {
+            expandColumns();
+            expandRows();
+            layoutCells();
+            for (Paintable paintable : child) {
+                Cell cell = paintableToCell.get(paintable);
+                if (cell.hasRelativeHeight() || cell.hasRelativeWidth()) {
+                    client.handleComponentRelativeSize((Widget) paintable);
+                }
+            }
+        }
+        if (canvas.getOffsetHeight() != offsetHeight
+                || canvas.getOffsetWidth() != offsetWidth) {
+            return false;
+        } else {
+            return true;
+        }
     }
 
     public RenderSpace getAllocatedSpace(Widget child) {
-        // TODO Auto-generated method stub
-        return null;
+        Cell cell = paintableToCell.get(child);
+        assert cell != null;
+        return cell.getAllocatedSpace();
+    }
+
+    private Cell[][] cells;
+
+    /**
+     * Private helper class.
+     */
+    private class Cell {
+        public Cell(UIDL c) {
+            // Set cell width
+            colspan = c.hasAttribute("w") ? c.getIntAttribute("w") : 1;
+            // Set cell height
+            rowspan = c.hasAttribute("h") ? c.getIntAttribute("h") : 1;
+            row = c.getIntAttribute("y");
+            col = c.getIntAttribute("x");
+            childUidl = c.getChildUIDL(0);
+        }
+
+        public boolean hasRelativeHeight() {
+            if (childUidl.hasAttribute("height")) {
+                String w = childUidl.getStringAttribute("height");
+                if (w.contains("%")) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public RenderSpace getAllocatedSpace() {
+            return new RenderSpace(getAvailableWidth(), getAvailableHeight());
+        }
+
+        public boolean hasContent() {
+            return childUidl != null;
+        }
+
+        /**
+         * @return total of spanned cols
+         */
+        private int getAvailableWidth() {
+            int width = columnWidths[col];
+            for (int i = 1; i < colspan; i++) {
+                width += spacingPixels + columnWidths[col + i];
+            }
+            return width;
+        }
+
+        /**
+         * @return total of spanned rows
+         */
+        private int getAvailableHeight() {
+            int height = rowHeights[row];
+            for (int i = 1; i < rowspan; i++) {
+                height += spacingPixels + rowHeights[row + i];
+            }
+            return height;
+        }
+
+        public void layout(int x, int y) {
+            if (cc != null && cc.isAttached()) {
+                canvas.setWidgetPosition(cc, x, y);
+                cc.setContainerSize(getAvailableWidth(), getAvailableHeight());
+                cc.setAlignment(new AlignmentInfo(alignment));
+            }
+        }
+
+        public int getWidth() {
+            if (cc != null) {
+                return cc.getOffsetWidth();
+            } else {
+                return 0;
+            }
+        }
+
+        public int getHeight() {
+            if (cc != null) {
+                return cc.getOffsetHeight();
+            } else {
+                return 0;
+            }
+        }
+
+        public boolean renderIfNoRelativeWidth() {
+            if (childUidl == null) {
+                return false;
+            }
+            if (!hasRelativeWidth()) {
+                render();
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        private boolean hasRelativeWidth() {
+            if (childUidl.hasAttribute("width")) {
+                String w = childUidl.getStringAttribute("width");
+                if (w.contains("%")) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        protected void render() {
+            Paintable paintable = client.getPaintable(childUidl);
+            if (cc == null) {
+                cc = new ChildComponentContainer((Widget) paintable,
+                        CellBasedLayout.ORIENTATION_HORIZONTAL);
+                cc.setHeight("");
+                canvas.add(cc);
+            }
+            widgetToComponentContainer.put((Widget) paintable, cc);
+            paintableToCell.put(paintable, this);
+            cc.renderChild(childUidl, client);
+        }
+
+        public UIDL getChildUIDL() {
+            return childUidl;
+        }
+
+        int row;
+        int col;
+        int colspan = 1;
+        int rowspan = 1;
+        UIDL childUidl;
+        int alignment;
+        ChildComponentContainer cc;
     }
 
+    private Cell getCell(UIDL c) {
+        int row = c.getIntAttribute("y");
+        int col = c.getIntAttribute("x");
+        Cell cell = cells[col][row];
+        if (cell == null) {
+            cell = new Cell(c);
+            cells[col][row] = cell;
+        }
+        return cell;
+    }
 }
index 7302724899b1be711d1bb411335e70a097d48027..b0ef5c08370739564969c3795f66b51824335113 100644 (file)
@@ -86,6 +86,7 @@ public class IPanel extends SimplePanel implements Container,
                 + "-deco");
         DOM.sinkEvents(getElement(), Event.ONKEYDOWN);
         DOM.sinkEvents(contentNode, Event.ONSCROLL);
+        contentNode.getStyle().setProperty("position", "relative");
     }
 
     @Override
@@ -94,7 +95,7 @@ public class IPanel extends SimplePanel implements Container,
     }
 
     private void setCaption(String text) {
-        DOM.setInnerText(captionText, text);
+        DOM.setInnerHTML(captionText, text);
     }
 
     public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
index e5e04c58a362f920c5df5b71e323b4b407311197..14c0f1c989ae6978f29c07c66a4383c111937628 100644 (file)
@@ -362,6 +362,7 @@ public class ITabsheet extends ITabsheetBase implements
             DOM.setStyleAttribute(contentNode, "height", contentHeight + "px");
             renderSpace.setHeight(contentHeight);
             DOM.setStyleAttribute(contentNode, "overflow", "auto");
+            contentNode.getStyle().setProperty("position", "relative");
         } else {
             DOM.setStyleAttribute(contentNode, "height", "");
             DOM.setStyleAttribute(contentNode, "overflow", "");
index dc381227f791e423951244441b2e630c7b7e065a..f4f49041f2187b5ed7a8e4ec20aac825b8c9df45 100644 (file)
@@ -239,7 +239,7 @@ public class ChildComponentContainer extends Panel {
         return getCaptionHeight();\r
     }\r
 \r
-    public int calculateVerticalAlignmentTopOffset(int emptySpace) {\r
+    private int calculateVerticalAlignmentTopOffset(int emptySpace) {\r
         if (alignment.isTop()) {\r
             return 0;\r
         }\r