]> source.dussan.org Git - vaadin-framework.git/commitdiff
All updates to Escalator size should get reported to LayoutManager. (#12050)
authorAnna Koskinen <Ansku@users.noreply.github.com>
Wed, 8 Jul 2020 09:42:25 +0000 (12:42 +0300)
committerGitHub <noreply@github.com>
Wed, 8 Jul 2020 09:42:25 +0000 (12:42 +0300)
Delayed size changes caused by added or removed scrollbars should be
taken into account.

client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java
client/src/main/java/com/vaadin/client/widget/grid/events/EscalatorSizeChangeHandler.java [new file with mode: 0644]
client/src/main/java/com/vaadin/client/widgets/Escalator.java
uitest/src/main/java/com/vaadin/tests/components/grid/GridSizeChange.java [new file with mode: 0644]
uitest/src/test/java/com/vaadin/tests/components/grid/GridSizeChangeTest.java [new file with mode: 0644]

index ef240e8ba43915ba311eeb058f86ee01dc6f945c..2728f74cbfcef15e1b53a0a3a51bf45efa4b9c45 100644 (file)
@@ -377,6 +377,15 @@ public class GridConnector extends AbstractListingConnector
             getLayoutManager().layoutNow();
         });
 
+        // Handling Escalator size changes
+        grid.getEscalator().addEscalatorSizeChangeHandler(event -> {
+            getLayoutManager().setNeedsMeasure(GridConnector.this);
+            if (!getConnection().getMessageHandler().isUpdatingState()
+                    && !getLayoutManager().isLayoutRunning()) {
+                getLayoutManager().layoutNow();
+            }
+        });
+
         /* Item click events */
         grid.addBodyClickHandler(itemClickHandler);
         grid.addBodyDoubleClickHandler(itemClickHandler);
diff --git a/client/src/main/java/com/vaadin/client/widget/grid/events/EscalatorSizeChangeHandler.java b/client/src/main/java/com/vaadin/client/widget/grid/events/EscalatorSizeChangeHandler.java
new file mode 100644 (file)
index 0000000..6bce817
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2018 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.widget.grid.events;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.GwtEvent;
+
+/**
+ * FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME!
+ * <p>
+ * Event handler that gets notified when the size of the Escalator changes.
+ *
+ * @author Vaadin Ltd
+ */
+public interface EscalatorSizeChangeHandler extends EventHandler {
+
+    /**
+     * FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME!
+     * <p>
+     * Called when the size of the Escalator changes.
+     *
+     * @param event
+     *            the row visibility change event describing the change
+     */
+    void onEscalatorSizeChange(EscalatorSizeChangeEvent event);
+
+    /**
+     * FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME!
+     * <p>
+     * Event fired when the Escalator size changes.
+     *
+     * @author Vaadin Ltd
+     */
+    public class EscalatorSizeChangeEvent
+            extends GwtEvent<EscalatorSizeChangeHandler> {
+        /**
+         * FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME!
+         * <p>
+         * The type of this event.
+         */
+        public static final Type<EscalatorSizeChangeHandler> TYPE = new Type<>();
+
+        /**
+         * FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME!
+         * <p>
+         * Creates a new Escalator size change event.
+         *
+         */
+        public EscalatorSizeChangeEvent() {
+            // NOP
+        }
+
+        /*
+         * (non-Javadoc)
+         *
+         * @see com.google.gwt.event.shared.GwtEvent#getAssociatedType()
+         */
+        @Override
+        public Type<EscalatorSizeChangeHandler> getAssociatedType() {
+            return TYPE;
+        }
+
+        /*
+         * (non-Javadoc)
+         *
+         * @see
+         * com.google.gwt.event.shared.GwtEvent#dispatch(com.google.gwt.event.
+         * shared .EventHandler)
+         */
+        @Override
+        protected void dispatch(EscalatorSizeChangeHandler handler) {
+            handler.onEscalatorSizeChange(this);
+        }
+    }
+}
\ No newline at end of file
index b4427b2df13c2ba584bfa55ffec003955e211898..2eab5d99c4dc221bde37c2e3a38f0e731b0ce080 100644 (file)
@@ -94,6 +94,8 @@ import com.vaadin.client.widget.escalator.SpacerUpdater;
 import com.vaadin.client.widget.escalator.events.RowHeightChangedEvent;
 import com.vaadin.client.widget.escalator.events.SpacerIndexChangedEvent;
 import com.vaadin.client.widget.escalator.events.SpacerVisibilityChangedEvent;
