]> source.dussan.org Git - vaadin-framework.git/commitdiff
Columns can now have subpixel accuracy widths (#13334)
authorHenrik Paul <henrik@vaadin.com>
Sun, 7 Dec 2014 23:02:29 +0000 (01:02 +0200)
committerHenrik Paul <henrik@vaadin.com>
Fri, 12 Dec 2014 07:44:00 +0000 (09:44 +0200)
Change-Id: I1d16260be7b15c9fbdbfdd8f51e50e9f34e96272

13 files changed:
client/src/com/vaadin/client/ui/grid/ColumnConfiguration.java
client/src/com/vaadin/client/ui/grid/Escalator.java
client/src/com/vaadin/client/ui/grid/FlyweightCell.java
client/src/com/vaadin/client/ui/grid/FlyweightRow.java
client/src/com/vaadin/client/ui/grid/Grid.java
client/src/com/vaadin/client/ui/grid/GridUtil.java
client/src/com/vaadin/client/ui/grid/ScrollbarBundle.java
server/src/com/vaadin/ui/Grid.java
server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java
shared/src/com/vaadin/shared/ui/grid/GridColumnState.java
uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java.orig [new file with mode: 0644]
uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorProxy.java

index 6c304ddaea07fac366d0d2950155317e828c8d48..88f07e023fa32915abfe5fbda9353f0a677c5a49 100644 (file)
@@ -123,7 +123,7 @@ public interface ColumnConfiguration {
      * @throws IllegalArgumentException
      *             if <code>index</code> is not a valid column index
      */
-    public void setColumnWidth(int index, int px)
+    public void setColumnWidth(int index, double px)
             throws IllegalArgumentException;
 
     /**
@@ -136,7 +136,7 @@ public interface ColumnConfiguration {
      * @throws IllegalArgumentException
      *             if <code>index</code> is not a valid column index
      */
-    public int getColumnWidth(int index) throws IllegalArgumentException;
+    public double getColumnWidth(int index) throws IllegalArgumentException;
 
     /**
      * Returns the actual width of a column.
@@ -147,7 +147,8 @@ public interface ColumnConfiguration {
      * @throws IllegalArgumentException
      *             if <code>index</code> is not a valid column index
      */
-    public int getColumnWidthActual(int index) throws IllegalArgumentException;
+    public double getColumnWidthActual(int index)
+            throws IllegalArgumentException;
 
     /**
      * Refreshes a range of rows in the current row containers in each Escalator
index 1bbcaaf1663be536da9a01a3be9da8dd43053944..3ea7d94282acf3e57c5dee45d432a495fd2dfd01 100644 (file)
@@ -744,7 +744,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
          */
         public void recalculateScrollbarsForVirtualViewport() {
             int scrollContentHeight = body.calculateEstimatedTotalRowHeight();
-            int scrollContentWidth = columnConfiguration.calculateRowWidth();
+            double scrollContentWidth = columnConfiguration.calculateRowWidth();
 
             double tableWrapperHeight = heightOfEscalator;
             double tableWrapperWidth = widthOfEscalator;
@@ -789,11 +789,11 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
              */
             double prevScrollPos = horizontalScrollbar.getScrollPos();
 
-            int unfrozenPixels = columnConfiguration
+            double unfrozenPixels = columnConfiguration
                     .getCalculatedColumnsWidth(Range.between(
                             columnConfiguration.getFrozenColumnCount(),
                             columnConfiguration.getColumnCount()));
-            int frozenPixels = scrollContentWidth - unfrozenPixels;
+            double frozenPixels = scrollContentWidth - unfrozenPixels;
             double hScrollOffsetWidth = tableWrapperWidth - frozenPixels;
             horizontalScrollbar.setOffsetSize(hScrollOffsetWidth);
             horizontalScrollbar.setScrollSize(unfrozenPixels);
@@ -1034,19 +1034,19 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
              * structure effectively means that scrollLeft also ignores the
              * frozen columns.
              */
-            final int frozenPixels = columnConfiguration
+            final double frozenPixels = columnConfiguration
                     .getCalculatedColumnsWidth(Range.withLength(0,
                             columnConfiguration.frozenColumns));
 
-            final int targetStartPx = columnConfiguration
+            final double targetStartPx = columnConfiguration
                     .getCalculatedColumnsWidth(Range.withLength(0, columnIndex))
                     - frozenPixels;
-            final int targetEndPx = targetStartPx
+            final double targetEndPx = targetStartPx
                     + columnConfiguration.getColumnWidthActual(columnIndex);
 
             final double viewportStartPx = getScrollLeft();
             double viewportEndPx = viewportStartPx
-                    + getElement().getOffsetWidth() - frozenPixels;
+                    + getPreciseWidth(getElement()) - frozenPixels;
             if (verticalScrollbar.showsScrollHandle()) {
                 viewportEndPx -= Util.getNativeScrollbarSize();
             }
@@ -1399,7 +1399,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
                 tr.addClassName(getStylePrimaryName() + "-row");
 
                 for (int col = 0; col < columnConfiguration.getColumnCount(); col++) {
-                    final int colWidth = columnConfiguration
+                    final double colWidth = columnConfiguration
                             .getColumnWidthActual(col);
                     final TableCellElement cellElem = createCellElement(
                             rowHeight, colWidth);
@@ -1542,11 +1542,11 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
          * @return a set-up empty cell element
          */
         public TableCellElement createCellElement(final int height,
-                final int width) {
+                final double colWidth) {
             final TableCellElement cellElem = TableCellElement.as(DOM
                     .createElement(getCellElementTagName()));
             cellElem.getStyle().setHeight(height, Unit.PX);
-            cellElem.getStyle().setWidth(width, Unit.PX);
+            cellElem.getStyle().setWidth(colWidth, Unit.PX);
             cellElem.addClassName(getStylePrimaryName() + "-cell");
             return cellElem;
         }
@@ -1640,7 +1640,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
 
             final int rowHeight = getDefaultRowHeight();
             for (FlyweightCell cell : cells) {
-                final int colWidth = columnConfiguration
+                final double colWidth = columnConfiguration
                         .getColumnWidthActual(cell.getColumn());
                 final TableCellElement cellElem = createCellElement(rowHeight,
                         colWidth);
@@ -1706,16 +1706,16 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
          *            the index of the column to inspect
          * @return the pixel width of the widest element in the indicated column
          */
-        public int calculateMaxColWidth(int index) {
+        public double calculateMaxColWidth(int index) {
             TableRowElement row = TableRowElement.as(root
                     .getFirstChildElement());
-            int maxWidth = 0;
+            double maxWidth = 0;
             while (row != null) {
                 final TableCellElement cell = row.getCells().getItem(index);
                 final boolean isVisible = !cell.getStyle().getDisplay()
                         .equals(Display.NONE.getCssName());
                 if (isVisible) {
-                    maxWidth = Math.max(maxWidth, cell.getScrollWidth());
+                    maxWidth = Math.max(maxWidth, getPreciseWidth(cell));
                 }
                 row = TableRowElement.as(row.getNextSiblingElement());
             }
@@ -1732,8 +1732,8 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
                 Element cell = row.getFirstChildElement();
                 int columnIndex = 0;
                 while (cell != null) {
-                    final int width = getCalculatedColumnWidthWithColspan(cell,
-                            columnIndex);
+                    final double width = getCalculatedColumnWidthWithColspan(
+                            cell, columnIndex);
 
                     /*
                      * TODO Should Escalator implement ProvidesResize at some
@@ -1750,7 +1750,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
             reapplyRowWidths();
         }
 
-        private int getCalculatedColumnWidthWithColspan(final Element cell,
+        private double getCalculatedColumnWidthWithColspan(final Element cell,
                 final int columnIndex) {
             final int colspan = cell.getPropertyInt(FlyweightCell.COLSPAN_ATTR);
             Range spannedColumns = Range.withLength(columnIndex, colspan);
@@ -1775,7 +1775,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
          * cells within.
          */
         protected void reapplyRowWidths() {
-            int rowWidth = columnConfiguration.calculateRowWidth();
+            double rowWidth = columnConfiguration.calculateRowWidth();
 
             com.google.gwt.dom.client.Element row = root.getFirstChildElement();
             while (row != null) {
@@ -1957,8 +1957,8 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
             return new Cell(domRowIndex, domColumnIndex, cellElement);
         }
 
-        int getMaxCellWidth(int colIndex) throws IllegalArgumentException {
-            int maxCellWidth = -1;
+        double getMaxCellWidth(int colIndex) throws IllegalArgumentException {
+            double maxCellWidth = -1;
 
             assert isAttached() : "Can't measure max width of cell, since Escalator is not attached to the DOM.";
 
@@ -1988,7 +1988,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
                 cellClone.getStyle().clearWidth();
 
                 rowElement.insertBefore(cellClone, cellOriginal);
-                maxCellWidth = Math.max(cellClone.getOffsetWidth(),
+                maxCellWidth = Math.max(getPreciseWidth(cellClone),
                         maxCellWidth);
                 cellClone.removeFromParent();
             }
@@ -3684,8 +3684,8 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
         public class Column {
             private static final int DEFAULT_COLUMN_WIDTH_PX = 100;
 
-            private int definedWidth = -1;
-            private int calculatedWidth = DEFAULT_COLUMN_WIDTH_PX;
+            private double definedWidth = -1;
+            private double calculatedWidth = DEFAULT_COLUMN_WIDTH_PX;
             private boolean measuringRequested = false;
 
             /**
@@ -3695,7 +3695,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
              */
             private boolean widthHasBeenFinalized = false;
 
-            public void setWidth(int px) {
+            public void setWidth(double px) {
                 definedWidth = px;
 
                 if (px < 0) {
@@ -3713,7 +3713,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
                 }
             }
 
-            public int getDefinedWidth() {
+            public double getDefinedWidth() {
                 return definedWidth;
             }
 
@@ -3723,7 +3723,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
              * @return the width in pixels in the DOM. Returns -1 if the column
              *         needs measuring, but has not been yet measured
              */
-            public int getCalculatedWidth() {
+            public double getCalculatedWidth() {
                 /*
                  * This might return an untrue value (e.g. during init/onload),
                  * since we haven't had a proper chance to actually calculate
@@ -3777,7 +3777,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
          * 
          * @see #getCalculatedColumnWidths()
          */
-        private int[] widthsArray = null;
+        private double[] widthsArray = null;
 
         /**
          * {@inheritDoc}
@@ -3884,7 +3884,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
          * 
          * @return the width of a row, in pixels
          */
-        public int calculateRowWidth() {
+        public double calculateRowWidth() {
             return getCalculatedColumnsWidth(Range.between(0, getColumnCount()));
         }
 
@@ -3966,12 +3966,12 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
             }
 
             // Adjust scrollbar
-            int pixelsToInsertedColumn = columnConfiguration
+            double pixelsToInsertedColumn = columnConfiguration
                     .getCalculatedColumnsWidth(Range.withLength(0, index));
             final boolean columnsWereAddedToTheLeftOfViewport = scroller.lastScrollLeft > pixelsToInsertedColumn;
 
             if (columnsWereAddedToTheLeftOfViewport) {
-                int insertedColumnsWidth = columnConfiguration
+                double insertedColumnsWidth = columnConfiguration
                         .getCalculatedColumnsWidth(Range.withLength(index,
                                 numberOfColumns));
                 horizontalScrollbar.setScrollPos(scroller.lastScrollLeft
@@ -4042,7 +4042,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
         }
 
         @Override
-        public void setColumnWidth(int index, int px)
+        public void setColumnWidth(int index, double px)
                 throws IllegalArgumentException {
             checkValidColumnIndex(index);
 
@@ -4069,25 +4069,25 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
         }
 
         @Override
-        public int getColumnWidth(int index) throws IllegalArgumentException {
+        public double getColumnWidth(int index) throws IllegalArgumentException {
             checkValidColumnIndex(index);
             return columns.get(index).getDefinedWidth();
         }
 
         @Override
-        public int getColumnWidthActual(int index) {
+        public double getColumnWidthActual(int index) {
             return columns.get(index).getCalculatedWidth();
         }
 
-        private int getMaxCellWidth(int colIndex)
+        private double getMaxCellWidth(int colIndex)
                 throws IllegalArgumentException {
-            int headerWidth = header.getMaxCellWidth(colIndex);
-            int bodyWidth = body.getMaxCellWidth(colIndex);
-            int footerWidth = footer.getMaxCellWidth(colIndex);
+            double headerWidth = header.getMaxCellWidth(colIndex);
+            double bodyWidth = body.getMaxCellWidth(colIndex);
+            double footerWidth = footer.getMaxCellWidth(colIndex);
 
-            int maxWidth = Math.max(headerWidth,
+            double maxWidth = Math.max(headerWidth,
                     Math.max(bodyWidth, footerWidth));
-            assert maxWidth > 0 : "Got a negative max width for a column, which should be impossible.";
+            assert maxWidth >= 0 : "Got a negative max width for a column, which should be impossible.";
             return maxWidth;
         }
 
@@ -4099,7 +4099,7 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
          * @return the total width of the columns in the given
          *         <code>columns</code>
          */
-        int getCalculatedColumnsWidth(final Range columns) {
+        double getCalculatedColumnsWidth(final Range columns) {
             /*
              * This is an assert instead of an exception, since this is an
              * internal method.
@@ -4110,17 +4110,17 @@ public class Escalator extends Widget implements RequiresResize, DeferredWorker
                     + ", but was given :"
                     + columns;
 
-            int sum = 0;
+            double sum = 0;
             for (int i = columns.getStart(); i < columns.getEnd(); i++) {
-                int columnWidthActual = getColumnWidthActual(i);
+                double columnWidthActual = getColumnWidthActual(i);
                 sum += columnWidthActual;
             }
             return sum;
         }
 
-        int[] getCalculatedColumnWidths() {
+        double[] getCalculatedColumnWidths() {
             if (widthsArray == null || widthsArray.length != getColumnCount()) {
-                widthsArray = new int[getColumnCount()];
+                widthsArray = new double[getColumnCount()];
                 for (int i = 0; i < columns.size(); i++) {
                     widthsArray[i] = columns.get(i).getCalculatedWidth();
                 }
index adcca1b630b6af85108976d1f0c65ef0891a2a68..fe826b16c3f5185e0d0b9217e35cc1a4715cba84 100644 (file)
@@ -169,8 +169,8 @@ public class FlyweightCell {
         final int cellsToTheRight = currentIterator.rawPeekNext(
                 numberOfCells - 1).size();
 
-        final int selfWidth = row.getColumnWidth(column);
-        int widthsOfColumnsToTheRight = 0;
+        final double selfWidth = row.getColumnWidth(column);
+        double widthsOfColumnsToTheRight = 0;
         for (int i = 0; i < cellsToTheRight; i++) {
             widthsOfColumnsToTheRight += row.getColumnWidth(column + i + 1);
         }
index 0e9c6ad95547f9121eb93d1cb1e0621968107dee..9f913f5cd1f2fbd3e4819b0e3d1376e032b96910 100644 (file)
@@ -140,10 +140,10 @@ class FlyweightRow implements Row {
 
     private int row;
     private TableRowElement element;
-    private int[] columnWidths = null;
+    private double[] columnWidths = null;
     private final List<FlyweightCell> cells = new ArrayList<FlyweightCell>();
 
-    void setup(final TableRowElement e, final int row, int[] columnWidths) {
+    void setup(final TableRowElement e, final int row, double[] columnWidths) {
         element = e;
         this.row = row;
         this.columnWidths = columnWidths;
@@ -285,7 +285,7 @@ class FlyweightRow implements Row {
                 + "has been stored and accessed.";
     }
 
-    int getColumnWidth(int column) {
+    double getColumnWidth(int column) {
         assertSetup();
         return columnWidths[column];
     }
index c6d7e22d3b00db810c8cdc03d3960e3706a17224..80ecc9a9e9f74e92c5a09315b28eba815671f929 100644 (file)
@@ -1875,7 +1875,7 @@ public class Grid<T> extends ResizeComposite implements
         }
 
         @Override
-        public GridColumn<Boolean, T> setWidth(int pixels) {
+        public GridColumn<Boolean, T> setWidth(double pixels) {
             if (pixels != getWidth() && initDone) {
                 throw new UnsupportedOperationException("The selection "
                         + "column cannot be modified after init");
@@ -2208,8 +2208,11 @@ public class Grid<T> extends ResizeComposite implements
          */
         private boolean visible = true;
 
-        /** Width of column in pixels as {@link #setWidth(int)} has been called */
-        private int widthUser = GridColumnState.DEFAULT_COLUMN_WIDTH_PX;
+        /**
+         * Width of column in pixels as {@link #setWidth(double)} has been
+         * called
+         */
+        private double widthUser = GridColumnState.DEFAULT_COLUMN_WIDTH_PX;
 
         /**
          * Renderer for rendering a value into the cell
@@ -2387,7 +2390,7 @@ public class Grid<T> extends ResizeComposite implements
          *            the width in pixels or negative for auto sizing
          * @return the column itself
          */
-        public GridColumn<C, T> setWidth(int pixels) {
+        public GridColumn<C, T> setWidth(double pixels) {
             widthUser = pixels;
             if (pixels < 0) {
                 setWidthAutodetect();
@@ -2409,14 +2412,14 @@ public class Grid<T> extends ResizeComposite implements
              */
         }
 
-        private void setWidthAbsolute(int pixels) {
+        private void setWidthAbsolute(double pixels) {
             asyncAutodetectWidth.stop();
             if (grid != null) {
                 setWidthForce(pixels);
             }
         }
 
-        private void setWidthForce(int pixels) {
+        private void setWidthForce(double pixels) {
             int index = grid.columns.indexOf(this);
             ColumnConfiguration conf = grid.escalator.getColumnConfiguration();
             conf.setColumnWidth(index, pixels);
@@ -2426,14 +2429,14 @@ public class Grid<T> extends ResizeComposite implements
          * Returns the pixel width of the column as given by the user.
          * <p>
          * <em>Note:</em> If a negative value was given to
-         * {@link #setWidth(int)}, that same negative value is returned here.
+         * {@link #setWidth(double)}, that same negative value is returned here.
          * 
          * @return pixel width of the column, or a negative number if the column
          *         width has been automatically calculated.
-         * @see #setWidth(int)
+         * @see #setWidth(double)
          * @see #getWidthActual()
          */
-        public int getWidth() {
+        public double getWidth() {
             return widthUser;
         }
 
@@ -2445,7 +2448,7 @@ public class Grid<T> extends ResizeComposite implements
          * 
          * @return pixel width of the column.
          */
-        public int getWidthActual() {
+        public double getWidthActual() {
             return grid.escalator.getColumnConfiguration()
                     .getColumnWidthActual(grid.columns.indexOf(this));
         }
index 0eed0e98b5e6823196d4e79f820ecb2ca911a8f6..8dc0822d9d8ebbea5e63916d7570a2b0caea91b8 100644 (file)
@@ -16,7 +16,6 @@
 package com.vaadin.client.ui.grid;
 
 import com.google.gwt.dom.client.Element;
-import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.client.Util;
 
@@ -28,9 +27,18 @@ import com.vaadin.client.Util;
  */
 public class GridUtil {
 
+    /**
+     * The allowed value inaccuracy when comparing two double-typed pixel
+     * values.
+     * <p>
+     * Since we're comparing pixels on a screen, epsilon must be less than 1.
+     * 0.49 was deemed a perfectly fine and beautifully round number.
+     */
+    public static final double PIXEL_EPSILON = 0.49d;
+
     /**
      * Returns the cell the given element belongs to.
-     *
+     * 
      * @param grid
      *            the grid instance that is queried
      * @param e
@@ -78,4 +86,17 @@ public class GridUtil {
         widget.@com.google.gwt.user.client.ui.Widget::setParent(Lcom/google/gwt/user/client/ui/Widget;)(parent);
     }-*/;
 
+    /**
+     * Compares two double values with the error margin of
+     * {@link #PIXEL_EPSILON} (i.e. {@value #PIXEL_EPSILON})
+     * 
+     * @param num1
+     *            the first value for which to compare equality
+     * @param num2
+     *            the second value for which to compare equality
+     */
+    public static boolean pixelValuesEqual(final double num1, final double num2) {
+        return Math.abs(num1 - num2) <= PIXEL_EPSILON;
+    }
+
 }
index a2df48e6c67faaa0389da9f52395441a6dc52a30..7d6d050e64308775b5efd24e3d398bc18206f7d7 100644 (file)
@@ -178,15 +178,6 @@ abstract class ScrollbarBundle {
      */
     private static final int OSX_INVISIBLE_SCROLLBAR_FAKE_SIZE_PX = 13;
 
-    /**
-     * The allowed value inaccuracy when comparing two double-typed pixel
-     * values.
-     * <p>
-     * Since we're comparing pixels on a screen, epsilon must be less than 1.
-     * 0.49 was deemed a perfectly fine and beautifully round number.
-     */
-    private static final double PIXEL_EPSILON = 0.49d;
-
     /**
      * A representation of a single vertical scrollbar.
      * 
@@ -211,7 +202,7 @@ abstract class ScrollbarBundle {
         }
 
         @Override
-        protected void internalSetScrollSize(int px) {
+        protected void internalSetScrollSize(double px) {
             scrollSizeElement.getStyle().setHeight(px, Unit.PX);
         }
 
@@ -280,7 +271,7 @@ abstract class ScrollbarBundle {
         }
 
         @Override
-        protected void internalSetScrollSize(int px) {
+        protected void internalSetScrollSize(double px) {
             scrollSizeElement.getStyle().setWidth(px, Unit.PX);
         }
 
@@ -451,7 +442,7 @@ abstract class ScrollbarBundle {
         double oldScrollPos = scrollPos;
         scrollPos = Math.max(0, Math.min(maxScrollPos, truncate(px)));
 
-        if (!pixelValuesEqual(oldScrollPos, scrollPos)) {
+        if (!GridUtil.pixelValuesEqual(oldScrollPos, scrollPos)) {
             if (isInvisibleScrollbar) {
                 invisibleScrollbarTemporaryResizer.show();
             }
@@ -533,7 +524,7 @@ abstract class ScrollbarBundle {
      *            the new size of {@link #scrollSizeElement} in the dimension
      *            this scrollbar is representing
      */
-    protected abstract void internalSetScrollSize(int px);
+    protected abstract void internalSetScrollSize(double px);
 
     /**
      * Sets the amount of pixels the scrollbar needs to be able to scroll
@@ -549,7 +540,7 @@ abstract class ScrollbarBundle {
      *            through
      */
     public final void setScrollSize(double px) {
-        internalSetScrollSize(toInt32(Math.max(0, truncate(px))));
+        internalSetScrollSize(Math.max(0, px));
         forceScrollbar(showsScrollHandle());
         recalculateMaxScrollPos();
         fireVisibilityChangeIfNeeded();
@@ -718,19 +709,6 @@ abstract class ScrollbarBundle {
         return val | 0;
     }-*/;
 
-    /**
-     * Compares two double values with the error margin of
-     * {@link #PIXEL_EPSILON} (i.e. {@value #PIXEL_EPSILON})
-     * 
-     * @param num1
-     *            the first value for which to compare equality
-     * @param num2
-     *            the second value for which to compare equality
-     */
-    private static boolean pixelValuesEqual(final double num1, final double num2) {
-        return Math.abs(num1 - num2) <= PIXEL_EPSILON;
-    }
-
     /**
      * Locks or unlocks the scrollbar bundle.
      * <p>
index 838829b9cc25611a7fd2e43a646f57173c51681a..d0485c3d682ed85a36429727320cb682e4348da0 100644 (file)
@@ -64,7 +64,6 @@ import com.vaadin.event.SortOrderChangeEvent.SortOrderChangeListener;
 import com.vaadin.event.SortOrderChangeEvent.SortOrderChangeNotifier;
 import com.vaadin.server.AbstractClientConnector;
 import com.vaadin.server.AbstractExtension;
-import com.vaadin.server.ClientConnector;
 import com.vaadin.server.ErrorHandler;
 import com.vaadin.server.ErrorMessage;
 import com.vaadin.server.JsonCodec;
@@ -1643,7 +1642,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier,
          * @throws IllegalStateException
          *             if the column is no longer attached to any grid
          */
-        public int getWidth() throws IllegalStateException {
+        public double getWidth() throws IllegalStateException {
             checkColumnIsAttached();
             return state.width;
         }
@@ -1660,7 +1659,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier,
          * @throws IllegalArgumentException
          *             thrown if pixel width is less than zero
          */
-        public Column setWidth(int pixelWidth) throws IllegalStateException,
+        public Column setWidth(double pixelWidth) throws IllegalStateException,
                 IllegalArgumentException {
             checkColumnIsAttached();
             if (pixelWidth < 0) {
@@ -2518,7 +2517,7 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier,
      * 
      * @return unmodifiable copy of current columns in visual order
      */
-    public Collection<Column> getColumns() {
+    public List<Column> getColumns() {
         List<Column> columns = new ArrayList<Grid.Column>();
         for (String columnId : getState(false).columnOrder) {
             columns.add(getColumnByColumnId(columnId));
index 366176c3fad3c3c5b5c3b1e7e8d2656add518962..1204b1e39653517b7f67cfdb02dfb706c12f81a2 100644 (file)
@@ -100,18 +100,18 @@ public class GridColumns {
                 .getCell("column1").getText());
 
         column.setWidth(100);
-        assertEquals(100, column.getWidth());
-        assertEquals(column.getWidth(), getColumnState("column1").width);
+        assertEquals(100, column.getWidth(), 0.49d);
+        assertEquals(column.getWidth(), getColumnState("column1").width, 0.49d);
 
         try {
             column.setWidth(-1);
             fail("Setting width to -1 should throw exception");
         } catch (IllegalArgumentException iae) {
-
+            // expected
         }
 
-        assertEquals(100, column.getWidth());
-        assertEquals(100, getColumnState("column1").width);
+        assertEquals(100, column.getWidth(), 0.49d);
+        assertEquals(100, getColumnState("column1").width, 0.49d);
     }
 
     @Test
index 751b262570a494290329d7de7e7ac90f7f222497..65a5ed625d24b30678b044f0cbbb8d24ce2f6959 100644 (file)
@@ -28,7 +28,7 @@ import com.vaadin.shared.Connector;
  */
 public class GridColumnState implements Serializable {
 
-    public static final int DEFAULT_COLUMN_WIDTH_PX = -1;
+    public static final double DEFAULT_COLUMN_WIDTH_PX = -1;
 
     /**
      * Id used by grid connector to map server side column with client side
@@ -40,7 +40,7 @@ public class GridColumnState implements Serializable {
      * Column width in pixels. Default column width is
      * {@value #DEFAULT_COLUMN_WIDTH_PX}.
      */
-    public int width = DEFAULT_COLUMN_WIDTH_PX;
+    public double width = DEFAULT_COLUMN_WIDTH_PX;
 
     /**
      * The connector for the renderer used to render the cells in this column.
index 043ff2e2e0a94627645f7fb129f0040e444fc8cb..e61edb4e65f0d6036564d9289c392acb6c88a263 100644 (file)
@@ -538,6 +538,17 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
                         }
                     }, -1, c);
 
+            createClickAction("25.5px", "Column " + c + " Width",
+                    new Command<Grid, Void>() {
+                        @Override
+                        @SuppressWarnings("boxing")
+                        public void execute(Grid grid, Void value,
+                                Object columnIndex) {
+                            grid.getColumns().get((Integer) columnIndex)
+                                    .setWidth(25.5);
+                        }
+                    }, null, c);
+
             for (int w = 50; w < 300; w += 50) {
                 createClickAction(w + "px", "Column " + c + " Width",
                         new Command<Grid, Integer>() {
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java.orig b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java.orig
new file mode 100644 (file)
index 0000000..5d7fa04
--- /dev/null
@@ -0,0 +1,922 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.grid.basicfeatures;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Random;
+
+import com.vaadin.data.Container.Filter;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
+import com.vaadin.data.sort.Sort;
+import com.vaadin.data.sort.SortOrder;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.event.SortOrderChangeEvent;
+import com.vaadin.event.SortOrderChangeEvent.SortOrderChangeListener;
+import com.vaadin.shared.ui.grid.GridStaticCellType;
+import com.vaadin.shared.ui.grid.HeightMode;
+import com.vaadin.shared.ui.grid.SortDirection;
+import com.vaadin.tests.components.AbstractComponentTest;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.CellStyleGenerator;
+import com.vaadin.ui.Grid.Column;
+import com.vaadin.ui.Grid.FooterCell;
+import com.vaadin.ui.Grid.HeaderCell;
+import com.vaadin.ui.Grid.HeaderRow;
+import com.vaadin.ui.Grid.MultiSelectionModel;
+import com.vaadin.ui.Grid.SelectionMode;
+<<<<<<< HEAD
+import com.vaadin.ui.renderer.DateRenderer;
+import com.vaadin.ui.renderer.HtmlRenderer;
+import com.vaadin.ui.renderer.NumberRenderer;
+=======
+import com.vaadin.ui.components.grid.SortOrderChangeEvent;
+import com.vaadin.ui.components.grid.SortOrderChangeListener;
+import com.vaadin.ui.components.grid.renderers.DateRenderer;
+import com.vaadin.ui.components.grid.renderers.HtmlRenderer;
+import com.vaadin.ui.components.grid.renderers.NumberRenderer;
+import com.vaadin.ui.components.grid.selection.MultiSelectionModel;
+import com.vaadin.ui.components.grid.sort.Sort;
+import com.vaadin.ui.components.grid.sort.SortOrder;
+>>>>>>> Columns can now have subpixel accuracy widths (#13334)
+
+/**
+ * Tests the basic features like columns, footers and headers
+ * 
+ * @since
+ * @author Vaadin Ltd
+ */
+public class GridBasicFeatures extends AbstractComponentTest<Grid> {
+
+    private static final int MANUALLY_FORMATTED_COLUMNS = 5;
+    public static final int COLUMNS = 12;
+    public static final int ROWS = 1000;
+
+    private int columnGroupRows = 0;
+    private IndexedContainer ds;
+    private Grid grid;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected Grid constructComponent() {
+
+        // Build data source
+        ds = new IndexedContainer() {
+            @Override
+            public List<Object> getItemIds(int startIndex, int numberOfIds) {
+                log("Requested items " + startIndex + " - "
+                        + (startIndex + numberOfIds));
+                return super.getItemIds(startIndex, numberOfIds);
+            }
+        };
+
+        {
+            int col = 0;
+            for (; col < COLUMNS - MANUALLY_FORMATTED_COLUMNS; col++) {
+                ds.addContainerProperty(getColumnProperty(col), String.class,
+                        "");
+            }
+
+            ds.addContainerProperty(getColumnProperty(col++), Integer.class,
+                    Integer.valueOf(0));
+            ds.addContainerProperty(getColumnProperty(col++), Date.class,
+                    new Date());
+            ds.addContainerProperty(getColumnProperty(col++), String.class, "");
+
+            // Random numbers
+            ds.addContainerProperty(getColumnProperty(col++), Integer.class, 0);
+            ds.addContainerProperty(getColumnProperty(col++), Integer.class, 0);
+
+        }
+
+        {
+            Random rand = new Random();
+            rand.setSeed(13334);
+            long timestamp = 0;
+            for (int row = 0; row < ROWS; row++) {
+                Item item = ds.addItem(Integer.valueOf(row));
+                int col = 0;
+                for (; col < COLUMNS - MANUALLY_FORMATTED_COLUMNS; col++) {
+                    item.getItemProperty(getColumnProperty(col)).setValue(
+                            "(" + row + ", " + col + ")");
+                }
+                item.getItemProperty(getColumnProperty(1)).setReadOnly(true);
+
+                item.getItemProperty(getColumnProperty(col++)).setValue(
+                        Integer.valueOf(row));
+                item.getItemProperty(getColumnProperty(col++)).setValue(
+                        new Date(timestamp));
+                timestamp += 91250000; // a bit over a day, just to get
+                                       // variation
+                item.getItemProperty(getColumnProperty(col++)).setValue(
+                        "<b>" + row + "</b>");
+
+                // Random numbers
+                item.getItemProperty(getColumnProperty(col++)).setValue(
+                        rand.nextInt());
+                // Random between 0 - 5 to test multisorting
+                item.getItemProperty(getColumnProperty(col++)).setValue(
+                        rand.nextInt(5));
+            }
+        }
+
+        // Create grid
+        Grid grid = new Grid(ds);
+
+        {
+            int col = grid.getContainerDataSource().getContainerPropertyIds()
+                    .size()
+                    - MANUALLY_FORMATTED_COLUMNS;
+            grid.getColumn(getColumnProperty(col++)).setRenderer(
+                    new NumberRenderer(new DecimalFormat("0,000.00",
+                            DecimalFormatSymbols.getInstance(new Locale("fi",
+                                    "FI")))));
+            grid.getColumn(getColumnProperty(col++)).setRenderer(
+                    new DateRenderer(new SimpleDateFormat("dd.MM.yy HH:mm")));
+            grid.getColumn(getColumnProperty(col++)).setRenderer(
+                    new HtmlRenderer());
+            grid.getColumn(getColumnProperty(col++)).setRenderer(
+                    new NumberRenderer());
+            grid.getColumn(getColumnProperty(col++)).setRenderer(
+                    new NumberRenderer());
+        }
+
+        // Create footer
+        grid.appendFooterRow();
+        grid.setFooterVisible(false);
+
+        // Add footer values (header values are automatically created)
+        for (int col = 0; col < COLUMNS; col++) {
+            grid.getFooterRow(0).getCell(getColumnProperty(col))
+                    .setText("Footer " + col);
+        }
+
+        // Set varying column widths
+        for (int col = 0; col < COLUMNS; col++) {
+            grid.getColumn(getColumnProperty(col)).setWidth(100 + col * 50);
+        }
+
+        grid.addSortOrderChangeListener(new SortOrderChangeListener() {
+            @Override
+            public void sortOrderChange(SortOrderChangeEvent event) {
+
+                log("SortOrderChangeEvent: isUserOriginated? "
+                        + event.isUserOriginated());
+            }
+        });
+
+        grid.setSelectionMode(SelectionMode.NONE);
+
+        grid.setPropertyEditable(getColumnProperty(3), false);
+
+        createGridActions();
+
+        createColumnActions();
+
+        createPropertyActions();
+
+        createHeaderActions();
+
+        createFooterActions();
+
+        createRowActions();
+
+        createEditorRowActions();
+
+        addHeightActions();
+
+        createClickAction("Column 1 starts with \"(23\"", "Filter",
+                new Command<Grid, Void>() {
+                    @Override
+                    public void execute(Grid grid, Void value, Object data) {
+                        ds.addContainerFilter(new Filter() {
+
+                            @Override
+                            public boolean passesFilter(Object itemId, Item item)
+                                    throws UnsupportedOperationException {
+                                return item.getItemProperty("Column 1")
+                                        .getValue().toString()
+                                        .startsWith("(23");
+                            }
+
+                            @Override
+                            public boolean appliesToProperty(Object propertyId) {
+                                return propertyId.equals("Column 1");
+                            }
+                        });
+                    }
+                }, null);
+
+        this.grid = grid;
+        return grid;
+    }
+
+    protected void createGridActions() {
+        LinkedHashMap<String, String> primaryStyleNames = new LinkedHashMap<String, String>();
+        primaryStyleNames.put("v-grid", "v-grid");
+        primaryStyleNames.put("v-escalator", "v-escalator");
+        primaryStyleNames.put("my-grid", "my-grid");
+
+        createMultiClickAction("Primary style name", "State",
+                primaryStyleNames, new Command<Grid, String>() {
+
+                    @Override
+                    public void execute(Grid grid, String value, Object data) {
+                        grid.setPrimaryStyleName(value);
+
+                    }
+                }, primaryStyleNames.get("v-grid"));
+
+        LinkedHashMap<String, SelectionMode> selectionModes = new LinkedHashMap<String, Grid.SelectionMode>();
+        selectionModes.put("single", SelectionMode.SINGLE);
+        selectionModes.put("multi", SelectionMode.MULTI);
+        selectionModes.put("none", SelectionMode.NONE);
+        createSelectAction("Selection mode", "State", selectionModes, "none",
+                new Command<Grid, Grid.SelectionMode>() {
+                    @Override
+                    public void execute(Grid grid, SelectionMode selectionMode,
+                            Object data) {
+                        grid.setSelectionMode(selectionMode);
+                    }
+                });
+
+        LinkedHashMap<String, Integer> selectionLimits = new LinkedHashMap<String, Integer>();
+        selectionLimits.put("2", Integer.valueOf(2));
+        selectionLimits.put("1000", Integer.valueOf(1000));
+        selectionLimits.put("Integer.MAX_VALUE",
+                Integer.valueOf(Integer.MAX_VALUE));
+        createSelectAction("Selection limit", "State", selectionLimits, "1000",
+                new Command<Grid, Integer>() {
+                    @Override
+                    public void execute(Grid grid, Integer limit, Object data) {
+                        if (!(grid.getSelectionModel() instanceof MultiSelectionModel)) {
+                            grid.setSelectionMode(SelectionMode.MULTI);
+                        }
+
+                        ((MultiSelectionModel) grid.getSelectionModel())
+                                .setSelectionLimit(limit.intValue());
+                    }
+                });
+
+        LinkedHashMap<String, List<SortOrder>> sortableProperties = new LinkedHashMap<String, List<SortOrder>>();
+        for (Object propertyId : ds.getSortableContainerPropertyIds()) {
+            sortableProperties.put(propertyId + ", ASC", Sort.by(propertyId)
+                    .build());
+            sortableProperties.put(propertyId + ", DESC",
+                    Sort.by(propertyId, SortDirection.DESCENDING).build());
+        }
+        createSelectAction("Sort by column", "State", sortableProperties,
+                "Column 9, ascending", new Command<Grid, List<SortOrder>>() {
+                    @Override
+                    public void execute(Grid grid, List<SortOrder> sortOrder,
+                            Object data) {
+                        grid.setSortOrder(sortOrder);
+                    }
+                });
+
+        createBooleanAction("Reverse Grid Columns", "State", false,
+                new Command<Grid, Boolean>() {
+
+                    @Override
+                    public void execute(Grid c, Boolean value, Object data) {
+                        List<Object> ids = new ArrayList<Object>();
+                        ids.addAll(ds.getContainerPropertyIds());
+                        if (!value) {
+                            c.setColumnOrder(ids.toArray());
+                        } else {
+                            Object[] idsArray = new Object[ids.size()];
+                            for (int i = 0; i < ids.size(); ++i) {
+                                idsArray[i] = ids.get((ids.size() - 1) - i);
+                            }
+                            c.setColumnOrder(idsArray);
+                        }
+                    }
+                });
+
+        LinkedHashMap<String, CellStyleGenerator> styleGenerators = new LinkedHashMap<String, CellStyleGenerator>();
+        styleGenerators.put("None", null);
+        styleGenerators.put("Row only", new CellStyleGenerator() {
+            @Override
+            public String getStyle(Grid grid, Object itemId, Object propertyId) {
+                if (propertyId == null) {
+                    return "row" + itemId;
+                } else {
+                    return null;
+                }
+            }
+        });
+        styleGenerators.put("Cell only", new CellStyleGenerator() {
+            @Override
+            public String getStyle(Grid grid, Object itemId, Object propertyId) {
+                if (propertyId == null) {
+                    return null;
+                } else {
+                    return propertyId.toString().replace(' ', '-');
+                }
+            }
+        });
+        styleGenerators.put("Combined", new CellStyleGenerator() {
+            @Override
+            public String getStyle(Grid grid, Object itemId, Object propertyId) {
+                int rowIndex = ((Integer) itemId).intValue();
+                if (propertyId == null) {
+                    if (rowIndex % 4 == 0) {
+                        return null;
+                    } else {
+                        return "row" + itemId;
+                    }
+                } else {
+                    if (rowIndex % 4 == 1) {
+                        return null;
+                    } else if (rowIndex % 4 == 3
+                            && "Column 1".equals(propertyId)) {
+                        return null;
+                    }
+                    return propertyId.toString().replace(' ', '_');
+                }
+            }
+        });
+        createSelectAction("Style generator", "State", styleGenerators, "None",
+                new Command<Grid, CellStyleGenerator>() {
+                    @Override
+                    public void execute(Grid grid,
+                            CellStyleGenerator generator, Object data) {
+                        grid.setCellStyleGenerator(generator);
+                    }
+                });
+
+        LinkedHashMap<String, Integer> frozenOptions = new LinkedHashMap<String, Integer>();
+        for (int i = -1; i <= COLUMNS; i++) {
+            frozenOptions.put(String.valueOf(i), Integer.valueOf(i));
+        }
+        createSelectAction("Frozen column count", "State", frozenOptions, "0",
+                new Command<Grid, Integer>() {
+                    @Override
+                    public void execute(Grid c, Integer value, Object data) {
+                        c.setFrozenColumnCount(value.intValue());
+                    }
+                });
+    }
+
+    protected void createHeaderActions() {
+        createCategory("Header", null);
+
+        createBooleanAction("Visible", "Header", true,
+                new Command<Grid, Boolean>() {
+
+                    @Override
+                    public void execute(Grid grid, Boolean value, Object data) {
+                        grid.setHeaderVisible(value);
+                    }
+                });
+
+        LinkedHashMap<String, String> defaultRows = new LinkedHashMap<String, String>();
+        defaultRows.put("Top", "Top");
+        defaultRows.put("Bottom", "Bottom");
+        defaultRows.put("Unset", "Unset");
+
+        createMultiClickAction("Default row", "Header", defaultRows,
+                new Command<Grid, String>() {
+
+                    @Override
+                    public void execute(Grid grid, String value, Object data) {
+                        HeaderRow defaultRow = null;
+                        if (value.equals("Top")) {
+                            defaultRow = grid.getHeaderRow(0);
+                        } else if (value.equals("Bottom")) {
+                            defaultRow = grid.getHeaderRow(grid
+                                    .getHeaderRowCount() - 1);
+                        }
+                        grid.setDefaultHeaderRow(defaultRow);
+                    }
+
+                }, defaultRows.get("Top"));
+
+        createClickAction("Prepend row", "Header", new Command<Grid, Object>() {
+
+            @Override
+            public void execute(Grid grid, Object value, Object data) {
+                grid.prependHeaderRow();
+            }
+
+        }, null);
+        createClickAction("Append row", "Header", new Command<Grid, Object>() {
+
+            @Override
+            public void execute(Grid grid, Object value, Object data) {
+                grid.appendHeaderRow();
+            }
+
+        }, null);
+
+        createClickAction("Remove top row", "Header",
+                new Command<Grid, Object>() {
+
+                    @Override
+                    public void execute(Grid grid, Object value, Object data) {
+                        grid.removeHeaderRow(0);
+                    }
+
+                }, null);
+        createClickAction("Remove bottom row", "Header",
+                new Command<Grid, Object>() {
+
+                    @Override
+                    public void execute(Grid grid, Object value, Object data) {
+                        grid.removeHeaderRow(grid.getHeaderRowCount() - 1);
+                    }
+
+                }, null);
+    }
+
+    protected void createFooterActions() {
+        createCategory("Footer", null);
+
+        createBooleanAction("Visible", "Footer", false,
+                new Command<Grid, Boolean>() {
+
+                    @Override
+                    public void execute(Grid grid, Boolean value, Object data) {
+                        grid.setFooterVisible(value);
+                    }
+                });
+
+        createClickAction("Prepend row", "Footer", new Command<Grid, Object>() {
+
+            @Override
+            public void execute(Grid grid, Object value, Object data) {
+                grid.prependFooterRow();
+            }
+
+        }, null);
+        createClickAction("Append row", "Footer", new Command<Grid, Object>() {
+
+            @Override
+            public void execute(Grid grid, Object value, Object data) {
+                grid.appendFooterRow();
+            }
+
+        }, null);
+
+        createClickAction("Remove top row", "Footer",
+                new Command<Grid, Object>() {
+
+                    @Override
+                    public void execute(Grid grid, Object value, Object data) {
+                        grid.removeFooterRow(0);
+                    }
+
+                }, null);
+        createClickAction("Remove bottom row", "Footer",
+                new Command<Grid, Object>() {
+
+                    @Override
+                    public void execute(Grid grid, Object value, Object data) {
+                        grid.removeFooterRow(grid.getFooterRowCount() - 1);
+                    }
+
+                }, null);
+    }
+
+    protected void createColumnActions() {
+        createCategory("Columns", null);
+
+        for (int c = 0; c < COLUMNS; c++) {
+            final int index = c;
+            createCategory(getColumnProperty(c), "Columns");
+
+            createClickAction("Add / Remove", getColumnProperty(c),
+                    new Command<Grid, String>() {
+
+                        @Override
+                        public void execute(Grid grid, String value, Object data) {
+                            String columnProperty = getColumnProperty((Integer) data);
+                            if (grid.getColumn(columnProperty) == null) {
+                                grid.addColumn(columnProperty);
+                            } else {
+                                grid.removeColumn(columnProperty);
+                            }
+                        }
+                    }, null, c);
+
+            createBooleanAction("Sortable", getColumnProperty(c), true,
+                    new Command<Grid, Boolean>() {
+
+                        @Override
+                        public void execute(Grid grid, Boolean value,
+                                Object columnIndex) {
+                            Object propertyId = getColumnProperty((Integer) columnIndex);
+                            Column column = grid.getColumn(propertyId);
+                            column.setSortable(value);
+                        }
+                    }, c);
+
+            createCategory("Column " + c + " Width", getColumnProperty(c));
+
+            createClickAction("Auto", "Column " + c + " Width",
+                    new Command<Grid, Integer>() {
+
+                        @Override
+                        public void execute(Grid grid, Integer value,
+                                Object columnIndex) {
+                            Object propertyId = getColumnProperty((Integer) columnIndex);
+                            Column column = grid.getColumn(propertyId);
+                            column.setWidthUndefined();
+                        }
+                    }, -1, c);
+
+            createClickAction("25.5px", "Column " + c + " Width",
+                    new Command<Grid, Void>() {
+                        @Override
+                        @SuppressWarnings("boxing")
+                        public void execute(Grid grid, Void value,
+                                Object columnIndex) {
+                            grid.getColumns().get((Integer) columnIndex)
+                                    .setWidth(25.5);
+                        }
+                    }, null, c);
+
+            for (int w = 50; w < 300; w += 50) {
+                createClickAction(w + "px", "Column " + c + " Width",
+                        new Command<Grid, Integer>() {
+
+                            @Override
+                            public void execute(Grid grid, Integer value,
+                                    Object columnIndex) {
+                                Object propertyId = getColumnProperty((Integer) columnIndex);
+                                Column column = grid.getColumn(propertyId);
+                                column.setWidth(value);
+                            }
+                        }, w, c);
+            }
+
+            LinkedHashMap<String, GridStaticCellType> defaultRows = new LinkedHashMap<String, GridStaticCellType>();
+            defaultRows.put("Text Header", GridStaticCellType.TEXT);
+            defaultRows.put("Html Header ", GridStaticCellType.HTML);
+            defaultRows.put("Widget Header", GridStaticCellType.WIDGET);
+
+            createMultiClickAction("Header Type", getColumnProperty(c),
+                    defaultRows, new Command<Grid, GridStaticCellType>() {
+
+                        @Override
+                        public void execute(Grid grid,
+                                GridStaticCellType value, Object columnIndex) {
+                            final Object propertyId = getColumnProperty((Integer) columnIndex);
+                            final HeaderCell cell = grid.getDefaultHeaderRow()
+                                    .getCell(propertyId);
+                            switch (value) {
+                            case TEXT:
+                                cell.setText("Text Header");
+                                break;
+                            case HTML:
+                                cell.setHtml("HTML Header");
+                                break;
+                            case WIDGET:
+                                cell.setComponent(new Button("Button Header",
+                                        new ClickListener() {
+
+                                            @Override
+                                            public void buttonClick(
+                                                    ClickEvent event) {
+                                                log("Button clicked!");
+                                            }
+                                        }));
+                            default:
+                                break;
+                            }
+                        }
+
+                    }, c);
+
+            defaultRows = new LinkedHashMap<String, GridStaticCellType>();
+            defaultRows.put("Text Footer", GridStaticCellType.TEXT);
+            defaultRows.put("Html Footer", GridStaticCellType.HTML);
+            defaultRows.put("Widget Footer", GridStaticCellType.WIDGET);
+
+            createMultiClickAction("Footer Type", getColumnProperty(c),
+                    defaultRows, new Command<Grid, GridStaticCellType>() {
+
+                        @Override
+                        public void execute(Grid grid,
+                                GridStaticCellType value, Object columnIndex) {
+                            final Object propertyId = getColumnProperty((Integer) columnIndex);
+                            final FooterCell cell = grid.getFooterRow(0)
+                                    .getCell(propertyId);
+                            switch (value) {
+                            case TEXT:
+                                cell.setText("Text Footer");
+                                break;
+                            case HTML:
+                                cell.setHtml("HTML Footer");
+                                break;
+                            case WIDGET:
+                                cell.setComponent(new Button("Button Footer",
+                                        new ClickListener() {
+
+                                            @Override
+                                            public void buttonClick(
+                                                    ClickEvent event) {
+                                                log("Button clicked!");
+                                            }
+                                        }));
+                            default:
+                                break;
+                            }
+                        }
+
+                    }, c);
+        }
+    }
+
+    private static String getColumnProperty(int c) {
+        return "Column " + c;
+    }
+
+    protected void createPropertyActions() {
+        createCategory("Properties", null);
+
+        createBooleanAction("Prepend property", "Properties", false,
+                new Command<Grid, Boolean>() {
+                    private final Object propertyId = new Object();
+
+                    @Override
+                    public void execute(Grid c, Boolean enable, Object data) {
+                        if (enable.booleanValue()) {
+                            ds.addContainerProperty(propertyId, String.class,
+                                    "property value");
+                            grid.getColumn(propertyId).setHeaderCaption(
+                                    "new property");
+                            grid.setColumnOrder(propertyId);
+                        } else {
+                            ds.removeContainerProperty(propertyId);
+                        }
+                    }
+                }, null);
+    }
+
+    protected void createRowActions() {
+        createCategory("Body rows", null);
+
+        class NewRowCommand implements Command<Grid, String> {
+            private final int index;
+
+            public NewRowCommand() {
+                this(0);
+            }
+
+            public NewRowCommand(int index) {
+                this.index = index;
+            }
+
+            @Override
+            public void execute(Grid c, String value, Object data) {
+                Item item = ds.addItemAt(index, new Object());
+                for (int i = 0; i < COLUMNS; i++) {
+                    Class<?> type = ds.getType(getColumnProperty(i));
+                    if (String.class.isAssignableFrom(type)) {
+                        Property<String> itemProperty = getProperty(item, i);
+                        itemProperty.setValue("newcell: " + i);
+                    } else if (Integer.class.isAssignableFrom(type)) {
+                        Property<Integer> itemProperty = getProperty(item, i);
+                        itemProperty.setValue(Integer.valueOf(i));
+                    } else {
+                        // let the default value be taken implicitly.
+                    }
+                }
+            }
+
+            private <T extends Object> Property<T> getProperty(Item item, int i) {
+                @SuppressWarnings("unchecked")
+                Property<T> itemProperty = item
+                        .getItemProperty(getColumnProperty(i));
+                return itemProperty;
+            }
+        }
+        final NewRowCommand newRowCommand = new NewRowCommand();
+
+        createClickAction("Add 18 rows", "Body rows",
+                new Command<Grid, String>() {
+                    @Override
+                    public void execute(Grid c, String value, Object data) {
+                        for (int i = 0; i < 18; i++) {
+                            newRowCommand.execute(c, value, data);
+                        }
+                    }
+                }, null);
+
+        createClickAction("Add first row", "Body rows", newRowCommand, null);
+
+        createClickAction("Add second row", "Body rows", new NewRowCommand(1),
+                null);
+
+        createClickAction("Remove first row", "Body rows",
+                new Command<Grid, String>() {
+                    @Override
+                    public void execute(Grid c, String value, Object data) {
+                        Object firstItemId = ds.getIdByIndex(0);
+                        ds.removeItem(firstItemId);
+                    }
+                }, null);
+
+        createClickAction("Remove 18 first rows", "Body rows",
+                new Command<Grid, String>() {
+                    @Override
+                    public void execute(Grid c, String value, Object data) {
+                        for (int i = 0; i < 18; i++) {
+                            Object firstItemId = ds.getIdByIndex(0);
+                            ds.removeItem(firstItemId);
+                        }
+                    }
+                }, null);
+
+        createClickAction("Modify first row (getItemProperty)", "Body rows",
+                new Command<Grid, String>() {
+                    @SuppressWarnings("unchecked")
+                    @Override
+                    public void execute(Grid c, String value, Object data) {
+                        Object firstItemId = ds.getIdByIndex(0);
+                        Item item = ds.getItem(firstItemId);
+                        for (int i = 0; i < COLUMNS; i++) {
+                            Property<?> property = item
+                                    .getItemProperty(getColumnProperty(i));
+                            if (property.getType().equals(String.class)) {
+                                ((Property<String>) property)
+                                        .setValue("modified: " + i);
+                            }
+                        }
+                    }
+                }, null);
+
+        createClickAction("Modify first row (getContainerProperty)",
+                "Body rows", new Command<Grid, String>() {
+                    @SuppressWarnings("unchecked")
+                    @Override
+                    public void execute(Grid c, String value, Object data) {
+                        Object firstItemId = ds.getIdByIndex(0);
+                        for (Object containerPropertyId : ds
+                                .getContainerPropertyIds()) {
+                            Property<?> property = ds.getContainerProperty(
+                                    firstItemId, containerPropertyId);
+                            if (property.getType().equals(String.class)) {
+                                ((Property<String>) property)
+                                        .setValue("modified: "
+                                                + containerPropertyId);
+                            }
+                        }
+                    }
+                }, null);
+
+        createBooleanAction("Select first row", "Body rows", false,
+                new Command<Grid, Boolean>() {
+                    @Override
+                    public void execute(Grid grid, Boolean select, Object data) {
+                        final Object firstItemId = grid
+                                .getContainerDataSource().firstItemId();
+                        if (select.booleanValue()) {
+                            grid.select(firstItemId);
+                        } else {
+                            grid.deselect(firstItemId);
+                        }
+                    }
+                });
+
+        createClickAction("Remove all rows", "Body rows",
+                new Command<Grid, String>() {
+                    @SuppressWarnings("unchecked")
+                    @Override
+                    public void execute(Grid c, String value, Object data) {
+                        ds.removeAllItems();
+                    }
+                }, null);
+    }
+
+    protected void createEditorRowActions() {
+        createBooleanAction("Enabled", "Editor row", false,
+                new Command<Grid, Boolean>() {
+                    @Override
+                    public void execute(Grid c, Boolean value, Object data) {
+                        c.setEditorRowEnabled(value);
+                    }
+                });
+
+        createClickAction("Edit item 5", "Editor row",
+                new Command<Grid, String>() {
+                    @Override
+                    public void execute(Grid c, String value, Object data) {
+                        c.editItem(5);
+                    }
+                }, null);
+
+        createClickAction("Edit item 100", "Editor row",
+                new Command<Grid, String>() {
+                    @Override
+                    public void execute(Grid c, String value, Object data) {
+                        c.editItem(100);
+                    }
+                }, null);
+        createClickAction("Save", "Editor row", new Command<Grid, String>() {
+            @Override
+            public void execute(Grid c, String value, Object data) {
+                try {
+                    c.saveEditorRow();
+                } catch (CommitException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+            }
+        }, null);
+        createClickAction("Cancel edit", "Editor row",
+                new Command<Grid, String>() {
+                    @Override
+                    public void execute(Grid c, String value, Object data) {
+                        c.cancelEditorRow();
+                    }
+                }, null);
+    }
+
+    @SuppressWarnings("boxing")
+    protected void addHeightActions() {
+        createCategory("Height by Rows", "Size");
+
+        createBooleanAction("HeightMode Row", "Size", false,
+                new Command<Grid, Boolean>() {
+                    @Override
+                    public void execute(Grid c, Boolean heightModeByRows,
+                            Object data) {
+                        c.setHeightMode(heightModeByRows ? HeightMode.ROW
+                                : HeightMode.CSS);
+                    }
+                }, null);
+
+        addActionForHeightByRows(1d / 3d);
+        addActionForHeightByRows(2d / 3d);
+
+        for (double i = 1; i < 5; i++) {
+            addActionForHeightByRows(i);
+            addActionForHeightByRows(i + 1d / 3d);
+            addActionForHeightByRows(i + 2d / 3d);
+        }
+
+        Command<Grid, String> sizeCommand = new Command<Grid, String>() {
+            @Override
+            public void execute(Grid grid, String height, Object data) {
+                grid.setHeight(height);
+            }
+        };
+
+        createCategory("Height", "Size");
+        // header 20px + scrollbar 16px = 36px baseline
+        createClickAction("86px (no drag scroll select)", "Height",
+                sizeCommand, "86px");
+        createClickAction("96px (drag scroll select limit)", "Height",
+                sizeCommand, "96px");
+        createClickAction("106px (drag scroll select enabled)", "Height",
+                sizeCommand, "106px");
+    }
+
+    private void addActionForHeightByRows(final Double i) {
+        DecimalFormat df = new DecimalFormat("0.00");
+        createClickAction(df.format(i) + " rows", "Height by Rows",
+                new Command<Grid, String>() {
+                    @Override
+                    public void execute(Grid c, String value, Object data) {
+                        c.setHeightByRows(i);
+                    }
+                }, null);
+    }
+
+    @Override
+    protected Integer getTicketNumber() {
+        return 12829;
+    }
+
+    @Override
+    protected Class<Grid> getTestClass() {
+        return Grid.class;
+    }
+
+}
index f1d64a50e778b52bcb68f674d3ded50e83f0e0f2..88ad1fcd5ae6b432eb1cea2550513148e3fd46dc 100644 (file)
@@ -65,18 +65,18 @@ public class EscalatorProxy extends Escalator {
         }
 
         @Override
-        public void setColumnWidth(int index, int px)
+        public void setColumnWidth(int index, double px)
                 throws IllegalArgumentException {
             columnConfiguration.setColumnWidth(index, px);
         }
 
         @Override
-        public int getColumnWidth(int index) throws IllegalArgumentException {
+        public double getColumnWidth(int index) throws IllegalArgumentException {
             return columnConfiguration.getColumnWidth(index);
         }
 
         @Override
-        public int getColumnWidthActual(int index)
+        public double getColumnWidthActual(int index)
                 throws IllegalArgumentException {
             return columnConfiguration.getColumnWidthActual(index);
         }