From c8e0335ccd4e2af54efe752fc98b20c52fafabcf Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Fri, 1 Aug 2014 15:07:30 +0300 Subject: [PATCH] Add server side support for Components in Headers and Footers (#13334) Change-Id: Ic5a6b4c68bc2d09840cbd7faffebae8991a5fff4 --- .../src/com/vaadin/client/ui/grid/Grid.java | 5 +- .../vaadin/client/ui/grid/GridConnector.java | 42 ++++++++- .../client/ui/grid/GridStaticSection.java | 21 ++--- .../com/vaadin/ui/components/grid/Grid.java | 38 +++++++- .../vaadin/ui/components/grid/GridFooter.java | 2 +- .../vaadin/ui/components/grid/GridHeader.java | 2 +- .../ui/components/grid/GridStaticSection.java | 93 +++++++++++++++---- .../shared/ui/grid/GridStaticCellType.java | 39 ++++++++ .../ui/grid/GridStaticSectionState.java | 8 ++ .../grid/basicfeatures/GridBasicFeatures.java | 88 ++++++++++++++++++ .../GridStaticSectionComponentTest.java | 56 +++++++++++ 11 files changed, 354 insertions(+), 40 deletions(-) create mode 100644 shared/src/com/vaadin/shared/ui/grid/GridStaticCellType.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java diff --git a/client/src/com/vaadin/client/ui/grid/Grid.java b/client/src/com/vaadin/client/ui/grid/Grid.java index cf0606a38c..d1858a8f3f 100644 --- a/client/src/com/vaadin/client/ui/grid/Grid.java +++ b/client/src/com/vaadin/client/ui/grid/Grid.java @@ -62,6 +62,7 @@ import com.vaadin.client.ui.grid.sort.SortEvent; import com.vaadin.client.ui.grid.sort.SortEventHandler; import com.vaadin.client.ui.grid.sort.SortOrder; import com.vaadin.shared.ui.grid.GridConstants; +import com.vaadin.shared.ui.grid.GridStaticCellType; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.Range; import com.vaadin.shared.ui.grid.ScrollDestination; @@ -1101,7 +1102,7 @@ public class Grid extends Composite implements * If the cell contains widgets that are not currently attach * then attach them now. */ - if (StaticCell.Type.WIDGET.equals(metadata.getType())) { + if (GridStaticCellType.WIDGET.equals(metadata.getType())) { final Widget widget = metadata.getWidget(); final Element cellElement = cell.getElement(); @@ -1129,7 +1130,7 @@ public class Grid extends Composite implements int index = columnIndices.get(cell.getColumn()); StaticCell metadata = gridRow.getCell(index); - if (StaticCell.Type.WIDGET.equals(metadata.getType()) + if (GridStaticCellType.WIDGET.equals(metadata.getType()) && metadata.getWidget().isAttached()) { Widget widget = metadata.getWidget(); diff --git a/client/src/com/vaadin/client/ui/grid/GridConnector.java b/client/src/com/vaadin/client/ui/grid/GridConnector.java index 56affc75d1..12952c7db8 100644 --- a/client/src/com/vaadin/client/ui/grid/GridConnector.java +++ b/client/src/com/vaadin/client/ui/grid/GridConnector.java @@ -30,11 +30,13 @@ import java.util.logging.Logger; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONValue; +import com.vaadin.client.ComponentConnector; +import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.data.DataSource.RowHandle; import com.vaadin.client.data.RpcDataSourceConnector.RpcDataSource; -import com.vaadin.client.ui.AbstractComponentConnector; +import com.vaadin.client.ui.AbstractHasComponentsConnector; import com.vaadin.client.ui.grid.GridHeader.HeaderRow; import com.vaadin.client.ui.grid.GridStaticSection.StaticCell; import com.vaadin.client.ui.grid.GridStaticSection.StaticRow; @@ -73,7 +75,7 @@ import com.vaadin.shared.ui.grid.SortDirection; * @author Vaadin Ltd */ @Connect(com.vaadin.ui.components.grid.Grid.class) -public class GridConnector extends AbstractComponentConnector { +public class GridConnector extends AbstractHasComponentsConnector { /** * Custom implementation of the custom grid column using a JSONObject to @@ -297,8 +299,22 @@ public class GridConnector extends AbstractComponentConnector { int i = 0; for (CellState cellState : rowState.cells) { - StaticCell cell = row.getCell(diff + (i++)); - cell.setText(cellState.text); + StaticCell cell = row.getCell(i++); + switch (cellState.type) { + case TEXT: + cell.setText(cellState.text); + break; + case HTML: + cell.setHtml(cellState.text); + break; + case WIDGET: + ComponentConnector connector = (ComponentConnector) cellState.connector; + cell.setWidget(connector.getWidget()); + break; + default: + throw new IllegalStateException("unexpected cell type: " + + cellState.type); + } } for (List group : rowState.cellGroups) { @@ -570,4 +586,22 @@ public class GridConnector extends AbstractComponentConnector { + key.getClass().getSimpleName() + " (" + key + ")"; return (String) key; } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.client.HasComponentsConnector#updateCaption(com.vaadin.client + * .ComponentConnector) + */ + @Override + public void updateCaption(ComponentConnector connector) { + // TODO Auto-generated method stub + + } + + @Override + public void onConnectorHierarchyChange( + ConnectorHierarchyChangeEvent connectorHierarchyChangeEvent) { + } } diff --git a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java index 14e4d6de9c..1be0a92b8f 100644 --- a/client/src/com/vaadin/client/ui/grid/GridStaticSection.java +++ b/client/src/com/vaadin/client/ui/grid/GridStaticSection.java @@ -22,6 +22,7 @@ import java.util.HashSet; import java.util.List; import com.google.gwt.user.client.ui.Widget; +import com.vaadin.shared.ui.grid.GridStaticCellType; /** * Abstract base class for Grid header and footer sections. @@ -39,17 +40,13 @@ abstract class GridStaticSection> */ static class StaticCell { - public enum Type { - TEXT, HTML, WIDGET; - } - private Object content = null; private int colspan = 1; private GridStaticSection section; - private Type type = Type.TEXT; + private GridStaticCellType type = GridStaticCellType.TEXT; /** * Sets the text displayed in this cell. @@ -59,7 +56,7 @@ abstract class GridStaticSection> */ public void setText(String text) { this.content = text; - this.type = Type.TEXT; + this.type = GridStaticCellType.TEXT; section.requestSectionRefresh(); } @@ -69,7 +66,7 @@ abstract class GridStaticSection> * @return the plain text caption */ public String getText() { - if (type != Type.TEXT) { + if (type != GridStaticCellType.TEXT) { throw new IllegalStateException( "Cannot fetch Text from a cell with type " + type); } @@ -120,7 +117,7 @@ abstract class GridStaticSection> * @return the html content of the cell. */ public String getHtml() { - if (type != Type.HTML) { + if (type != GridStaticCellType.HTML) { throw new IllegalStateException( "Cannot fetch HTML from a cell with type " + type); } @@ -136,7 +133,7 @@ abstract class GridStaticSection> */ public void setHtml(String html) { this.content = html; - this.type = Type.HTML; + this.type = GridStaticCellType.HTML; section.requestSectionRefresh(); } @@ -149,7 +146,7 @@ abstract class GridStaticSection> * @return the widget in the cell */ public Widget getWidget() { - if (type != Type.WIDGET) { + if (type != GridStaticCellType.WIDGET) { throw new IllegalStateException( "Cannot fetch Widget from a cell with type " + type); } @@ -166,7 +163,7 @@ abstract class GridStaticSection> */ public void setWidget(Widget widget) { this.content = widget; - this.type = Type.WIDGET; + this.type = GridStaticCellType.WIDGET; section.requestSectionRefresh(); } @@ -175,7 +172,7 @@ abstract class GridStaticSection> * * @return the type of content the cell contains. */ - public Type getType() { + public GridStaticCellType getType() { return type; } } diff --git a/server/src/com/vaadin/ui/components/grid/Grid.java b/server/src/com/vaadin/ui/components/grid/Grid.java index 2e0ac6bb31..d365d3e0cc 100644 --- a/server/src/com/vaadin/ui/components/grid/Grid.java +++ b/server/src/com/vaadin/ui/components/grid/Grid.java @@ -45,10 +45,16 @@ import com.vaadin.shared.ui.grid.GridColumnState; import com.vaadin.shared.ui.grid.GridServerRpc; import com.vaadin.shared.ui.grid.GridState; import com.vaadin.shared.ui.grid.GridState.SharedSelectionMode; +import com.vaadin.shared.ui.grid.GridStaticCellType; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.shared.ui.grid.ScrollDestination; import com.vaadin.shared.ui.grid.SortDirection; import com.vaadin.ui.AbstractComponent; +import com.vaadin.ui.Component; +import com.vaadin.ui.HasComponents; +import com.vaadin.ui.components.grid.GridFooter.FooterCell; +import com.vaadin.ui.components.grid.GridFooter.FooterRow; +import com.vaadin.ui.components.grid.GridHeader.HeaderCell; import com.vaadin.ui.components.grid.GridHeader.HeaderRow; import com.vaadin.ui.components.grid.selection.MultiSelectionModel; import com.vaadin.ui.components.grid.selection.NoSelectionModel; @@ -123,7 +129,8 @@ import com.vaadin.util.ReflectTools; * @since * @author Vaadin Ltd */ -public class Grid extends AbstractComponent implements SelectionChangeNotifier { +public class Grid extends AbstractComponent implements SelectionChangeNotifier, + HasComponents { /** * Selection modes representing built-in {@link SelectionModel @@ -1259,4 +1266,33 @@ public class Grid extends AbstractComponent implements SelectionChangeNotifier { public GridFooter getFooter() { return footer; } + + @Override + public Iterator iterator() { + List componentList = new ArrayList(); + + GridHeader header = getHeader(); + for (int i = 0; i < header.getRowCount(); ++i) { + HeaderRow row = header.getRow(i); + for (Object propId : datasource.getContainerPropertyIds()) { + HeaderCell cell = row.getCell(propId); + if (cell.getCellState().type == GridStaticCellType.WIDGET) { + componentList.add(cell.getComponent()); + } + } + } + + GridFooter footer = getFooter(); + for (int i = 0; i < footer.getRowCount(); ++i) { + FooterRow row = footer.getRow(i); + for (Object propId : datasource.getContainerPropertyIds()) { + FooterCell cell = row.getCell(propId); + if (cell.getCellState().type == GridStaticCellType.WIDGET) { + componentList.add(cell.getComponent()); + } + } + } + + return componentList.iterator(); + } } diff --git a/server/src/com/vaadin/ui/components/grid/GridFooter.java b/server/src/com/vaadin/ui/components/grid/GridFooter.java index 84b2b70090..0a28a481cf 100644 --- a/server/src/com/vaadin/ui/components/grid/GridFooter.java +++ b/server/src/com/vaadin/ui/components/grid/GridFooter.java @@ -38,7 +38,7 @@ public class GridFooter extends GridStaticSection { } - public class FooterCell extends GridStaticSection.StaticCell { + public class FooterCell extends GridStaticSection.StaticCell { protected FooterCell(FooterRow row) { super(row); diff --git a/server/src/com/vaadin/ui/components/grid/GridHeader.java b/server/src/com/vaadin/ui/components/grid/GridHeader.java index 67f7bfdf69..9d7ec24a97 100644 --- a/server/src/com/vaadin/ui/components/grid/GridHeader.java +++ b/server/src/com/vaadin/ui/components/grid/GridHeader.java @@ -41,7 +41,7 @@ public class GridHeader extends GridStaticSection { } } - public class HeaderCell extends GridStaticSection.StaticCell { + public class HeaderCell extends GridStaticSection.StaticCell { protected HeaderCell(HeaderRow row) { super(row); diff --git a/server/src/com/vaadin/ui/components/grid/GridStaticSection.java b/server/src/com/vaadin/ui/components/grid/GridStaticSection.java index 8c983052ea..eb098d0d4e 100644 --- a/server/src/com/vaadin/ui/components/grid/GridStaticSection.java +++ b/server/src/com/vaadin/ui/components/grid/GridStaticSection.java @@ -26,9 +26,11 @@ import java.util.List; import java.util.Map; import com.vaadin.data.Container.Indexed; +import com.vaadin.shared.ui.grid.GridStaticCellType; import com.vaadin.shared.ui.grid.GridStaticSectionState; import com.vaadin.shared.ui.grid.GridStaticSectionState.CellState; import com.vaadin.shared.ui.grid.GridStaticSectionState.RowState; +import com.vaadin.ui.Component; /** * Abstract base class for Grid header and footer sections. @@ -47,7 +49,7 @@ abstract class GridStaticSection> * @param * the type of the cells in the row */ - abstract static class StaticRow> implements + abstract static class StaticRow implements Serializable { private RowState rowState = new RowState(); @@ -184,17 +186,13 @@ abstract class GridStaticSection> /** * A header or footer cell. Has a simple textual caption. - * - * @param - * the type of row this cells is in */ - abstract static class StaticCell> implements - Serializable { + abstract static class StaticCell implements Serializable { private CellState cellState = new CellState(); - private ROWTYPE row; + private StaticRow row; - protected StaticCell(ROWTYPE row) { + protected StaticCell(StaticRow row) { this.row = row; } @@ -203,7 +201,7 @@ abstract class GridStaticSection> * * @return row for this cell */ - public ROWTYPE getRow() { + public StaticRow getRow() { return row; } @@ -212,26 +210,83 @@ abstract class GridStaticSection> } /** - * Gets the current text content of this cell. Text is null if HTML or - * Component content is used. + * Sets the text displayed in this cell. * - * @return text content or null + * @param text + * a plain text caption + */ + public void setText(String text) { + cellState.text = text; + cellState.type = GridStaticCellType.TEXT; + row.section.markAsDirty(); + } + + /** + * Returns the text displayed in this cell. + * + * @return the plain text caption */ public String getText() { + if (cellState.type != GridStaticCellType.TEXT) { + throw new IllegalStateException( + "Cannot fetch Text from a cell with type " + + cellState.type); + } return cellState.text; } /** - * Sets the current text content of this cell. + * Returns the HTML content displayed in this cell. + * + * @return the html * - * @param text - * new text content */ - public void setText(String text) { - if (text != null && !text.equals(getCellState().text)) { - getCellState().text = text; - row.section.markAsDirty(); + public String getHtml() { + if (cellState.type != GridStaticCellType.HTML) { + throw new IllegalStateException( + "Cannot fetch HTML from a cell with type " + + cellState.type); } + return cellState.html; + } + + /** + * Sets the HTML content displayed in this cell. + * + * @param html + * the html to set + */ + public void setHtml(String html) { + cellState.html = html; + cellState.type = GridStaticCellType.HTML; + row.section.markAsDirty(); + } + + /** + * Returns the component displayed in this cell. + * + * @return the component + */ + public Component getComponent() { + if (cellState.type != GridStaticCellType.WIDGET) { + throw new IllegalStateException( + "Cannot fetch Component from a cell with type " + + cellState.type); + } + return (Component) cellState.connector; + } + + /** + * Sets the component displayed in this cell. + * + * @param component + * the component to set + */ + public void setComponent(Component component) { + component.setParent(row.section.grid); + cellState.connector = component; + cellState.type = GridStaticCellType.WIDGET; + row.section.markAsDirty(); } } diff --git a/shared/src/com/vaadin/shared/ui/grid/GridStaticCellType.java b/shared/src/com/vaadin/shared/ui/grid/GridStaticCellType.java new file mode 100644 index 0000000000..eae4bc8da4 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/grid/GridStaticCellType.java @@ -0,0 +1,39 @@ +/* + * 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.shared.ui.grid; + +/** + * Enumeration, specifying the content type of a Cell in a GridStaticSection. + * + * @since + * @author Vaadin Ltd + */ +public enum GridStaticCellType { + /** + * Text content + */ + TEXT, + + /** + * HTML content + */ + HTML, + + /** + * Widget content + */ + WIDGET; +} \ No newline at end of file diff --git a/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java b/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java index 41f56199da..c3c373b5af 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridStaticSectionState.java @@ -19,6 +19,8 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import com.vaadin.shared.Connector; + /** * Shared state for Grid headers and footers. * @@ -29,6 +31,12 @@ public class GridStaticSectionState implements Serializable { public static class CellState implements Serializable { public String text = ""; + + public String html = ""; + + public Connector connector = null; + + public GridStaticCellType type = GridStaticCellType.TEXT; } public static class RowState implements Serializable { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 8b3391253b..031ebf7fa5 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -28,14 +28,20 @@ import java.util.Random; import com.vaadin.data.Item; import com.vaadin.data.Property; import com.vaadin.data.util.IndexedContainer; +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.components.grid.Grid; import com.vaadin.ui.components.grid.Grid.SelectionMode; import com.vaadin.ui.components.grid.GridColumn; import com.vaadin.ui.components.grid.GridFooter; +import com.vaadin.ui.components.grid.GridFooter.FooterCell; import com.vaadin.ui.components.grid.GridHeader; +import com.vaadin.ui.components.grid.GridHeader.HeaderCell; import com.vaadin.ui.components.grid.GridHeader.HeaderRow; import com.vaadin.ui.components.grid.SortOrderChangeEvent; import com.vaadin.ui.components.grid.SortOrderChangeListener; @@ -440,6 +446,88 @@ public class GridBasicFeatures extends AbstractComponentTest { } }, w, c); } + + LinkedHashMap defaultRows = new LinkedHashMap(); + 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() { + + @Override + public void execute(Grid grid, + GridStaticCellType value, Object columnIndex) { + final Object propertyId = (new ArrayList(grid + .getContainerDatasource() + .getContainerPropertyIds()) + .get((Integer) columnIndex)); + final HeaderCell cell = grid.getHeader() + .getDefaultRow().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(); + 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() { + + @Override + public void execute(Grid grid, + GridStaticCellType value, Object columnIndex) { + final Object propertyId = (new ArrayList(grid + .getContainerDatasource() + .getContainerPropertyIds()) + .get((Integer) columnIndex)); + final FooterCell cell = grid.getFooter().getRow(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); } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java new file mode 100644 index 0000000000..fe32825d75 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridStaticSectionComponentTest.java @@ -0,0 +1,56 @@ +/* + * 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 static org.junit.Assert.assertEquals; + +import java.io.IOException; + +import org.junit.Test; + +import com.vaadin.testbench.elements.ButtonElement; + +public class GridStaticSectionComponentTest extends GridBasicFeaturesTest { + + @Test + public void testNativeButtonInHeader() throws IOException { + openTestURL(); + + selectMenuPath("Component", "Columns", "Column 1", "Header Type", + "Widget Header"); + + getGridElement().$(ButtonElement.class).first().click(); + + // Clicking also triggers sorting + assertEquals("2. Button clicked!", getLogRow(2)); + + compareScreen("button"); + } + + @Test + public void testNativeButtonInFooter() throws IOException { + openTestURL(); + + selectMenuPath("Component", "Footer", "Visible"); + selectMenuPath("Component", "Footer", "Append row"); + selectMenuPath("Component", "Columns", "Column 1", "Footer Type", + "Widget Footer"); + + getGridElement().$(ButtonElement.class).first().click(); + + assertEquals("4. Button clicked!", getLogRow(0)); + } +} -- 2.39.5