+import com.vaadin.client.widget.grid.events.EscalatorSizeChangeHandler;
+import com.vaadin.client.widget.grid.events.EscalatorSizeChangeHandler.EscalatorSizeChangeEvent;
 import com.vaadin.client.widget.grid.events.ScrollEvent;
 import com.vaadin.client.widget.grid.events.ScrollHandler;
 import com.vaadin.client.widgets.Escalator.JsniUtil.TouchHandlerBundle;
@@ -7513,10 +7515,17 @@ public class Escalator extends Widget
 
     @Override
     public void setWidth(final String width) {
+        String oldWidth = getElement().getStyle().getProperty("width");
         if (width != null && !width.isEmpty()) {
             super.setWidth(width);
+            if (!width.equals(oldWidth)) {
+                fireEscalatorSizeChangeEvent();
+            }
         } else {
             super.setWidth(DEFAULT_WIDTH);
+            if (!DEFAULT_WIDTH.equals(oldWidth)) {
+                fireEscalatorSizeChangeEvent();
+            }
         }
 
         recalculateElementSizes();
@@ -7558,7 +7567,11 @@ public class Escalator extends Widget
         final int escalatorRowsBefore = body.visualRowOrder.size();
 
         if (height != null && !height.isEmpty()) {
+            String oldHeight = getElement().getStyle().getProperty("height");
             super.setHeight(height);
+            if (!height.equals(oldHeight)) {
+                fireEscalatorSizeChangeEvent();
+            }
         } else {
             if (getHeightMode() == HeightMode.UNDEFINED) {
                 int newHeightByRows = body.getRowCount();
@@ -7568,7 +7581,12 @@ public class Escalator extends Widget
                 }
                 return;
             } else {
+                String oldHeight = getElement().getStyle()
+                        .getProperty("height");
                 super.setHeight(DEFAULT_HEIGHT);
+                if (!DEFAULT_HEIGHT.equals(oldHeight)) {
+                    fireEscalatorSizeChangeEvent();
+                }
             }
         }
 
@@ -7855,6 +7873,25 @@ public class Escalator extends Widget
         return array;
     }
 
