]> source.dussan.org Git - vaadin-framework.git/commitdiff
Support widgets in Grid body row cells #12993
authorJohn Ahlroos <john@vaadin.com>
Tue, 26 Nov 2013 14:30:52 +0000 (16:30 +0200)
committerJohn Ahlroos <john@vaadin.com>
Wed, 4 Dec 2013 07:43:57 +0000 (09:43 +0200)
Change-Id: I8000efd86b5d860d241daea57f70a6626ca8d3dc

client/src/com/vaadin/client/ui/grid/Cell.java
client/src/com/vaadin/client/ui/grid/ColumnGroup.java
client/src/com/vaadin/client/ui/grid/ColumnGroupRow.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/GridColumn.java
client/src/com/vaadin/client/ui/grid/GridConnector.java
client/src/com/vaadin/client/ui/grid/Renderer.java [new file with mode: 0644]

index 09bc5da344dc284c937d1a68d5f66a33a51df337..31156ffe7ba8ad70d63bf45d55b3339934661e39 100644 (file)
@@ -17,6 +17,7 @@
 package com.vaadin.client.ui.grid;
 
 import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.HasOneWidget;
 
 /**
  * A representation of a single cell.
@@ -27,7 +28,8 @@ import com.google.gwt.user.client.Element;
  * @since 7.2
  * @author Vaadin Ltd
  */
