]> source.dussan.org Git - vaadin-framework.git/commitdiff
Fixes subpixel allocation accuracy and speed (#16614, #16750)
authorHenrik Paul <henrik@vaadin.com>
Fri, 6 Feb 2015 14:35:16 +0000 (16:35 +0200)
committerLeif Åstrand <leif@vaadin.com>
Wed, 4 Mar 2015 14:06:52 +0000 (16:06 +0200)
This reverts workarounds used in subpixel quick fix commit
6133b2cffd0c0b0e0e360ae30330a8adbe7662f4. New logic uses Escalator's
more optimised multiple column width setting method.

Change-Id: I0863f9774e6efc26f01ebdb736b4847e4ef5354c

client/src/com/vaadin/client/widget/escalator/FlyweightRow.java
client/src/com/vaadin/client/widgets/Escalator.java
client/src/com/vaadin/client/widgets/Grid.java
uitest/src/com/vaadin/tests/components/grid/GridWidthIncreaseTest.java
uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridClientColumnPropertiesTest.java

index 6e25e822355e5757baa649df2a6c40dbbef8b4d7..8628adb05f9dc61e025a5bf7c1fb5e4a23ccfa69 100644 (file)
@@ -21,7 +21,6 @@ import java.util.Iterator;
 import java.util.List;
 
 import com.google.gwt.dom.client.TableRowElement;
-import com.vaadin.client.widgets.Escalator;
 
 /**
  * An internal implementation of the {@link Row} interface.
index 0e34d9846608a5e8d405d6c9127512142935a777..5f69be9142ee1c061335515d636603d3f763ba67 100644 (file)
@@ -819,18 +819,23 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
             double tableWrapperWidth = widthOfEscalator;
 
             boolean verticalScrollNeeded = scrollContentHeight > tableWrapperHeight
-                    - header.heightOfSection - footer.heightOfSection;
-            boolean horizontalScrollNeeded = scrollContentWidth > tableWrapperWidth;
+                    + WidgetUtil.PIXEL_EPSILON
+                    - header.heightOfSection
+                    - footer.heightOfSection;
+            boolean horizontalScrollNeeded = scrollContentWidth > tableWrapperWidth
+                    + WidgetUtil.PIXEL_EPSILON;
 
             // One dimension got scrollbars, but not the other. Recheck time!
             if (verticalScrollNeeded != horizontalScrollNeeded) {
                 if (!verticalScrollNeeded && horizontalScrollNeeded) {
                     verticalScrollNeeded = scrollContentHeight > tableWrapperHeight
+                            + WidgetUtil.PIXEL_EPSILON
                             - header.heightOfSection
                             - footer.heightOfSection
                             - horizontalScrollbar.getScrollbarThickness();
                 } else {
                     horizontalScrollNeeded = scrollContentWidth > tableWrapperWidth
+                            + WidgetUtil.PIXEL_EPSILON
                             - verticalScrollbar.getScrollbarThickness();
                 }
             }
@@ -1810,12 +1815,13 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
          */
         protected void reapplyRowWidths() {
             double rowWidth = columnConfiguration.calculateRowWidth();
+            if (rowWidth < 0) {
+                return;
+            }
 
-            com.google.gwt.dom.client.Element row = root.getFirstChildElement();
+            Element row = root.getFirstChildElement();
             while (row != null) {
-                if (rowWidth >= 0) {
-                    row.getStyle().setWidth(rowWidth, Unit.PX);
-                }
+                row.getStyle().setWidth(rowWidth, Unit.PX);
                 row = row.getNextSiblingElement();
             }
         }
@@ -2035,22 +2041,17 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
                 cellClone.getStyle().clearWidth();
 
                 rowElement.insertBefore(cellClone, cellOriginal);
-
-                /*
-                 * [[subpixelworkaround]] (6.2.2015, Henrik Paul) FIXME: not
-                 * using the double-version is a workaround for a bug. It'll be
-                 * converted to use the double version at a later time
-                 */
                 double requiredWidth = WidgetUtil
-                        .getRequiredWidthBoundingClientRect(cellClone);
+                        .getRequiredWidthBoundingClientRectDouble(cellClone);
 
-                if (BrowserInfo.get().isIE9()) {
+                if (BrowserInfo.get().isIE()) {
                     /*
-                     * IE9 does not support subpixels. Usually it is rounded
-                     * down which leads to content not shown. Increase the
-                     * counted required size by one just to be on the safe side.
+                     * IE browsers have some issues with subpixels. Occasionally
+                     * content is overflown even if not necessary. Increase the
+                     * counted required size by 0.01 just to be on the safe
+                     * side.
                      */
-                    requiredWidth += 1;
+                    requiredWidth += 0.01;
                 }
 
                 maxCellWidth = Math.max(requiredWidth, maxCellWidth);
@@ -3792,7 +3793,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
                     } else {
                         /*
                          * the column's width is calculated at Escalator.onLoad
-                         * via measureIfNeeded!
+                         * via measureAndSetWidthIfNeeded!
                          */
                         measuringRequested = true;
                     }
@@ -3818,7 +3819,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
                  * widths yet.
                  * 
                  * This is fixed during Escalator.onLoad, by the call to
-                 * "measureIfNeeded", which fixes "everything".
+                 * "measureAndSetWidthIfNeeded", which fixes "everything".
                  */
                 if (!measuringRequested) {
                     return calculatedWidth;
@@ -3833,7 +3834,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
              * Called by {@link Escalator#onLoad()}.
              */
             public boolean measureAndSetWidthIfNeeded() {
-                assert isAttached() : "Column.measureIfNeeded() was called even though Escalator was not attached!";
+                assert isAttached() : "Column.measureAndSetWidthIfNeeded() was called even though Escalator was not attached!";
 
                 if (measuringRequested) {
                     measuringRequested = false;
@@ -3851,6 +3852,11 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
         private final List<Column> columns = new ArrayList<Column>();
         private int frozenColumns = 0;
 
+        /*
+         * TODO: this is a bit of a duplicate functionality with the
+         * Column.calculatedWidth caching. Probably should use one or the other,
+         * not both
+         */
         /**
          * A cached array of all the calculated column widths.
          * 
@@ -3995,6 +4001,8 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
          */
         @Override
         public void insertColumns(final int index, final int numberOfColumns) {
+            subpixelBrowserBugDetector.invalidateFix();
+
             // Validate
             if (index < 0 || index > getColumnCount()) {
                 throw new IndexOutOfBoundsException("The given index(" + index
@@ -4146,14 +4154,23 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
             for (Entry<Integer, Double> entry : indexWidthMap.entrySet()) {
                 int index = entry.getKey().intValue();
                 double width = entry.getValue().doubleValue();
+
+                if (index == getColumnCount() - 1) {
+                    subpixelBrowserBugDetector.invalidateFix();
+                }
+
                 checkValidColumnIndex(index);
                 columns.get(index).setWidth(width);
+
             }
 
             widthsArray = null;
             header.reapplyColumnWidths();
             body.reapplyColumnWidths();
             footer.reapplyColumnWidths();
+
+            subpixelBrowserBugDetector.checkAndFix();
+
             recalculateElementSizes();
         }
 
@@ -4248,6 +4265,137 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
         }
     }
 
+    private class SubpixelBrowserBugDetector {
+        private static final double SUBPIXEL_ADJUSTMENT = .1;
+        private boolean hasAlreadyBeenFixed = false;
+
+        /**
+         * This is a fix essentially for Firefox and how it handles subpixels.
+         * <p>
+         * Even if an element has {@code style="width: 1000.12px"}, the bounding
+         * box's width in Firefox is usually nothing of that sort. It's actually
+         * 1000.11669921875 (in version 35.0.1). That's not even close, when
+         * talking about floating point precision. Other browsers handle the
+         * subpixels way better
+         * <p>
+         * In any case, we need to fix that. And that's fixed by simply checking
+         * if the sum of the width of all the cells is larger than the width of
+         * the row. If it is, we <i>hack</i> the last column
+         * {@value #SUBPIXEL_ADJUSTMENT}px narrower.
+         */
+        public void checkAndFix() {
+            if (!hasAlreadyBeenFixed && hasSubpixelBrowserBug()) {
+                fixSubpixelBrowserBug();
+                hasAlreadyBeenFixed = true;
+            }
+        }
+
+        public void invalidateFix() {
+            adjustBookkeepingPixels(SUBPIXEL_ADJUSTMENT);
+            hasAlreadyBeenFixed = false;
+        }
+
+        private boolean hasSubpixelBrowserBug() {
+            final RowContainer rowContainer;
+            if (header.getRowCount() > 0) {
+                rowContainer = header;
+            } else if (body.getRowCount() > 0) {
+                rowContainer = body;
+            } else if (footer.getRowCount() > 0) {
+                rowContainer = footer;
+            } else {
+                return false;
+            }
+
+            double sumOfCellWidths = 0;
+            TableRowElement tr = rowContainer.getElement().getRows().getItem(0);
+
+            if (tr == null) {
+                /*
+                 * for some weird reason, the row might be null at this point in
+                 * (some?) webkit browsers.
+                 */
+                return false;
+            }
+
+            NodeList<TableCellElement> cells = tr.getCells();
+            assert cells != null : "cells was null, why is it null?";
+
+            for (int i = 0; i < cells.getLength(); i++) {
+                TableCellElement cell = cells.getItem(i);
+                if (!cell.getStyle().getDisplay()
+                        .equals(Display.NONE.getCssName())) {
+                    sumOfCellWidths += WidgetUtil.getBoundingClientRect(cell)
+                            .getWidth();
+                }
+            }
+
+            double rowWidth = WidgetUtil.getBoundingClientRect(tr).getWidth();
+            return sumOfCellWidths >= rowWidth;
+        }
+
+        private void fixSubpixelBrowserBug() {
+            assert columnConfiguration.getColumnCount() > 0 : "Why are we running this code if there are no columns?";
+
+            adjustBookkeepingPixels(-SUBPIXEL_ADJUSTMENT);
+
+            fixSubpixelBrowserBugFor(header);
+            fixSubpixelBrowserBugFor(body);
+            fixSubpixelBrowserBugFor(footer);
+        }
+
+        private void adjustBookkeepingPixels(double adjustment) {
+            int lastColumnIndex = columnConfiguration.columns.size() - 1;
+            if (lastColumnIndex < 0) {
+                return;
+            }
+
+            columnConfiguration.columns.get(lastColumnIndex).calculatedWidth += adjustment;
+            if (columnConfiguration.widthsArray != null) {
+                columnConfiguration.widthsArray[lastColumnIndex] += adjustment;
+            }
+        }
+
+        /**
+         * Adjust the last non-spanned cell by {@link #SUBPIXEL_ADJUSTMENT} (
+         * {@value #SUBPIXEL_ADJUSTMENT}px).
+         * <p>
+         * We'll do this brute-force, by individually measuring and shrinking
+         * the last non-spanned cell. Brute-force, since each row might be
+         * spanned differently - we can't simply pick one index and one width,
+         * and mass-apply that to everything :(
+         */
+        private void fixSubpixelBrowserBugFor(RowContainer rowContainer) {
+            if (rowContainer.getRowCount() == 0) {
+                return;
+            }
+
+            NodeList<TableRowElement> rows = rowContainer.getElement()
+                    .getRows();
+            for (int i = 0; i < rows.getLength(); i++) {
+
+                NodeList<TableCellElement> cells = rows.getItem(i).getCells();
+                TableCellElement lastNonspannedCell = null;
+                for (int j = cells.getLength() - 1; j >= 0; j--) {
+                    TableCellElement cell = cells.getItem(j);
+                    if (!cell.getStyle().getDisplay()
+                            .equals(Display.NONE.getCssName())) {
+                        lastNonspannedCell = cell;
+                        break;
+                    }
+                }
+
+                assert lastNonspannedCell != null : "all cells were \"display: none\" on row "
+                        + i + " in " + rowContainer.getElement().getTagName();
+
+                double cellWidth = WidgetUtil.getBoundingClientRect(
+                        lastNonspannedCell).getWidth();
+                double newWidth = cellWidth - SUBPIXEL_ADJUSTMENT;
+                lastNonspannedCell.getStyle().setWidth(newWidth, Unit.PX);
+            }
+        }
+    }
+
     // abs(atan(y/x))*(180/PI) = n deg, x = 1, solve y
     /**
      * The solution to
@@ -4344,6 +4492,8 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
         }
     };
 
+    private final SubpixelBrowserBugDetector subpixelBrowserBugDetector = new SubpixelBrowserBugDetector();
+
     /**
      * Creates a new Escalator widget instance.
      */
index 3c2d070fa0febed781d38356833311a17e1a74ba..9e0cb0f4f89649967056ae2c4ca31f6a5701da59 100644 (file)
@@ -60,6 +60,7 @@ import com.google.gwt.user.client.ui.HasEnabled;
 import com.google.gwt.user.client.ui.HasWidgets;
 import com.google.gwt.user.client.ui.ResizeComposite;
 import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.BrowserInfo;
 import com.vaadin.client.DeferredWorker;
 import com.vaadin.client.WidgetUtil;
 import com.vaadin.client.data.DataChangeHandler;
@@ -2447,29 +2448,6 @@ public class Grid<T> extends ResizeComposite implements
                 applyColumnWidths();
             } else {
                 applyColumnWidthsWithExpansion();
-
-                /*
-                 * [[subpixelworkaround]] (6.2.2015, Henrik Paul) FIXME: just
-                 * dump all the remaining pixels into the last column and
-                 * whistle loudly
-                 */
-                boolean dumpIntoLastColumn = false;
-                double escalatorWidth = escalator.getInnerWidth();
-                double occupiedWidth = 0;
-                for (Column column : getColumns()) {
-                    occupiedWidth += column.getWidthActual();
-                    if (column.getWidth() < 0 && column.getExpandRatio() != 0) {
-                        dumpIntoLastColumn = true;
-                    }
-                }
-
-                if (dumpIntoLastColumn) {
-                    Column<?, T> lastColumn = getColumn(getColumnCount() - 1);
-                    double width = Math.floor(lastColumn.getWidthActual()
-                            + (escalatorWidth - occupiedWidth));
-                    escalator.getColumnConfiguration().setColumnWidth(
-                            getColumnCount() - 1, width);
-                }
             }
         }
 
@@ -2526,10 +2504,12 @@ public class Grid<T> extends ResizeComposite implements
         }
 
         private void applyColumnWidthsWithExpansion() {
-            boolean someColumnExpands = false;
+            boolean defaultExpandRatios = true;
             int totalRatios = 0;
             double reservedPixels = 0;
-            final Set<Column<?, ?>> columnsToExpand = new HashSet<Column<?, ?>>();
+            final Set<Column<?, T>> columnsToExpand = new HashSet<Column<?, T>>();
+            List<Column<?, T>> nonFixedColumns = new ArrayList<Column<?, T>>();
+            Map<Integer, Double> columnSizes = new HashMap<Integer, Double>();
 
             /*
              * Set all fixed widths and also calculate the size-to-fit widths
@@ -2538,49 +2518,37 @@ public class Grid<T> extends ResizeComposite implements
              * This way we know with how many pixels we have left to expand the
              * rest.
              */
-            for (Column<?, ?> column : getColumns()) {
+            for (Column<?, T> column : getColumns()) {
                 final double widthAsIs = column.getWidth();
                 final boolean isFixedWidth = widthAsIs >= 0;
                 final double widthFixed = Math.max(widthAsIs,
                         column.getMinimumWidth());
-                final int expandRatio = column.getExpandRatio();
+                defaultExpandRatios = defaultExpandRatios
+                        && column.getExpandRatio() == -1;
 
                 if (isFixedWidth) {
-                    column.doSetWidth(widthFixed);
+                    columnSizes.put(indexOfColumn(column), widthFixed);
+                    reservedPixels += widthFixed;
                 } else {
-                    column.doSetWidth(-1);
-                    final double newWidth = column.getWidthActual();
-                    final double maxWidth = getMaxWidth(column);
-                    boolean shouldExpand = newWidth < maxWidth
-                            && expandRatio > 0;
-                    if (shouldExpand) {
-                        totalRatios += expandRatio;
-                        columnsToExpand.add(column);
-                        someColumnExpands = true;
-                    }
+                    nonFixedColumns.add(column);
+                    columnSizes.put(indexOfColumn(column), -1.0d);
                 }
-                reservedPixels += column.getWidthActual();
             }
 
-            /*
-             * If no column has a positive expand ratio, all columns with a
-             * negative expand ratio has an expand ratio. Columns with 0 expand
-             * ratio are excluded.
-             * 
-             * This means that if we only define one column to have 0 expand, it
-             * will be the only one not to expand, while all the others expand.
-             */
-            if (!someColumnExpands) {
-                assert totalRatios == 0 : "totalRatios should've been 0";
-                assert columnsToExpand.isEmpty() : "columnsToExpand should've been empty";
-                for (Column<?, ?> column : getColumns()) {
-                    final double width = column.getWidth();
-                    final int expandRatio = column.getExpandRatio();
-                    if (width < 0 && expandRatio < 0) {
-                        totalRatios++;
-                        columnsToExpand.add(column);
-                    }
+            setColumnSizes(columnSizes);
+
+            for (Column<?, T> column : nonFixedColumns) {
+                final int expandRatio = (defaultExpandRatios ? 1 : column
+                        .getExpandRatio());
+                final double newWidth = column.getWidthActual();
+                final double maxWidth = getMaxWidth(column);
+                boolean shouldExpand = newWidth < maxWidth && expandRatio > 0;
+                if (shouldExpand) {
+                    totalRatios += expandRatio;
+                    columnsToExpand.add(column);
                 }
+                reservedPixels += newWidth;
+                columnSizes.put(indexOfColumn(column), newWidth);
             }
 
             /*
@@ -2588,8 +2556,7 @@ public class Grid<T> extends ResizeComposite implements
              * can distribute the remaining pixels to all columns according to
              * their expand ratios.
              */
-            // [[subpixelworkaround]] (6.2.2015, Henrik Paul) FIXME: ceil
-            double pixelsToDistribute = Math.ceil(escalator.getInnerWidth())
+            double pixelsToDistribute = escalator.getInnerWidth()
                     - reservedPixels;
             if (pixelsToDistribute <= 0 || totalRatios <= 0) {
                 return;
@@ -2603,30 +2570,30 @@ public class Grid<T> extends ResizeComposite implements
             boolean aColumnHasMaxedOut;
             do {
                 aColumnHasMaxedOut = false;
-                // [[subpixelworkaround]] (6.2.2015, Henrik Paul) FIXME floor
-                final double widthPerRatio = Math.floor(pixelsToDistribute
-                        / totalRatios);
-                final Iterator<Column<?, ?>> i = columnsToExpand.iterator();
+                final double widthPerRatio = pixelsToDistribute / totalRatios;
+                final Iterator<Column<?, T>> i = columnsToExpand.iterator();
                 while (i.hasNext()) {
-                    final Column<?, ?> column = i.next();
+                    final Column<?, T> column = i.next();
                     final int expandRatio = getExpandRatio(column,
-                            someColumnExpands);
-                    final double autoWidth = column.getWidthActual();
+                            defaultExpandRatios);
+                    final double autoWidth = columnSizes
+                            .get(indexOfColumn(column));
                     final double maxWidth = getMaxWidth(column);
-                    final double widthCandidate = autoWidth + widthPerRatio
+                    double expandedWidth = autoWidth + widthPerRatio
                             * expandRatio;
 
-                    if (maxWidth <= widthCandidate) {
-                        column.doSetWidth(maxWidth);
-                        totalRatios -= expandRatio;
-                        pixelsToDistribute -= maxWidth - autoWidth;
+                    if (maxWidth <= expandedWidth) {
                         i.remove();
+                        totalRatios -= expandRatio;
                         aColumnHasMaxedOut = true;
+                        pixelsToDistribute -= maxWidth - autoWidth;
+                        columnSizes.put(indexOfColumn(column), maxWidth);
                     }
                 }
             } while (aColumnHasMaxedOut);
 
             if (totalRatios <= 0 && columnsToExpand.isEmpty()) {
+                setColumnSizes(columnSizes);
                 return;
             }
             assert pixelsToDistribute > 0 : "We've run out of pixels to distribute ("
@@ -2641,16 +2608,28 @@ public class Grid<T> extends ResizeComposite implements
              * If we still have anything left, distribute the remaining pixels
              * to the remaining columns.
              */
-            // [[subpixelworkaround]] (6.2.2015, Henrik Paul) FIXME: floor
-            final double widthPerRatio = Math.floor(pixelsToDistribute
-                    / totalRatios);
-            for (Column<?, ?> column : columnsToExpand) {
+            final double widthPerRatio;
+            int leftOver = 0;
+            if (BrowserInfo.get().isIE8() || BrowserInfo.get().isIE9()
+                    || BrowserInfo.getBrowserString().contains("PhantomJS")) {
+                // These browsers report subpixels as integers. this usually
+                // results into issues..
+                widthPerRatio = (int) (pixelsToDistribute / totalRatios);
+                leftOver = (int) (pixelsToDistribute - widthPerRatio
+                        * totalRatios);
+            } else {
+                widthPerRatio = pixelsToDistribute / totalRatios;
+            }
+            for (Column<?, T> column : columnsToExpand) {
                 final int expandRatio = getExpandRatio(column,
-                        someColumnExpands);
-                final double autoWidth = column.getWidthActual();
-                final double totalWidth = autoWidth + widthPerRatio
-                        * expandRatio;
-                column.doSetWidth(totalWidth);
+                        defaultExpandRatios);
+                final double autoWidth = columnSizes.get(indexOfColumn(column));
+                double totalWidth = autoWidth + widthPerRatio * expandRatio;
+                if (leftOver > 0) {
+                    totalWidth += 1;
+                    leftOver--;
+                }
+                columnSizes.put(indexOfColumn(column), totalWidth);
 
                 totalRatios -= expandRatio;
             }
@@ -2679,12 +2658,12 @@ public class Grid<T> extends ResizeComposite implements
                      * wouldn't show up in that set.
                      */
 
-                    // [[subpixelworkaround]] (6.2.2015, Henrik Paul) FIXME ceil
-                    double minWidth = Math.ceil(getMinWidth(column));
-                    double currentWidth = column.getWidthActual();
+                    double minWidth = getMinWidth(column);
+                    double currentWidth = columnSizes
+                            .get(indexOfColumn(column));
                     boolean hasAutoWidth = column.getWidth() < 0;
                     if (hasAutoWidth && currentWidth < minWidth) {
-                        column.doSetWidth(minWidth);
+                        columnSizes.put(indexOfColumn(column), minWidth);
                         pixelsToRemoveFromOtherColumns += (minWidth - currentWidth);
                         minWidthsCausedReflows = true;
 
@@ -2703,27 +2682,36 @@ public class Grid<T> extends ResizeComposite implements
                  */
                 totalRatios = 0;
                 for (Column<?, ?> column : columnsToExpand) {
-                    totalRatios += getExpandRatio(column, someColumnExpands);
+                    totalRatios += getExpandRatio(column, defaultExpandRatios);
                 }
-                // [[subpixelworkaround]] (6.2.2015, Henrik Paul) FIXME: ceil
-                final double pixelsToRemovePerRatio = Math
-                        .ceil(pixelsToRemoveFromOtherColumns / totalRatios);
-                for (Column<?, ?> column : columnsToExpand) {
+                final double pixelsToRemovePerRatio = pixelsToRemoveFromOtherColumns
+                        / totalRatios;
+                for (Column<?, T> column : columnsToExpand) {
                     final double pixelsToRemove = pixelsToRemovePerRatio
-                            * getExpandRatio(column, someColumnExpands);
-                    column.doSetWidth(column.getWidthActual() - pixelsToRemove);
+                            * getExpandRatio(column, defaultExpandRatios);
+                    int colIndex = indexOfColumn(column);
+                    columnSizes.put(colIndex, columnSizes.get(colIndex)
+                            - pixelsToRemove);
                 }
 
             } while (minWidthsCausedReflows);
+
+            // Finally set all the column sizes.
+            setColumnSizes(columnSizes);
+        }
+
+        private void setColumnSizes(Map<Integer, Double> columnSizes) {
+            // Set all widths at once
+            escalator.getColumnConfiguration().setColumnWidths(columnSizes);
         }
 
         private int getExpandRatio(Column<?, ?> column,
-                boolean someColumnExpands) {
+                boolean defaultExpandRatios) {
             int expandRatio = column.getExpandRatio();
             if (expandRatio > 0) {
                 return expandRatio;
             } else if (expandRatio < 0) {
-                assert !someColumnExpands : "No columns should've expanded";
+                assert defaultExpandRatios : "No columns should've expanded";
                 return 1;
             } else {
                 assert false : "this method should've not been called at all if expandRatio is 0";
@@ -6192,9 +6180,7 @@ public class Grid<T> extends ResizeComposite implements
 
             @Override
             public void execute() {
-                if (!autoColumnWidthsRecalculator.isScheduled()) {
-                    autoColumnWidthsRecalculator.schedule();
-                }
+                recalculateColumnWidths();
             }
         });
     }
index bf9110b01def5b48c44b4c4f8ece335b38c8f8de..96b1a56fba89071b52d230098919e50b9f7c6ad2 100644 (file)
 package com.vaadin.tests.components.grid;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
 
 import org.junit.Test;
+import org.openqa.selenium.remote.DesiredCapabilities;
 
 import com.vaadin.testbench.elements.ButtonElement;
 import com.vaadin.testbench.elements.GridElement;
+import com.vaadin.testbench.parallel.BrowserUtil;
 import com.vaadin.tests.tb3.MultiBrowserTest;
 
 public class GridWidthIncreaseTest extends MultiBrowserTest {
@@ -29,28 +32,37 @@ public class GridWidthIncreaseTest extends MultiBrowserTest {
     private static int INCREASE_COUNT = 3;
 
     @Test
-    public void testColumnsExpandWithGrid() {
+    public void testColumnsExpandWithGrid() throws IOException {
         openTestURL();
 
         GridElement grid = $(GridElement.class).first();
 
-        int[] widths = new int[GridWidthIncrease.COLUMN_COUNT];
+        double accuracy = 1.0d;
+        DesiredCapabilities cap = getDesiredCapabilities();
+        if (BrowserUtil.isIE(cap, 8) || BrowserUtil.isIE(cap, 9)
+                || BrowserUtil.isPhantomJS(cap)) {
+            accuracy = 2.0d;
+        }
+
         for (int i = 0; i < INCREASE_COUNT; ++i) {
-            int totalWidth = 0;
             $(ButtonElement.class).first().click();
+            int prevWidth = 0;
             for (int c = 0; c < GridWidthIncrease.COLUMN_COUNT; ++c) {
                 int width = grid.getCell(0, c).getSize().getWidth();
-                totalWidth += width;
-                widths[c] = width;
                 if (c > 0) {
                     // check that columns are roughly the same width.
-                    assertEquals("Difference in column widths", widths[c],
-                            widths[c - 1], 1.0d);
+                    assertEquals("Difference in column widths", prevWidth,
+                            width, accuracy);
                 }
+                prevWidth = width;
             }
-            // Column widths should be the same as table wrapper size
-            assertTrue(totalWidth == grid.getTableWrapper().getSize()
-                    .getWidth());
+            /*
+             * Column widths should be the same as table wrapper size. Since
+             * Selenium doesn't support subpixels correctly, we use a rough
+             * estimation.
+             */
+            assertEquals(grid.getRow(0).getSize().getWidth(), grid
+                    .getTableWrapper().getSize().getWidth(), accuracy);
         }
     }
 }
index 2ba1dbc3113cdca6188cb967d1f2f153f2eb737c..9e7256e0d3f43598dadf1ccc88cf45a70f634b41 100644 (file)
@@ -145,14 +145,12 @@ public class GridClientColumnPropertiesTest extends GridBasicClientFeaturesTest
         gridElement = getGridElement();
         headerCells = gridElement.getHeaderCells(0);
         final int size = headerCells.size();
-        // skip last column since there is a bug in the width of the last column
-        for (int i = 0; i < size - 1; i++) {
+        for (int i = 0; i < size; i++) {
+            // Avoid issues with inaccuracies regarding subpixels.
             assertEquals(
                     "Column widths don't match after reset, index after flip "
-                            + i,
-                    columnWidths.get(i),
-                    Integer.valueOf(headerCells.get(size - 1 - i).getSize()
-                            .getWidth()));
+                            + i, columnWidths.get(i),
+                    headerCells.get(size - 1 - i).getSize().getWidth(), 1.0d);
         }
 
     }