From b759707df2eac06de4b2d62687588a6665850187 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Tue, 21 Oct 2008 13:54:04 +0000 Subject: [PATCH] Major layout renewals. GridLayout now totally absolutely positioned, all scrollable areas position: relative due IE. Still some broken scrollbars, IE6 issues and dev inconveniences. svn changeset:5690/svn branch:trunk --- .../demo/featurebrowser/LabelExample.java | 61 +- .../terminal/gwt/client/DefaultWidgetSet.java | 9 +- .../terminal/gwt/client/ui/IAccordion.java | 2 +- .../terminal/gwt/client/ui/IGridLayout.java | 802 +++++++++++++----- .../terminal/gwt/client/ui/IPanel.java | 3 +- .../terminal/gwt/client/ui/ITabsheet.java | 1 + .../ui/layout/ChildComponentContainer.java | 2 +- 7 files changed, 609 insertions(+), 271 deletions(-) diff --git a/src/com/itmill/toolkit/demo/featurebrowser/LabelExample.java b/src/com/itmill/toolkit/demo/featurebrowser/LabelExample.java index 8f96602cdc..2747c1fdfe 100644 --- a/src/com/itmill/toolkit/demo/featurebrowser/LabelExample.java +++ b/src/com/itmill/toolkit/demo/featurebrowser/LabelExample.java @@ -4,10 +4,10 @@ package com.itmill.toolkit.demo.featurebrowser; +import com.itmill.toolkit.ui.Component; import com.itmill.toolkit.ui.CustomComponent; import com.itmill.toolkit.ui.GridLayout; import com.itmill.toolkit.ui.Label; -import com.itmill.toolkit.ui.OrderedLayout; import com.itmill.toolkit.ui.Panel; /** @@ -28,68 +28,61 @@ public class LabelExample extends CustomComponent { + " This is an indented row. \n Same indentation here."; public LabelExample() { - - final OrderedLayout main = new OrderedLayout(); - main.setSizeFull(); - main.setMargin(true); - setSizeFull(); - setCompositionRoot(main); - final GridLayout g = new GridLayout(2, 4); - g.setSizeFull(); - main.addComponent(g); + g.setMargin(true); + setCompositionRoot(g); + g.setWidth("100%"); + // plain w/o caption - Panel p = new Panel("Plain"); - p.setWidth("100%"); - p.getLayout().setWidth("100%"); - p.setStyleName(Panel.STYLE_LIGHT); + Panel p = getExpamplePanel("Plain"); Label l = new Label("A plain label without caption."); p.addComponent(l); g.addComponent(p); // plain w/ caption - p = new Panel("Plain w/ caption + tooltip"); - p.setWidth("100%"); - p.getLayout().setWidth("100%"); - p.setStyleName(Panel.STYLE_LIGHT); + p = getExpamplePanel("Plain w/ caption + tooltip"); l = new Label("A plain label with caption."); l.setCaption("Label caption"); l.setDescription("This is a description (tooltip) for the label."); p.addComponent(l); g.addComponent(p); // plain w/ xhtml - p = new Panel("Plain w/ XHTML content"); - p.setWidth("100%"); - p.getLayout().setWidth("100%"); - p.setStyleName(Panel.STYLE_LIGHT); + p = getExpamplePanel("Plain w/ XHTML content"); l = new Label(xhtml); p.addComponent(l); g.addComponent(p); // xhtml w/ xhtml - p = new Panel("XHTML-mode w/ XHTML content"); - p.setWidth("100%"); - p.getLayout().setWidth("100%"); - p.setStyleName(Panel.STYLE_LIGHT); + p = getExpamplePanel("XHTML-mode w/ XHTML content"); l = new Label(xhtml); l.setContentMode(Label.CONTENT_XHTML); p.addComponent(l); g.addComponent(p); // plain w/ preformatted - p = new Panel("Plain w/ preformatted content"); - p.setWidth("100%"); - p.getLayout().setWidth("100%"); - p.setStyleName(Panel.STYLE_LIGHT); + p = getExpamplePanel("Plain w/ preformatted content"); l = new Label(pre); p.addComponent(l); g.addComponent(p); // preformatted w/ preformatted - p = new Panel("Preformatted-mode w/ preformatted content"); - p.setWidth("100%"); - p.getLayout().setWidth("100%"); - p.setStyleName(Panel.STYLE_LIGHT); + p = getExpamplePanel("Preformatted-mode w/ preformatted content"); l = new Label(pre); l.setContentMode(Label.CONTENT_PREFORMATTED); p.addComponent(l); g.addComponent(p); } + + private Panel getExpamplePanel(String caption) { + Panel p = new Panel(caption) { + + @Override + public void addComponent(Component c) { + c.setWidth("100%"); + super.addComponent(c); + } + + }; + p.addStyleName(Panel.STYLE_LIGHT); + p.setWidth("100%"); + p.getLayout().setWidth("100%"); + return p; + } } diff --git a/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java b/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java index d73bbe1d74..e4f629180e 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java @@ -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)) { diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IAccordion.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IAccordion.java index 01ede8079c..00788b2972 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IAccordion.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IAccordion.java @@ -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", ""); diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IGridLayout.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IGridLayout.java index e7d4dd3c82..c868cc5a1f 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IGridLayout.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IGridLayout.java @@ -4,332 +4,682 @@ 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 widgetToComponentContainer = new HashMap(); + + private HashMap paintableToCell = new HashMap(); + + 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 orphaned = new LinkedList(); + 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 nonRenderedWidgets = (HashMap) widgetToComponentContainer + .clone(); + + final int[] alignments = uidl.getIntArrayAttribute("alignments"); + int alignmentIndex = 0; + int column; + int row = 0; + + LinkedList pendingCells = new LinkedList(); + + LinkedList relativeHeighted = new LinkedList(); + + 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 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 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 colSpans = new LinkedList(); + private LinkedList rowSpans = new LinkedList(); - public void replaceChildComponent(Widget oldComponent, - Widget newComponent) { - // TODO Auto-generated method stub + private int marginTopAndBottom; - } + private class SpanList { + final int span; + List cells = new LinkedList(); - 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 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 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; + } } diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IPanel.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IPanel.java index 7302724899..b0ef5c0837 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IPanel.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IPanel.java @@ -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) { diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheet.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheet.java index e5e04c58a3..14c0f1c989 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheet.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITabsheet.java @@ -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", ""); diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/layout/ChildComponentContainer.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/layout/ChildComponentContainer.java index dc381227f7..f4f49041f2 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/layout/ChildComponentContainer.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/layout/ChildComponentContainer.java @@ -239,7 +239,7 @@ public class ChildComponentContainer extends Panel { return getCaptionHeight(); } - public int calculateVerticalAlignmentTopOffset(int emptySpace) { + private int calculateVerticalAlignmentTopOffset(int emptySpace) { if (alignment.isTop()) { return 0; } -- 2.39.5