-public interface Cell {
+public interface Cell extends HasOneWidget {
+
     /**
      * Gets the index of the row this cell is in.
      * 
index c37068def73c11d51de90eef1603b1cddf33abfa..0b9cbee13c7015af62b052d27a4d85da53fde88d 100644 (file)
@@ -29,7 +29,7 @@ import java.util.List;
  * @since 7.2
  * @author Vaadin Ltd
  */
-public class ColumnGroup {
+public class ColumnGroup<T> {
 
     /**
      * The text shown in the header
@@ -45,7 +45,7 @@ public class ColumnGroup {
      * The columns included in the group when also accounting for subgroup
      * columns
      */
-    private final List<GridColumn> columns;
+    private final List<GridColumn<?, T>> columns;
 
     /**
      * The grid associated with the column group
@@ -55,14 +55,14 @@ public class ColumnGroup {
     /**
      * Constructs a new column group
      */
-    ColumnGroup(Grid grid, Collection<GridColumn> columns) {
+    ColumnGroup(Grid grid, Collection<GridColumn<?, T>> columns) {
         if (columns == null) {
             throw new IllegalArgumentException(
                     "columns cannot be null. Pass an empty list instead.");
         }
         this.grid = grid;
-        this.columns = Collections.unmodifiableList(new ArrayList<GridColumn>(
-                columns));
+        this.columns = Collections
+                .unmodifiableList(new ArrayList<GridColumn<?, T>>(columns));
     }
 
     /**
@@ -111,7 +111,7 @@ public class ColumnGroup {
      * 
      * @return unmodifiable list of columns
      */
-    public List<GridColumn> getColumns() {
+    public List<GridColumn<?, T>> getColumns() {
         return columns;
     }
 }
index 6bbc9bc9ebc4c7f6f33a1243131cb22070ee7764..113e0b34c6004e1abe4ebd78ca2e94fd9cb768f2 100644 (file)
@@ -27,20 +27,22 @@ import java.util.Set;
  * A column group row represents an auxiliary header or footer row added to the
  * grid. A column group row includes column groups that group columns together.
  * 
+ * @param <T>
+ *            Row type
  * @since 7.2
  * @author Vaadin Ltd
  */
-public class ColumnGroupRow {
+public class ColumnGroupRow<T> {
 
     /**
      * The column groups in this row
      */
-    private List<ColumnGroup> groups = new ArrayList<ColumnGroup>();
+    private List<ColumnGroup<T>> groups = new ArrayList<ColumnGroup<T>>();
 
     /**
      * The grid associated with the column row
      */
-    private final Grid grid;
+    private final Grid<T> grid;
 
     /**
      * Is the header shown
@@ -59,7 +61,7 @@ public class ColumnGroupRow {
      *            Grid associated with this column
      * 
      */
-    ColumnGroupRow(Grid grid) {
+    ColumnGroupRow(Grid<T> grid) {
         this.grid = grid;
     }
 
@@ -71,9 +73,9 @@ public class ColumnGroupRow {
      * @return a column group representing the collection of columns added to
      *         the group.
      */
-    public ColumnGroup addGroup(GridColumn... columns) {
+    public ColumnGroup<T> addGroup(GridColumn<?, T>... columns) {
 
-        for (GridColumn column : columns) {
+        for (GridColumn<?, T> column : columns) {
             if (isColumnGrouped(column)) {
                 throw new IllegalArgumentException("Column "
                         + String.valueOf(column.getHeaderCaption())
@@ -81,7 +83,7 @@ public class ColumnGroupRow {
             }
         }
 
-        ColumnGroup group = new ColumnGroup(grid, Arrays.asList(columns));
+        ColumnGroup<T> group = new ColumnGroup<T>(grid, Arrays.asList(columns));
         groups.add(group);
         grid.refreshHeader();
         grid.refreshFooter();
@@ -97,15 +99,15 @@ public class ColumnGroupRow {
      *         the group.
      * 
      */
-    public ColumnGroup addGroup(ColumnGroup... groups) {
+    public ColumnGroup<T> addGroup(ColumnGroup<T>... groups) {
         assert groups != null : "groups cannot be null";
 
-        Set<GridColumn> columns = new HashSet<GridColumn>();
-        for (ColumnGroup group : groups) {
+        Set<GridColumn<?, T>> columns = new HashSet<GridColumn<?, T>>();
+        for (ColumnGroup<T> group : groups) {
             columns.addAll(group.getColumns());
         }
 
-        ColumnGroup group = new ColumnGroup(grid, columns);
+        ColumnGroup<T> group = new ColumnGroup<T>(grid, columns);
         this.groups.add(group);
         grid.refreshHeader();
         grid.refreshFooter();
@@ -118,7 +120,7 @@ public class ColumnGroupRow {
      * @param group
      *            The group to remove
      */
-    public void removeGroup(ColumnGroup group) {
+    public void removeGroup(ColumnGroup<T> group) {
         groups.remove(group);
         grid.refreshHeader();
         grid.refreshFooter();
@@ -129,7 +131,7 @@ public class ColumnGroupRow {
      * 
      * @return unmodifiable list of groups in this row
      */
-    public List<ColumnGroup> getGroups() {
+    public List<ColumnGroup<T>> getGroups() {
         return Collections.unmodifiableList(groups);
     }
 
@@ -177,8 +179,8 @@ public class ColumnGroupRow {
      * Iterates all the column groups and checks if the columns alread has been
      * added to a group.
      */
-    private boolean isColumnGrouped(GridColumn column) {
-        for (ColumnGroup group : groups) {
+    private boolean isColumnGrouped(GridColumn<?, T> column) {
+        for (ColumnGroup<T> group : groups) {
             if (group.getColumns().contains(column)) {
                 return true;
             }
index 2f5f28871b2ae6be556d41aae38164e0ba14743b..e3aae2eb13240867b8195dc49efec31c40e683cb 100644 (file)
@@ -246,10 +246,6 @@ public class Escalator extends Widget {
      * escalator DOM). NOTE: these bits can most often also be identified by
      * searching for code that call scrollElem.getScrollTop();.
      */
-    /*
-     * [[widgets]]: This needs to be re-inspected once GWT/Vaadin widgets are
-     * being supported.
-     */
 
     /**
      * A utility class that contains utility methods that are usually called
@@ -1236,8 +1232,9 @@ public class Escalator extends Widget {
                 final Node tr = childNodes.getItem(visualRowIndex);
 
                 for (int column = 0; column < numberOfColumns; column++) {
-                    // TODO [[widgets]]
-                    tr.getChild(offset).removeFromParent();
+                    Element cellElement = tr.getChild(offset).cast();
+                    detachPossibleWidgetFromCell(cellElement);
+                    cellElement.removeFromParent();
                 }
                 recalculateRowWidth((Element) tr);
             }
@@ -1269,6 +1266,18 @@ public class Escalator extends Widget {
             }
         }
 
+        void detachPossibleWidgetFromCell(Node cellNode) {
+            // Detach possible widget
+            Widget widget = getWidgetFromCell(cellNode);
+            if (widget != null) {
+                // Orphan.
+                setParent(widget, null);
+
+                // Physical detach.
+                cellNode.removeChild(widget.getElement());
+            }
+        }
+
         protected void paintInsertColumns(final int offset,
                 final int numberOfColumns, boolean frozen) {
             final NodeList<Node> childNodes = root.getChildNodes();
@@ -1370,7 +1379,10 @@ public class Escalator extends Widget {
         protected void paintRemoveRows(final int index, final int numberOfRows) {
             for (int i = index; i < index + numberOfRows; i++) {
                 final Element tr = (Element) root.getChild(index);
-                // TODO [[widgets]]
+                for (int c = 0; c < tr.getChildCount(); c++) {
+                    detachPossibleWidgetFromCell((Element) tr.getChild(c)
+                            .cast());
+                }
                 tr.removeFromParent();
             }
             recalculateSectionHeight();
@@ -1935,7 +1947,10 @@ public class Escalator extends Widget {
                     for (int i = 0; i < escalatorRowsToRemove; i++) {
                         final Element tr = visualRowOrder
                                 .remove(removedVisualInside.getStart());
-                        // TODO [[widgets]]
+                        for (int c = 0; c < tr.getChildCount(); c++) {
+                            detachPossibleWidgetFromCell((Element) tr.getChild(
+                                    c).cast());
+                        }
                         tr.removeFromParent();
                         rowTopPosMap.remove(tr);
                     }
@@ -2429,8 +2444,11 @@ public class Escalator extends Widget {
                 final ListIterator<Element> iter = visualRowOrder
                         .listIterator(visualRowOrder.size());
                 for (int i = 0; i < -neededEscalatorRowsDiff; i++) {
-                    // TODO [[widgets]]
                     final Element last = iter.previous();
+                    for (int c = 0; c < last.getChildCount(); c++) {
+                        detachPossibleWidgetFromCell((Element) last.getChild(c)
+                                .cast());
+                    }
                     last.removeFromParent();
                     iter.remove();
                 }
@@ -3177,4 +3195,33 @@ public class Escalator extends Widget {
         fireEvent(new RowVisibilityChangeEvent(visibleRangeStart,
                 visibleRowCount));
     }
+
+    /**
+     * Accesses the package private method Widget#setParent()
+     * 
+     * @param widget
+     *            The widget to access
+     * @param parent
+     *            The parent to set
+     */
+    static native final void setParent(Widget widget, Widget parent)
+    /*-{
+        widget.@com.google.gwt.user.client.ui.Widget::setParent(Lcom/google/gwt/user/client/ui/Widget;)(parent);
+    }-*/;
+
+    /**
+     * Returns the widget from a cell node or <code>null</code> if there is no
+     * widget in the cell
+     * 
+     * @param cellNode
+     *            The cell node
+     */
+    static Widget getWidgetFromCell(Node cellNode) {
+        Node possibleWidgetNode = cellNode.getFirstChild();
+        if (possibleWidgetNode != null
+                && possibleWidgetNode.getNodeType() == Node.ELEMENT_NODE) {
+            return Util.findWidget((Element) possibleWidgetNode, null);
+        }
+        return null;
+    }
 }
index 08c27fa859fcc0ec7f996317a6356909d4d0698b..3613e73affe7dc4016ea9f6fffd98454019e46f9 100644 (file)
@@ -19,7 +19,10 @@ import java.util.List;
 
 import com.google.gwt.dom.client.Style.Display;
 import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.IsWidget;
+import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.client.ui.grid.FlyweightRow.CellIterator;
 
 /**
@@ -39,11 +42,16 @@ class FlyweightCell implements Cell {
 
     private final int column;
     private final FlyweightRow row;
+
     private CellIterator currentIterator = null;
 
-    public FlyweightCell(final FlyweightRow row, final int column) {
+    private final Escalator escalator;
+
+    public FlyweightCell(final FlyweightRow row, final int column,
+            Escalator escalator) {
         this.row = row;
         this.column = column;
+        this.escalator = escalator;
     }
 
     @Override
@@ -146,4 +154,50 @@ class FlyweightCell implements Cell {
             }
         }
     }
+
+    @Override
+    public Widget getWidget() {
+        return Escalator.getWidgetFromCell(getElement());
+    }
+
+    @Override
+    public void setWidget(Widget widget) {
+
+        Widget oldWidget = getWidget();
+
+        // Validate
+        if (oldWidget == widget) {
+            return;
+        }
+
+        // Detach old child.
+        if (oldWidget != null) {
+            // Orphan.
+            Escalator.setParent(oldWidget, null);
+
+            // Physical detach.
+            getElement().removeChild(oldWidget.getElement());
+        }
+
+        // Remove any previous text nodes from previous
+        // setInnerText/setInnerHTML
+        getElement().removeAllChildren();
+
+        // Attach new child.
+        if (widget != null) {
+            // Detach new child from old parent.
+            widget.removeFromParent();
+
+            // Physical attach.
+            DOM.appendChild(getElement(), widget.getElement());
+
+            Escalator.setParent(widget, escalator);
+        }
+    }
+
+    @Override
+    public void setWidget(IsWidget w) {
+        setWidget(Widget.asWidgetOrNull(w));
+    }
+
 }
index fc1c9770524df80adc799981479be63f61614d0e..c386b7dd1fbbd22a13ac668c5bed76ecba49c0eb 100644 (file)
@@ -157,7 +157,7 @@ class FlyweightRow implements Row {
     void addCells(final int index, final int numberOfColumns) {
         for (int i = 0; i < numberOfColumns; i++) {
             final int col = index + i;
-            cells.add(col, new FlyweightCell(this, col));
+            cells.add(col, new FlyweightCell(this, col, escalator));
         }
         updateRestOfCells(index + numberOfColumns);
     }
@@ -172,7 +172,7 @@ class FlyweightRow implements Row {
     private void updateRestOfCells(final int startPos) {
         // update the column number for the cells to the right
         for (int col = startPos; col < cells.size(); col++) {
-            cells.set(col, new FlyweightCell(this, col));
+            cells.set(col, new FlyweightCell(this, col, escalator));
         }
     }
 
index 66f37c762095d9d3b829fcc18732b8ce182faaac..25e6596a355785c7f97a4a18046bff1e9e1f8db9 100644 (file)
@@ -21,6 +21,7 @@ import java.util.List;
 
 import com.google.gwt.core.shared.GWT;
 import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.client.data.DataChangeHandler;
 import com.vaadin.client.data.DataSource;
 import com.vaadin.shared.util.SharedUtil;
@@ -64,14 +65,14 @@ public class Grid<T> extends Composite {
     /**
      * List of columns in the grid. Order defines the visible order.
      */
-    private final List<GridColumn<T>> columns = new ArrayList<GridColumn<T>>();
+    private final List<GridColumn<?, T>> columns = new ArrayList<GridColumn<?, T>>();
 
     private DataSource<T> dataSource;
 
     /**
      * The column groups rows added to the grid
      */
-    private final List<ColumnGroupRow> columnGroupRows = new ArrayList<ColumnGroupRow>();
+    private final List<ColumnGroupRow<T>> columnGroupRows = new ArrayList<ColumnGroupRow<T>>();
 
     /**
      * Are the headers for the columns visible
@@ -83,16 +84,19 @@ public class Grid<T> extends Composite {
      */
     private boolean columnFootersVisible = false;
 
-    private GridColumn<T> lastFrozenColumn;
+    private GridColumn<?, T> lastFrozenColumn;
 
     /**
      * Base class for grid columns internally used by the Grid. The user should
      * use {@link GridColumn} when creating new columns.
      * 
+     * @param <C>
+     *            the column type
+     * 
      * @param <T>
      *            the row type
      */
-    public static abstract class AbstractGridColumn<T> {
+    public static abstract class AbstractGridColumn<C, T> {
 
         /**
          * The grid the column is associated with
@@ -114,6 +118,44 @@ public class Grid<T> extends Composite {
          */
         private String footer;
 
+        /**
+         * Renderer for rendering a value into the cell
+         */
+        private Renderer<C> renderer = new Renderer<C>() {
+
+            @Override
+            public void renderCell(Cell cell, C value) {
+                if (value instanceof Widget) {
+                    cell.setWidget((Widget) value);
+                } else if (value instanceof String) {
+                    cell.getElement().setInnerText(value.toString());
+                } else {
+                    throw new IllegalArgumentException(
+                            "Cell value cannot be converted into a String. Please use a custom renderer to convert the value.");
+                }
+            }
+        };
+
+        /**
+         * Constructs a new column.
+         */
+        public AbstractGridColumn() {
+
+        }
+
+        /**
+         * Constructs a new column with a custom renderer.
+         * 
+         * @param renderer
+         *            The renderer to use for rendering the cells
+         */
+        public AbstractGridColumn(Renderer<C> renderer) {
+            if (renderer == null) {
+                throw new IllegalArgumentException("Renderer cannot be null.");
+            }
+            this.renderer = renderer;
+        }
+
         /**
          * Internally used by the grid to set itself
          * 
@@ -218,22 +260,36 @@ public class Grid<T> extends Composite {
                 } else {
                     conf.removeColumns(index, 1);
                 }
-
-                // TODO should update body as well
             }
 
             this.visible = visible;
         }
 
         /**
-         * Returns the text that should be displayed in the cell.
+         * Returns the data that should be rendered into the cell. By default
+         * returning Strings and Widgets are supported. If the return type is a
+         * String then it will be treated as preformatted text.
+         * <p>
+         * To support other types you will need to pass a custom renderer to the
+         * column via the column constructor.
          * 
          * @param row
          *            The row object that provides the cell content.
          * 
          * @return The cell content
          */
-        public abstract String getValue(T row);
+        public abstract C getValue(T row);
+
+        /**
+         * The renderer to render the cell width. By default renders the data as
+         * a String or adds the widget into the cell if the column type is of
+         * widget type.
+         * 
+         * @return The renderer to render the cell content with
+         */
+        public Renderer<C> getRenderer() {
+            return renderer;
+        }
 
         /**
          * Finds the index of this column instance
@@ -276,9 +332,12 @@ public class Grid<T> extends Composite {
         /**
          * Gets the header/footer caption value
          * 
+         * @param column
+         *            The column to get the value for.
+         * 
          * @return The value that should be rendered for the column caption
          */
-        public abstract String getColumnValue(GridColumn column);
+        public abstract String getColumnValue(GridColumn<?, T> column);
 
         /**
          * Gets the group caption value
@@ -287,14 +346,17 @@ public class Grid<T> extends Composite {
          *            The group for with the caption value should be returned
          * @return The value that should be rendered for the column caption
          */
-        public abstract String getGroupValue(ColumnGroup group);
+        public abstract String getGroupValue(ColumnGroup<T> group);
 
         /**
          * Is the row visible in the header/footer
          * 
+         * @param row
+         *            the row to check
+         * 
          * @return <code>true</code> if the row should be visible
          */
-        public abstract boolean isRowVisible(ColumnGroupRow row);
+        public abstract boolean isRowVisible(ColumnGroupRow<T> row);
 
         /**
          * Should the first row be visible
@@ -317,7 +379,7 @@ public class Grid<T> extends Composite {
                 // column headers
                 for (Cell cell : cellsToUpdate) {
                     int columnIndex = cell.getColumn();
-                    GridColumn column = columns.get(columnIndex);
+                    GridColumn<?, T> column = columns.get(columnIndex);
                     cell.getElement().setInnerText(getColumnValue(column));
                 }
 
@@ -328,7 +390,7 @@ public class Grid<T> extends Composite {
                 }
 
                 // Adjust for previous invisible header rows
-                ColumnGroupRow groupRow = null;
+                ColumnGroupRow<T> groupRow = null;
                 for (int i = 0, realIndex = 0; i < columnGroupRows.size(); i++) {
                     groupRow = columnGroupRows.get(i);
                     if (isRowVisible(groupRow)) {
@@ -344,8 +406,8 @@ public class Grid<T> extends Composite {
 
                 for (Cell cell : cellsToUpdate) {
                     int columnIndex = cell.getColumn();
-                    GridColumn column = columns.get(columnIndex);
-                    ColumnGroup group = getGroupForColumn(groupRow, column);
+                    GridColumn<?, T> column = columns.get(columnIndex);
+                    ColumnGroup<T> group = getGroupForColumn(groupRow, column);
 
                     if (group != null) {
                         // FIXME Should merge the group cells when escalator
@@ -398,17 +460,17 @@ public class Grid<T> extends Composite {
         return new HeaderFooterEscalatorUpdater(escalator.getHeader(), true) {
 
             @Override
-            public boolean isRowVisible(ColumnGroupRow row) {
+            public boolean isRowVisible(ColumnGroupRow<T> row) {
                 return row.isHeaderVisible();
             }
 
             @Override
-            public String getGroupValue(ColumnGroup group) {
+            public String getGroupValue(ColumnGroup<T> group) {
                 return group.getHeaderCaption();
             }
 
             @Override
-            public String getColumnValue(GridColumn column) {
+            public String getColumnValue(GridColumn<?, T> column) {
                 return column.getHeaderCaption();
             }
 
@@ -437,9 +499,9 @@ public class Grid<T> extends Composite {
                 }
 
                 for (Cell cell : cellsToUpdate) {
-                    String value = getColumn(cell.getColumn())
-                            .getValue(rowData);
-                    cell.getElement().setInnerText(value);
+                    GridColumn column = getColumn(cell.getColumn());
+                    Object value = column.getValue(rowData);
+                    column.getRenderer().renderCell(cell, value);
                 }
             }
 
@@ -461,17 +523,17 @@ public class Grid<T> extends Composite {
         return new HeaderFooterEscalatorUpdater(escalator.getFooter(), false) {
 
             @Override
-            public boolean isRowVisible(ColumnGroupRow row) {
+            public boolean isRowVisible(ColumnGroupRow<T> row) {
                 return row.isFooterVisible();
             }
 
             @Override
-            public String getGroupValue(ColumnGroup group) {
+            public String getGroupValue(ColumnGroup<T> group) {
                 return group.getFooterCaption();
             }
 
             @Override
-            public String getColumnValue(GridColumn column) {
+            public String getColumnValue(GridColumn<?, T> column) {
                 return column.getFooterCaption();
             }
 
@@ -498,7 +560,7 @@ public class Grid<T> extends Composite {
 
         // Count needed rows
         int totalRows = firstRowIsVisible ? 1 : 0;
-        for (ColumnGroupRow row : columnGroupRows) {
+        for (ColumnGroupRow<T> row : columnGroupRows) {
             if (isHeader ? row.isHeaderVisible() : row.isFooterVisible()) {
                 totalRows++;
             }
@@ -540,7 +602,7 @@ public class Grid<T> extends Composite {
      * @param column
      *            the column to add
      */
-    public void addColumn(GridColumn<T> column) {
+    public void addColumn(GridColumn<?, T> column) {
         ColumnConfiguration conf = escalator.getColumnConfiguration();
         addColumn(column, conf.getColumnCount());
     }
@@ -553,10 +615,10 @@ public class Grid<T> extends Composite {
      * @param column
      *            the column to add
      */
-    public void addColumn(GridColumn<T> column, int index) {
+    public void addColumn(GridColumn<?, T> column, int index) {
 
         // Register this grid instance with the column
-        ((AbstractGridColumn<T>) column).setGrid(this);
+        ((AbstractGridColumn<?, T>) column).setGrid(this);
 
         columns.add(index, column);
 
@@ -564,7 +626,7 @@ public class Grid<T> extends Composite {
         conf.insertColumns(index, 1);
 
         if (lastFrozenColumn != null
-                && ((AbstractGridColumn<T>) lastFrozenColumn)
+                && ((AbstractGridColumn<?, T>) lastFrozenColumn)
                         .findIndexOfColumn() < index) {
             refreshFrozenColumns();
         }
@@ -576,13 +638,13 @@ public class Grid<T> extends Composite {
      * @param column
      *            the column to remove
      */
-    public void removeColumn(GridColumn<T> column) {
+    public void removeColumn(GridColumn<?, T> column) {
 
         int columnIndex = columns.indexOf(column);
         columns.remove(columnIndex);
 
         // de-register column with grid
-        ((AbstractGridColumn<T>) column).setGrid(null);
+        ((AbstractGridColumn<?, T>) column).setGrid(null);
 
         ColumnConfiguration conf = escalator.getColumnConfiguration();
         conf.removeColumns(columnIndex, 1);
@@ -608,8 +670,8 @@ public class Grid<T> extends Composite {
      * 
      * @return A unmodifiable list of the columns in the grid
      */
-    public List<GridColumn<T>> getColumns() {
-        return Collections.unmodifiableList(new ArrayList<GridColumn<T>>(
+    public List<GridColumn<?, T>> getColumns() {
+        return Collections.unmodifiableList(new ArrayList<GridColumn<?, T>>(
                 columns));
     }
 
@@ -622,7 +684,8 @@ public class Grid<T> extends Composite {
      * @throws IllegalArgumentException
      *             if the column index does not exist in the grid
      */
-    public GridColumn<T> getColumn(int index) throws IllegalArgumentException {
+    public GridColumn<?, T> getColumn(int index)
+            throws IllegalArgumentException {
         if (index < 0 || index >= columns.size()) {
             throw new IllegalStateException("Column not found.");
         }
@@ -749,8 +812,8 @@ public class Grid<T> extends Composite {
      * 
      * @return a column group row instance you can use to add column groups
      */
-    public ColumnGroupRow addColumnGroupRow() {
-        ColumnGroupRow row = new ColumnGroupRow(this);
+    public ColumnGroupRow<T> addColumnGroupRow() {
+        ColumnGroupRow<T> row = new ColumnGroupRow<T>(this);
         columnGroupRows.add(row);
         refreshHeader();
         refreshFooter();
@@ -767,8 +830,8 @@ public class Grid<T> extends Composite {
      *            the index where the column group row should be added
      * @return a column group row instance you can use to add column groups
      */
-    public ColumnGroupRow addColumnGroupRow(int rowIndex) {
-        ColumnGroupRow row = new ColumnGroupRow(this);
+    public ColumnGroupRow<T> addColumnGroupRow(int rowIndex) {
+        ColumnGroupRow<T> row = new ColumnGroupRow<T>(this);
         columnGroupRows.add(rowIndex, row);
         refreshHeader();
         refreshFooter();
@@ -781,7 +844,7 @@ public class Grid<T> extends Composite {
      * @param row
      *            The row to remove
      */
-    public void removeColumnGroupRow(ColumnGroupRow row) {
+    public void removeColumnGroupRow(ColumnGroupRow<T> row) {
         columnGroupRows.remove(row);
         refreshHeader();
         refreshFooter();
@@ -793,8 +856,8 @@ public class Grid<T> extends Composite {
      * @return a unmodifiable list of column group rows
      * 
      */
-    public List<ColumnGroupRow> getColumnGroupRows() {
-        return Collections.unmodifiableList(new ArrayList<ColumnGroupRow>(
+    public List<ColumnGroupRow<T>> getColumnGroupRows() {
+        return Collections.unmodifiableList(new ArrayList<ColumnGroupRow<T>>(
                 columnGroupRows));
     }
 
@@ -808,10 +871,10 @@ public class Grid<T> extends Composite {
      * @return A column group for the row and column or <code>null</code> if not
      *         found.
      */
-    private static ColumnGroup getGroupForColumn(ColumnGroupRow row,
-            GridColumn column) {
-        for (ColumnGroup group : row.getGroups()) {
-            List<GridColumn> columns = group.getColumns();
+    private ColumnGroup<T> getGroupForColumn(ColumnGroupRow<T> row,
+            GridColumn<?, T> column) {
+        for (ColumnGroup<T> group : row.getGroups()) {
+            List<GridColumn<?, T>> columns = group.getColumns();
             if (columns.contains(column)) {
                 return group;
             }
@@ -888,7 +951,7 @@ public class Grid<T> extends Composite {
      * @throws IllegalArgumentException
      *             if {@code lastFrozenColumn} is not a column from this grid
      */
-    public void setLastFrozenColumn(GridColumn<T> lastFrozenColumn) {
+    public void setLastFrozenColumn(GridColumn<?, T> lastFrozenColumn) {
         this.lastFrozenColumn = lastFrozenColumn;
         refreshFrozenColumns();
     }
@@ -918,7 +981,7 @@ public class Grid<T> extends Composite {
      * @return the rightmost frozen column in the grid, or <code>null</code> if
      *         no columns are frozen.
      */
-    public GridColumn<T> getLastFrozenColumn() {
+    public GridColumn<?, T> getLastFrozenColumn() {
         return lastFrozenColumn;
     }
 }
index 992bfae0148c61893918048722f7f288038eb350..ad74a008b9434eea68abb4fb290904d916ccce3f 100644 (file)
@@ -18,13 +18,16 @@ package com.vaadin.client.ui.grid;
 /**
  * Represents a column in the {@link Grid}.
  * 
+ * @param <C>
+ *            The column type
+ * 
  * @param <T>
  *            The row type
  * 
  * @since 7.2
  * @author Vaadin Ltd
  */
-public abstract class GridColumn<T> extends Grid.AbstractGridColumn<T> {
+public abstract class GridColumn<C, T> extends Grid.AbstractGridColumn<C, T> {
 
     /*
      * This class is a convenience class so you do not have to reference
index ac209b9c2c52cbd98747dfce7cb232ea2e8ce587..47558b2f2276763145db7aa3be76f2523ccc7b87 100644 (file)
@@ -44,9 +44,9 @@ public class GridConnector extends AbstractComponentConnector {
 
     /**
      * Custom implementation of the custom grid column using a String[] to
-     * represent the cell value
+     * represent the cell value and String as a column type.
      */
-    private class CustomGridColumn extends GridColumn<String[]> {
+    private class CustomGridColumn extends GridColumn<String, String[]> {
 
         private final int columnIndex;
 
@@ -147,7 +147,7 @@ public class GridConnector extends AbstractComponentConnector {
      *            The index of the column to update
      */
     private void updateColumnFromStateChangeEvent(int columnIndex) {
-        GridColumn<String[]> column = getWidget().getColumn(columnIndex);
+        GridColumn<?, String[]> column = getWidget().getColumn(columnIndex);
         GridColumnState columnState = getState().columns.get(columnIndex);
         updateColumnFromState(column, columnState);
     }
@@ -176,7 +176,7 @@ public class GridConnector extends AbstractComponentConnector {
      * @param state
      *            The state to get the data from
      */
-    private static void updateColumnFromState(GridColumn<String[]> column,
+    private static void updateColumnFromState(GridColumn<?, String[]> column,
             GridColumnState state) {
         column.setVisible(state.visible);
         column.setHeaderCaption(state.header);
@@ -216,22 +216,22 @@ public class GridConnector extends AbstractComponentConnector {
         // FIXME When something changes the header/footer rows will be
         // re-created. At some point we should optimize this so partial updates
         // can be made on the header/footer.
-        for (ColumnGroupRow row : getWidget().getColumnGroupRows()) {
+        for (ColumnGroupRow<String[]> row : getWidget().getColumnGroupRows()) {
             getWidget().removeColumnGroupRow(row);
         }
 
         for (ColumnGroupRowState rowState : getState().columnGroupRows) {
-            ColumnGroupRow row = getWidget().addColumnGroupRow();
+            ColumnGroupRow<String[]> row = getWidget().addColumnGroupRow();
             row.setFooterVisible(rowState.footerVisible);
             row.setHeaderVisible(rowState.headerVisible);
 
             for (ColumnGroupState groupState : rowState.groups) {
-                List<GridColumn> columns = new ArrayList<GridColumn>();
+                List<GridColumn<String, String[]>> columns = new ArrayList<GridColumn<String, String[]>>();
                 for (String columnId : groupState.columns) {
                     CustomGridColumn column = columnIdToColumn.get(columnId);
                     columns.add(column);
                 }
-                ColumnGroup group = row.addGroup(columns
+                ColumnGroup<String[]> group = row.addGroup(columns
                         .toArray(new GridColumn[columns.size()]));
                 group.setFooterCaption(groupState.footer);
                 group.setHeaderCaption(groupState.header);
diff --git a/client/src/com/vaadin/client/ui/grid/Renderer.java b/client/src/com/vaadin/client/ui/grid/Renderer.java
new file mode 100644 (file)
index 0000000..7ead3ad
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2013 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.client.ui.grid;
+
+/**
+ * Renderer for rending a value <T> into cell.
+ * <p>
+ * You can add a renderer to any column by overring the
+ * {@link GridColumn#getRenderer()} method and returning your own renderer. You
+ * can retrieve the cell element using {@link Cell#getElement()}.
+ * 
+ * @param <T>
+ *            The row type
+ * 
+ * @since 7.2
+ * @author Vaadin Ltd
+ */
+public interface Renderer<T> {
+
+    /**
+     * Called whenever the {@link Grid} updates a cell
+     * 
+     * @param cell
+     *            The cell that gets updated
+     * 
+     * @param data
+     *            The row data object
+     */
+    public void renderCell(Cell cell, T data);
+}