diff options
author | Artur Signell <artur@vaadin.com> | 2016-01-16 19:44:26 +0200 |
---|---|---|
committer | Artur Signell <artur@vaadin.com> | 2016-01-29 07:56:56 +0000 |
commit | b99d9e0cef04a2137b665367fcc562491f15b972 (patch) | |
tree | 9487ea4ca1d867c8e39a0649f55f52025ef5aa3e | |
parent | f300a2f7e4b5a11390eea13bd2c6892b85e99def (diff) | |
download | vaadin-framework-b99d9e0cef04a2137b665367fcc562491f15b972.tar.gz vaadin-framework-b99d9e0cef04a2137b665367fcc562491f15b972.zip |
Make hiding/showing components in grid header/footer work (#19297)
Change-Id: Iebe1135e26f2f6fae98befb7c42e3c0fdb18c13b
4 files changed, 325 insertions, 37 deletions
diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java index 808b7ba2f3..7d8a2a8fbf 100644 --- a/client/src/com/vaadin/client/connectors/GridConnector.java +++ b/client/src/com/vaadin/client/connectors/GridConnector.java @@ -937,7 +937,13 @@ public class GridConnector extends AbstractHasComponentsConnector implements break; case WIDGET: ComponentConnector connector = (ComponentConnector) cellState.connector; - cell.setWidget(connector.getWidget()); + if (connector != null) { + cell.setWidget(connector.getWidget()); + } else { + // This happens if you do setVisible(false) on the component on + // the server side + cell.setWidget(null); + } break; default: throw new IllegalStateException("unexpected cell type: " @@ -991,7 +997,13 @@ public class GridConnector extends AbstractHasComponentsConnector implements break; case WIDGET: ComponentConnector connector = (ComponentConnector) cellState.connector; - cell.setWidget(connector.getWidget()); + if (connector != null) { + cell.setWidget(connector.getWidget()); + } else { + // This happens if you do setVisible(false) on the component on + // the server side + cell.setWidget(null); + } break; default: throw new IllegalStateException("unexpected cell type: " diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index e3c51830fe..0de5e7a239 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -116,10 +116,10 @@ import com.vaadin.client.widget.grid.DetailsGenerator; import com.vaadin.client.widget.grid.EditorHandler; import com.vaadin.client.widget.grid.EditorHandler.EditorRequest; import com.vaadin.client.widget.grid.EventCellReference; +import com.vaadin.client.widget.grid.HeightAwareDetailsGenerator; import com.vaadin.client.widget.grid.RendererCellReference; import com.vaadin.client.widget.grid.RowReference; import com.vaadin.client.widget.grid.RowStyleGenerator; -import com.vaadin.client.widget.grid.HeightAwareDetailsGenerator; import com.vaadin.client.widget.grid.events.AbstractGridKeyEventHandler; import com.vaadin.client.widget.grid.events.AbstractGridMouseEventHandler; import com.vaadin.client.widget.grid.events.BodyClickHandler; @@ -371,6 +371,14 @@ public class Grid<T> extends ResizeComposite implements * null). */ public void setWidget(Widget widget) { + if (this.content == widget) { + return; + } + + if (this.content instanceof Widget) { + // Old widget in the cell, detach it first + section.getGrid().detachWidget((Widget) this.content); + } this.content = widget; this.type = GridStaticCellType.WIDGET; section.requestSectionRefresh(); @@ -407,6 +415,17 @@ public class Grid<T> extends ResizeComposite implements } + /** + * Called when the cell is detached from the row + * + * @since + */ + void detach() { + if (this.content instanceof Widget) { + // Widget in the cell, detach it + section.getGrid().detachWidget((Widget) this.content); + } + } } /** @@ -626,6 +645,22 @@ public class Grid<T> extends ResizeComposite implements this.styleName = styleName; section.requestSectionRefresh(); } + + /** + * Called when the row is detached from the grid + * + * @since + */ + void detach() { + // Avoid calling detach twice for a merged cell + HashSet<CELLTYPE> cells = new HashSet<CELLTYPE>(); + for (Column<?, ?> column : getSection().grid.getColumns()) { + cells.add(getCell(column)); + } + for (CELLTYPE cell : cells) { + cell.detach(); + } + } } private Grid<?> grid; @@ -738,7 +773,8 @@ public class Grid<T> extends ResizeComposite implements * @see #removeRow(StaticRow) */ public void removeRow(int index) { - rows.remove(index); + ROWTYPE row = rows.remove(index); + row.detach(); requestSectionRefresh(); } @@ -1820,7 +1856,7 @@ public class Grid<T> extends ResizeComposite implements if (editor != null) { columnToWidget.put(column, editor); - attachWidget(editor, cell); + grid.attachWidget(editor, cell); } if (i == focusedColumnIndex) { @@ -1866,7 +1902,7 @@ public class Grid<T> extends ResizeComposite implements } } }); - attachWidget(checkBox, cell); + grid.attachWidget(checkBox, cell); columnToWidget.put(column, checkBox); // Only enable CheckBox in non-buffered mode @@ -1891,8 +1927,8 @@ public class Grid<T> extends ResizeComposite implements } if (isBuffered()) { - attachWidget(saveButton, buttonsWrapper); - attachWidget(cancelButton, buttonsWrapper); + grid.attachWidget(saveButton, buttonsWrapper); + grid.attachWidget(cancelButton, buttonsWrapper); } setMessageAndButtonsWrapperVisible(isBuffered()); @@ -1981,8 +2017,8 @@ public class Grid<T> extends ResizeComposite implements } columnToWidget.clear(); - detachWidget(saveButton); - detachWidget(cancelButton); + grid.detachWidget(saveButton); + grid.detachWidget(cancelButton); editorOverlay.removeAllChildren(); cellWrapper.removeAllChildren(); @@ -2052,16 +2088,6 @@ public class Grid<T> extends ResizeComposite implements return cell; } - private void attachWidget(Widget w, Element parent) { - parent.appendChild(w.getElement()); - setParent(w, grid); - } - - private void detachWidget(Widget w) { - setParent(w, null); - w.getElement().removeFromParent(); - } - private static void setBounds(Element e, double left, double top, double width, double height) { Style style = e.getStyle(); @@ -5787,20 +5813,14 @@ public class Grid<T> extends ResizeComposite implements StaticSection.StaticCell metadata = gridRow.getCell(columns .get(cell.getColumn())); /* - * If the cell contains widgets that are not currently attach + * If the cell contains widgets that are not currently attached * then attach them now. */ if (GridStaticCellType.WIDGET.equals(metadata.getType())) { final Widget widget = metadata.getWidget(); - final Element cellElement = cell.getElement(); - - if (!widget.isAttached()) { - - // Physical attach - cellElement.appendChild(widget.getElement()); - - // Logical attach - setParent(widget, Grid.this); + if (widget != null && !widget.isAttached()) { + getGrid().attachWidget(metadata.getWidget(), + cell.getElement()); } } } @@ -5817,20 +5837,19 @@ public class Grid<T> extends ResizeComposite implements .get(cell.getColumn())); if (GridStaticCellType.WIDGET.equals(metadata.getType()) + && metadata.getWidget() != null && metadata.getWidget().isAttached()) { - Widget widget = metadata.getWidget(); - - // Logical detach - setParent(widget, null); - - // Physical detach - widget.getElement().removeFromParent(); + getGrid().detachWidget(metadata.getWidget()); } } } } + protected Grid getGrid() { + return section.grid; + } + @Override public void postDetach(Row row, Iterable<FlyweightCell> detachedCells) { } @@ -8585,6 +8604,20 @@ public class Grid<T> extends ResizeComposite implements } } + private void attachWidget(Widget w, Element parent) { + assert w.getParent() == null; + + parent.appendChild(w.getElement()); + setParent(w, this); + } + + private void detachWidget(Widget w) { + assert w.getParent() == this; + + setParent(w, null); + w.getElement().removeFromParent(); + } + /** * Resets all cached pixel sizes and reads new values from the DOM. This * methods should be used e.g. when styles affecting the dimensions of diff --git a/uitest/src/com/vaadin/tests/components/grid/GridHeaderFooterComponents.java b/uitest/src/com/vaadin/tests/components/grid/GridHeaderFooterComponents.java new file mode 100644 index 0000000000..6c2efc9a25 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridHeaderFooterComponents.java @@ -0,0 +1,140 @@ +/* + * 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; + +import com.vaadin.annotations.Theme; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.data.util.IndexedContainer; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Component; +import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.FooterRow; +import com.vaadin.ui.Grid.HeaderRow; +import com.vaadin.ui.TextField; + +@Theme("valo") +public class GridHeaderFooterComponents extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + final Grid grid = new Grid(); + grid.setWidth("800px"); + grid.setContainerDataSource(createContainer()); + grid.setFooterVisible(true); + final HeaderRow defaultRow = grid.getDefaultHeaderRow(); + final HeaderRow toggleVisibilityRow = grid.appendHeaderRow(); + final Grid.HeaderRow filterRow = grid.appendHeaderRow(); + + final FooterRow footerRow = grid.addFooterRowAt(0); + final FooterRow toggleVisibilityFooterRow = grid.addFooterRowAt(0); + final FooterRow filterFooterRow = grid.addFooterRowAt(0); + + // Set up a filter for all columns + for (final Object pid : grid.getContainerDataSource() + .getContainerPropertyIds()) { + final Grid.HeaderCell headerCell = filterRow.getCell(pid); + final Grid.FooterCell footerCell = filterFooterRow.getCell(pid); + + headerCell.setComponent(createTextField(pid)); + footerCell.setComponent(createTextField(pid)); + + toggleVisibilityRow.getCell(pid).setComponent( + new Button("Toggle field", new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + Component c = headerCell.getComponent(); + c.setVisible(!c.isVisible()); + } + })); + toggleVisibilityFooterRow.getCell(pid).setComponent( + new Button("Toggle field", new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + Component c = footerCell.getComponent(); + c.setVisible(!c.isVisible()); + } + })); + } + addComponent(grid); + + addRemoveHeaderRow(grid, defaultRow); + addRemoveHeaderRow(grid, filterRow); + addRemoveHeaderRow(grid, toggleVisibilityRow); + + addRemoveFooterRow(grid, footerRow); + addRemoveFooterRow(grid, filterFooterRow); + addRemoveFooterRow(grid, toggleVisibilityFooterRow); + + // Hide first field initially + filterRow.getCell("string").getComponent().setVisible(false); + filterFooterRow.getCell("string").getComponent().setVisible(false); + } + + private void addRemoveHeaderRow(final Grid grid, final HeaderRow row) { + row.getCell("action").setComponent( + new Button("Remove row", new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + grid.removeHeaderRow(row); + } + })); + + } + + private void addRemoveFooterRow(final Grid grid, final FooterRow row) { + row.getCell("action").setComponent( + new Button("Remove row", new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + grid.removeFooterRow(row); + } + })); + + } + + private IndexedContainer createContainer() { + IndexedContainer ic = new IndexedContainer(); + ic.addContainerProperty("action", String.class, ""); + ic.addContainerProperty("string", String.class, "Hello world"); + ic.addContainerProperty("int", int.class, 13); + ic.addContainerProperty("double", double.class, 5.2f); + + for (int i = 0; i < 5; i++) { + ic.addItem(); + } + return ic; + } + + private TextField createTextField(final Object pid) { + TextField filterField = new TextField(); + filterField.setColumns(8); + filterField.setValue("Filter: " + pid); + filterField.addValueChangeListener(new ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + log("value change for field in " + pid + " to " + + event.getProperty().getValue()); + } + }); + return filterField; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridHeaderFooterComponentsTest.java b/uitest/src/com/vaadin/tests/components/grid/GridHeaderFooterComponentsTest.java new file mode 100644 index 0000000000..977b16cebd --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridHeaderFooterComponentsTest.java @@ -0,0 +1,103 @@ +/* + * 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; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.elements.GridElement.GridCellElement; +import com.vaadin.testbench.elements.TextFieldElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class GridHeaderFooterComponentsTest extends SingleBrowserTest { + + @Test + public void hideAndShowComponentsInHeader() { + openTestURL(); + GridElement grid = $(GridElement.class).first(); + + int filterRow = 2; + Assert.assertNull(getHeaderElement(grid, filterRow, 1)); + Assert.assertNotNull(getHeaderElement(grid, filterRow, 2)); + Assert.assertNotNull(getHeaderElement(grid, filterRow, 3)); + + // Show (1,2) + grid.getHeaderCell(1, 1).$(ButtonElement.class).first().click(); + + TextFieldElement textfield = getHeaderElement(grid, filterRow, 1); + Assert.assertNotNull(textfield); + Assert.assertEquals("Filter: string", textfield.getValue()); + + textfield.setValue("foo"); + Assert.assertEquals("1. value change for field in string to foo", + getLogRow(0)); + } + + private TextFieldElement getHeaderElement(GridElement grid, int row, int col) { + GridCellElement cell = grid.getHeaderCell(row, col); + List<TextFieldElement> all = cell.$(TextFieldElement.class).all(); + if (all.size() == 0) { + return null; + } else if (all.size() == 1) { + return all.get(0); + } else { + throw new RuntimeException( + "Multiple elements found in the header cell at " + row + + "," + col); + } + } + + @Test + public void hideAndShowComponentsInFooter() { + openTestURL(); + GridElement grid = $(GridElement.class).first(); + + int filterRow = 0; + Assert.assertNull(getFooterElement(grid, filterRow, 1)); + Assert.assertNotNull(getFooterElement(grid, filterRow, 2)); + Assert.assertNotNull(getFooterElement(grid, filterRow, 3)); + + // Show (1,2) + grid.getFooterCell(1, 1).$(ButtonElement.class).first().click(); + + TextFieldElement textfield = getFooterElement(grid, filterRow, 1); + Assert.assertNotNull(textfield); + Assert.assertEquals("Filter: string", textfield.getValue()); + + textfield.setValue("foo"); + Assert.assertEquals("1. value change for field in string to foo", + getLogRow(0)); + } + + private TextFieldElement getFooterElement(GridElement grid, int row, int col) { + GridCellElement cell = grid.getFooterCell(row, col); + List<TextFieldElement> all = cell.$(TextFieldElement.class).all(); + if (all.size() == 0) { + return null; + } else if (all.size() == 1) { + return all.get(0); + } else { + throw new RuntimeException( + "Multiple elements found in the footer cell at " + row + + "," + col); + } + } + +} |