+    /**
+     * FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME!
+     * <p>
+     * Adds an event handler that gets notified when the Escalator size changes.
+     *
+     * @param escalatorSizeChangeHandler
+     *            the event handler
+     * @return a handler registration for the added handler
+     */
+    public HandlerRegistration addEscalatorSizeChangeHandler(
+            EscalatorSizeChangeHandler escalatorSizeChangeHandler) {
+        return addHandler(escalatorSizeChangeHandler,
+                EscalatorSizeChangeEvent.TYPE);
+    }
+
+    private void fireEscalatorSizeChangeEvent() {
+        fireEvent(new EscalatorSizeChangeEvent());
+    }
+
     /**
      * Adds an event handler that gets notified when the range of visible rows
      * changes e.g. because of scrolling, row resizing or spacers
diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/GridSizeChange.java b/uitest/src/main/java/com/vaadin/tests/components/grid/GridSizeChange.java
new file mode 100644 (file)
index 0000000..a446e47
--- /dev/null
@@ -0,0 +1,109 @@
+package com.vaadin.tests.components.grid;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.data.provider.DataProvider;
+import com.vaadin.data.provider.ListDataProvider;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.grid.HeightMode;
+import com.vaadin.tests.components.AbstractReindeerTestUI;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.VerticalLayout;
+
+@Widgetset("com.vaadin.DefaultWidgetSet")
+public class GridSizeChange extends AbstractReindeerTestUI {
+
+    private Grid<Integer> grid;
+    private List<Integer> data;
+    private ListDataProvider<Integer> dataProvider;
+    private int counter = 0;
+
+    @Override
+    protected void setup(VaadinRequest request) {
+        grid = new Grid<>();
+        data = new ArrayList<>();
+        for (int i = 0; i < 10; ++i) {
+            data.add(i);
+            ++counter;
+        }
+
+        dataProvider = DataProvider.ofCollection(data);
+        grid.setDataProvider(dataProvider);
+
+        // create column and fill rows
+        grid.addColumn(item -> "row_" + item).setCaption("Item");
+
+        // set height mode and height
+        grid.setHeightMode(HeightMode.ROW);
+        grid.setHeightByRows(10);
+        grid.setWidth(90, Unit.PIXELS);
+
+        // create a tabsheet with one tab and place grid inside
+        VerticalLayout tab = new VerticalLayout();
+        tab.setSpacing(false);
+        tab.setMargin(false);
+        TabSheet tabSheet = new TabSheet();
+        tabSheet.setWidthUndefined();
+        tabSheet.addTab(tab, "Tab");
+        tab.addComponent(grid);
+
+        GridLayout layout = new GridLayout(3, 2);
+        layout.setDefaultComponentAlignment(Alignment.TOP_CENTER);
+
+        layout.addComponent(new Button("Reduce height", e -> {
+            double newHeight = grid.getHeightByRows() - 1;
+            grid.setHeightByRows(newHeight);
+        }));
+
+        layout.addComponent(new Button("Remove row", e -> {
+            removeRow();
+            dataProvider.refreshAll();
+        }));
+
+        layout.addComponent(new Button("Reduce width", e -> {
+            grid.setWidth(grid.getWidth() - 30, Unit.PIXELS);
+        }));
+
+        layout.addComponent(new Button("Increase height", e -> {
+            double newHeight = grid.getHeightByRows() + 1;
+            grid.setHeightByRows(newHeight);
+        }));
+
+        layout.addComponent(new Button("Add row", e -> {
+            addRow();
+            dataProvider.refreshAll();
+        }));
+
+        layout.addComponent(new Button("Increase width", e -> {
+            grid.setWidth(grid.getWidth() + 30, Unit.PIXELS);
+        }));
+
+        addComponent(tabSheet);
+        addComponent(layout);
+
+        getLayout().setSpacing(true);
+    }
+
+    private void removeRow() {
+        data.remove(0);
+        dataProvider.refreshAll();
+    }
+
+    private void addRow() {
+        ++counter;
+        data.add(counter);
+        dataProvider.refreshAll();
+    }
+
+    @Override
+    protected String getTestDescription() {
+        return "Changing Grid size should resize the TabSheet accordingly "
+                + "even if scrollbar(s) appear or disappear.";
+    }
+}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/GridSizeChangeTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/GridSizeChangeTest.java
new file mode 100644 (file)
index 0000000..3b8e485
--- /dev/null
@@ -0,0 +1,95 @@
+package com.vaadin.tests.components.grid;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.number.IsCloseTo.closeTo;
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.GridElement;
+import com.vaadin.testbench.elements.TabSheetElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class GridSizeChangeTest extends MultiBrowserTest {
+
+    private TabSheetElement tabSheet;
+    private GridElement grid;
+    private WebElement vScrollbar;
+    private WebElement hScrollbar;
+
+    @Test
+    public void scrollbarsTakenIntoAccountInSizeChanges() {
+        openTestURL();
+        tabSheet = $(TabSheetElement.class).first();
+        grid = $(GridElement.class).first();
+
+        vScrollbar = grid.findElement(By.className("v-grid-scroller-vertical"));
+        hScrollbar = grid
+                .findElement(By.className("v-grid-scroller-horizontal"));
+
+        // ensure no initial scrollbars
+        ensureVerticalScrollbar(false);
+        ensureHorizontalScrollbar(false);
+
+        assertGridWithinTabSheet();
+
+        $(ButtonElement.class).caption("Reduce height").first().click();
+        // more rows than height -> scrollbar
+
+        assertGridWithinTabSheet();
+        ensureVerticalScrollbar(true);
+
+        $(ButtonElement.class).caption("Remove row").first().click();
+        // height matches rows -> no scrollbar
+
+        assertGridWithinTabSheet();
+        ensureVerticalScrollbar(false);
+
+        $(ButtonElement.class).caption("Reduce width").first().click();
+        // column too wide -> scrollbar
+
+        assertGridWithinTabSheet();
+        ensureHorizontalScrollbar(true);
+
+        $(ButtonElement.class).caption("Increase width").first().click();
+        // column fits -> no scrollbar
+
+        assertGridWithinTabSheet();
+        ensureHorizontalScrollbar(false);
+
+        $(ButtonElement.class).caption("Add row").first().click();
+        // more rows than height -> scrollbar
+
+        assertGridWithinTabSheet();
+        ensureVerticalScrollbar(true);
+
+        $(ButtonElement.class).caption("Increase height").first().click();
+        // height matches rows -> no scrollbar
+
+        assertGridWithinTabSheet();
+        ensureVerticalScrollbar(false);
+    }
+
+    private void ensureVerticalScrollbar(boolean displayed) {
+        assertEquals(displayed ? "block" : "none",
+                vScrollbar.getCssValue("display"));
+    }
+
+    private void ensureHorizontalScrollbar(boolean displayed) {
+        assertEquals(displayed ? "block" : "none",
+                hScrollbar.getCssValue("display"));
+    }
+
+    private void assertGridWithinTabSheet() throws AssertionError {
+        // allow two pixel leeway
+        assertThat(
+                "Grid and TabSheet should always have the same bottom position, "
+                        + "not be offset by a scrollbar's thickness",
+                (double) grid.getLocation().getY() + grid.getSize().getHeight(),
+                closeTo(tabSheet.getLocation().getY()
+                        + tabSheet.getSize().getHeight(), 2));
+    }
+}