diff options
author | Leif Åstrand <leif@vaadin.com> | 2015-03-19 13:13:14 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2015-03-20 11:33:07 +0000 |
commit | f6a148783e898c828155aab59b97f7a52faa5129 (patch) | |
tree | e87a824ed91906884ed5ab5be08daf092739d230 | |
parent | c77b94560588320b2b0b746c17b9240f433475dc (diff) | |
download | vaadin-framework-f6a148783e898c828155aab59b97f7a52faa5129.tar.gz vaadin-framework-f6a148783e898c828155aab59b97f7a52faa5129.zip |
Restructure sidebar widget handling to work with custom content (#17023)
Change-Id: Ib24d1536af89ce97b2117d813e0f75405df7dab7
3 files changed, 211 insertions, 62 deletions
diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 174f2dde38..e9288a7ece 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -63,8 +63,8 @@ import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HasEnabled; -import com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.ResizeComposite; import com.google.gwt.user.client.ui.ToggleButton; @@ -2887,8 +2887,8 @@ public class Grid<T> extends ResizeComposite implements } /** - * Sidebar displaying toggles for hidable columns and additional custom - * widgets. + * Sidebar displaying toggles for hidable columns and custom widgets + * provided by the application. * <p> * The button for opening the sidebar is automatically visible inside the * grid, if it contains any column hiding options or custom widgets. The @@ -2903,7 +2903,7 @@ public class Grid<T> extends ResizeComposite implements @Override public void onClick(ClickEvent event) { - if (!open) { + if (!isOpen()) { open(); } else { close(); @@ -2911,77 +2911,67 @@ public class Grid<T> extends ResizeComposite implements } }; - /** - * Contains all the widgets which should be shown once the sidebar is - * opened - */ - private final List<Widget> widgets = new ArrayList<Widget>(); + private final FlowPanel rootContainer; - private final VerticalPanel rootContainer; + private final FlowPanel content; private final VButton openCloseButton; private final Grid<?> grid; - private boolean open; - - public Sidebar(Grid<?> grid) { + private Sidebar(Grid<?> grid) { this.grid = grid; - rootContainer = new VerticalPanel(); + rootContainer = new FlowPanel(); initWidget(rootContainer); openCloseButton = new VButton(); openCloseButton.addClickHandler(openCloseButtonHandler); rootContainer.add(openCloseButton); - rootContainer - .setCellHorizontalAlignment( - openCloseButton, - HorizontalAlignmentConstant - .endOf(com.google.gwt.i18n.client.HasDirection.Direction.LTR)); + + content = new FlowPanel() { + @Override + public boolean remove(Widget w) { + // Check here to catch child.removeFromParent() calls + boolean removed = super.remove(w); + if (removed) { + updateVisibility(); + } + + return removed; + } + }; } /** - * Opens the sidebar if not yet opened. - * - * @since + * Opens the sidebar if not yet opened. Opening the sidebar has no + * effect if it is empty. */ public void open() { - if (!open) { + if (!isOpen() && isInDOM()) { addStyleName("opened"); - open = true; - for (Widget w : widgets) { - rootContainer.add(w); - } + rootContainer.add(content); } } /** * Closes the sidebar if not yet closed. - * - * @since */ public void close() { - if (open) { + if (isOpen()) { removeStyleName("opened"); - open = false; - rootContainer.clear(); - rootContainer.add(openCloseButton); + content.removeFromParent(); } } /** * Returns whether the sidebar is open or not. - * <p> - * <em>Note:</em> The sidebar can be in "open state" but not actually - * visible inside grid. See {@link #isVisibleInGrid()}. * - * @since * @return <code>true</code> if open, <code>false</code> if not */ public boolean isOpen() { - return open; + return content.getParent() == rootContainer; } /** @@ -2991,11 +2981,7 @@ public class Grid<T> extends ResizeComposite implements * the widget to add or move */ public void add(Widget widget) { - widgets.remove(widget); - widgets.add(widget); - if (open) { - rootContainer.add(widget); - } + content.add(widget); updateVisibility(); } @@ -3006,11 +2992,8 @@ public class Grid<T> extends ResizeComposite implements * the widget to remove */ public void remove(Widget widget) { - widgets.remove(widget); - if (open) { - rootContainer.remove(widget); - } - updateVisibility(); + content.remove(widget); + // updateVisibility is called by remove listener } /** @@ -3018,7 +3001,7 @@ public class Grid<T> extends ResizeComposite implements * widget is already in the sidebar, then it is moved to the new index. * <p> * See - * {@link VerticalPanel#insert(com.google.gwt.user.client.ui.IsWidget, int)} + * {@link FlowPanel#insert(com.google.gwt.user.client.ui.IsWidget, int)} * for further details. * * @param widget @@ -3027,33 +3010,34 @@ public class Grid<T> extends ResizeComposite implements * 0-based index position for the widget. */ public void insert(Widget widget, int beforeIndex) { - widgets.remove(widget); - widgets.add(beforeIndex, widget); - if (open) { - // the first widget in the container is always the open button - rootContainer.insert(widget, beforeIndex + 1); - } + content.insert(widget, beforeIndex); updateVisibility(); } @Override public void setStylePrimaryName(String styleName) { super.setStylePrimaryName(styleName); + content.setStylePrimaryName(styleName + "-content"); openCloseButton.setStylePrimaryName(styleName + "-button"); } private void updateVisibility() { - final boolean hasWidgets = widgets.size() > 0; - final boolean isVisible = getParent() != null; + final boolean hasWidgets = content.getWidgetCount() > 0; + final boolean isVisible = isInDOM(); if (isVisible && !hasWidgets) { + Grid.setParent(this, null); getElement().removeFromParent(); - removeFromParent(); } else if (!isVisible && hasWidgets) { + close(); grid.getElement().appendChild(getElement()); Grid.setParent(this, grid); } } + private boolean isInDOM() { + return getParent() != null; + } + } /** @@ -3109,9 +3093,7 @@ public class Grid<T> extends ResizeComposite implements private void updatePanelVisibility() { final boolean columnHidable = getWidgetCount() > 0; - // parent for the panel might be null sidebar is not open - final boolean columnTogglesPanelIsVisible = sidebar.widgets - .contains(this); + final boolean columnTogglesPanelIsVisible = getParent() != null; if (columnHidable && !columnTogglesPanelIsVisible) { sidebar.insert(this, 0); @@ -3225,7 +3207,6 @@ public class Grid<T> extends ResizeComposite implements private boolean enabled = true; - private DetailsGenerator detailsGenerator = DetailsGenerator.NULL; private GridSpacerUpdater gridSpacerUpdater = new GridSpacerUpdater(); /** A set keeping track of the indices of all currently open details */ @@ -7246,6 +7227,30 @@ public class Grid<T> extends ResizeComposite implements widget.@com.google.gwt.user.client.ui.Widget::setParent(Lcom/google/gwt/user/client/ui/Widget;)(parent); }-*/; + private static native final void onAttach(Widget widget) + /*-{ + widget.@Widget::onAttach()(); + }-*/; + + private static native final void onDetach(Widget widget) + /*-{ + widget.@Widget::onDetach()(); + }-*/; + + @Override + protected void doAttachChildren() { + if (getSidebar().getParent() == this) { + onAttach(getSidebar()); + } + } + + @Override + protected void doDetachChildren() { + if (getSidebar().getParent() == this) { + onDetach(getSidebar()); + } + } + /** * 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/basicfeatures/client/GridSidebarContentTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridSidebarContentTest.java new file mode 100644 index 0000000000..563fe890ec --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridSidebarContentTest.java @@ -0,0 +1,105 @@ +/* + * 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.client; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest; +import com.vaadin.tests.components.grid.basicfeatures.element.CustomGridElement; + +public class GridSidebarContentTest extends GridBasicClientFeaturesTest { + + @Test + public void testSidebarWithHidableColumn() { + openTestURL(); + CustomGridElement gridElement = getGridElement(); + + Assert.assertEquals("Sidebar should not be initially present", 0, + countBySelector(".v-grid-sidebar")); + + selectMenuPath("Component", "Columns", "Column 0", "Hidable"); + + gridElement.findElement(By.className("v-grid-sidebar-button")).click(); + + WebElement toggle = gridElement.findElement(By + .className("column-hiding-toggle")); + + Assert.assertEquals("Column 0 should be togglable", "Header (0,0)", + toggle.getText()); + + selectMenuPath("Component", "Columns", "Column 0", "Hidable"); + Assert.assertEquals("Sidebar should disappear without toggable column", + 0, countBySelector(".v-grid-sidebar")); + + } + + @Test + public void testSidebarWithCustomContent() { + openTestURL(); + CustomGridElement gridElement = getGridElement(); + + Assert.assertEquals("Sidebar should not be initially present", 0, + countBySelector(".v-grid-sidebar")); + + selectMenuPath("Component", "Sidebar", "Toggle sidebar entry"); + + gridElement.findElement(By.className("v-grid-sidebar-button")).click(); + + WebElement sidebarButton = gridElement.findElement(By + .cssSelector(".v-grid-sidebar-content button")); + + Assert.assertEquals("Sidebar button", sidebarButton.getText()); + + sidebarButton.click(); + + Assert.assertEquals("Click count: 1", sidebarButton.getText()); + + selectMenuPath("Component", "Sidebar", "Toggle sidebar entry"); + + Assert.assertEquals("Sidebar should disappear after content remove", 0, + countBySelector(".v-grid-sidebar")); + } + + @Test + public void testProgrammaticSidebarToggle() { + openTestURL(); + + selectMenuPath("Component", "Sidebar", "Toggle sidebar visibility"); + + Assert.assertEquals("Toggling without content should't show anything", + 0, countBySelector(".v-grid-sidebar-content button")); + + selectMenuPath("Component", "Sidebar", "Toggle sidebar entry"); + selectMenuPath("Component", "Sidebar", "Toggle sidebar visibility"); + + Assert.assertEquals("Toggling with content should show sidebar", 1, + countBySelector(".v-grid-sidebar-content button")); + + selectMenuPath("Component", "Sidebar", "Toggle sidebar visibility"); + + Assert.assertEquals("Toggling again should hide sidebar", 0, + countBySelector(".v-grid-sidebar-content button")); + } + + private int countBySelector(String cssSelector) { + return getGridElement().findElements(By.cssSelector(cssSelector)) + .size(); + } + +} diff --git a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java index 6615cda8da..97d1a50ff6 100644 --- a/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java +++ b/uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java @@ -80,6 +80,7 @@ import com.vaadin.client.widgets.Grid.Column; import com.vaadin.client.widgets.Grid.FooterRow; import com.vaadin.client.widgets.Grid.HeaderRow; import com.vaadin.client.widgets.Grid.SelectionMode; +import com.vaadin.client.widgets.Grid.Sidebar; import com.vaadin.tests.widgetset.client.grid.GridBasicClientFeaturesWidget.Data; /** @@ -199,6 +200,17 @@ public class GridBasicClientFeaturesWidget extends private boolean secondEditorError = false; + private Button sidebarEntry = new Button("Sidebar button", + new ClickHandler() { + private int count = 0; + + @Override + public void onClick(ClickEvent event) { + count++; + sidebarEntry.setText("Click count: " + count); + } + }); + /** * Our basic data object */ @@ -408,6 +420,7 @@ public class GridBasicClientFeaturesWidget extends createInternalsMenu(); createDataSourceMenu(); createDetailsMenu(); + createSidebarMenu(); grid.getElement().getStyle().setZIndex(0); @@ -1441,6 +1454,32 @@ public class GridBasicClientFeaturesWidget extends grid.setDetailsVisible(100, visible); } }, menupath); + } + private void createSidebarMenu() { + String[] menupath = new String[] { "Component", "Sidebar" }; + + addMenuCommand("Toggle sidebar visibility", new ScheduledCommand() { + @Override + public void execute() { + Sidebar sidebar = grid.getSidebar(); + if (sidebar.isOpen()) { + sidebar.close(); + } else { + sidebar.open(); + } + } + }, menupath); + + addMenuCommand("Toggle sidebar entry", new ScheduledCommand() { + @Override + public void execute() { + if (sidebarEntry.getParent() != null) { + sidebarEntry.removeFromParent(); + } else { + grid.getSidebar().add(sidebarEntry); + } + } + }, menupath); } } |