]> source.dussan.org Git - vaadin-framework.git/commitdiff
Reintroduce grid column hiding
authorAleksi Hietanen <aleksi@vaadin.com>
Mon, 19 Sep 2016 14:01:20 +0000 (17:01 +0300)
committerDenis Anisimov <denis@vaadin.com>
Tue, 20 Sep 2016 11:23:53 +0000 (11:23 +0000)
Change-Id: I8a0344dffe3f2ef84f8134e05d9b7340d9b603a0

client/src/main/java/com/vaadin/client/connectors/grid/ColumnConnector.java
client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java
server/src/main/java/com/vaadin/ui/Grid.java
shared/src/main/java/com/vaadin/shared/ui/grid/ColumnState.java
shared/src/main/java/com/vaadin/shared/ui/grid/GridServerRpc.java
uitest/src/main/java/com/vaadin/tests/components/grid/GridColumnHiding.java [new file with mode: 0644]
uitest/src/test/java/com/vaadin/tests/components/grid/GridColumnHidingTest.java [new file with mode: 0644]

index 3805e01370453cdab00b657e87354d0db91cf727..d88a50b7e56bb78b4cd704f374f7eecbddaaf58f 100644 (file)
@@ -80,6 +80,21 @@ public class ColumnConnector extends AbstractExtensionConnector {
         column.setSortable(getState().sortable);
     }
 
+    @OnStateChange("hidingToggleCaption")
+    void updateHidingToggleCaption() {
+        column.setHidingToggleCaption(getState().hidingToggleCaption);
+    }
+
+    @OnStateChange("hidden")
+    void updateHidden() {
+        column.setHidden(getState().hidden);
+    }
+
+    @OnStateChange("hidable")
+    void updateHidable() {
+        column.setHidable(getState().hidable);
+    }
+
     @Override
     public void onUnregister() {
         super.onUnregister();
index 58a5ea8262e3c7acb5d16df2a1920801fae45680..fd31622cfeafdd85b79928ccfc33eb37f2f4d4e6 100644 (file)
@@ -157,6 +157,13 @@ public class GridConnector
             return null;
         });
 
+        getWidget().addColumnVisibilityChangeHandler(event -> {
+            if (event.isUserOriginated()) {
+                getRpcProxy(GridServerRpc.class).columnVisibilityChanged(
+                        getColumnId(event.getColumn()), event.isHidden());
+            }
+        });
+
         /* Item click events */
         getWidget().addBodyClickHandler(itemClickHandler);
         getWidget().addBodyDoubleClickHandler(itemClickHandler);
index 806f0d270fb3b410e1e90b859d38bd9d6fbc9302..b77e2ca7f712d7d723a895e7481249def5745c87 100644 (file)
@@ -73,6 +73,12 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
     private static final Method ITEM_CLICK_METHOD = ReflectTools
             .findMethod(ItemClickListener.class, "accept", ItemClick.class);
 
+    @Deprecated
+    private static final Method COLUMN_VISIBILITY_METHOD = ReflectTools
+            .findMethod(ColumnVisibilityChangeListener.class,
+                    "columnVisibilityChanged",
+                    ColumnVisibilityChangeEvent.class);
+
     /**
      * An event fired when an item in the Grid has been clicked.
      *
@@ -242,6 +248,85 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
         }
     }
 
+    /**
+     * An event listener for column visibility change events in the Grid.
+     *
+     * @since 7.5.0
+     */
+    public interface ColumnVisibilityChangeListener extends Serializable {
+
+        /**
+         * Called when a column has become hidden or unhidden.
+         *
+         * @param event
+         */
+        void columnVisibilityChanged(ColumnVisibilityChangeEvent event);
+    }
+
+    /**
+     * An event that is fired when a column's visibility changes.
+     *
+     * @since 7.5.0
+     */
+    public static class ColumnVisibilityChangeEvent extends Component.Event {
+
+        private final Column<?, ?> column;
+        private final boolean userOriginated;
+        private final boolean hidden;
+
+        /**
+         * Constructor for a column visibility change event.
+         *
+         * @param source
+         *            the grid from which this event originates
+         * @param column
+         *            the column that changed its visibility
+         * @param hidden
+         *            <code>true</code> if the column was hidden,
+         *            <code>false</code> if it became visible
+         * @param isUserOriginated
+         *            <code>true</code> iff the event was triggered by an UI
+         *            interaction
+         */
+        public ColumnVisibilityChangeEvent(Grid<?> source, Column<?, ?> column,
+                boolean hidden, boolean isUserOriginated) {
+            super(source);
+            this.column = column;
+            this.hidden = hidden;
+            userOriginated = isUserOriginated;
+        }
+
+        /**
+         * Gets the column that became hidden or visible.
+         *
+         * @return the column that became hidden or visible.
+         * @see Column#isHidden()
+         */
+        public Column<?, ?> getColumn() {
+            return column;
+        }
+
+        /**
+         * Was the column set hidden or visible.
+         *
+         * @return <code>true</code> if the column was hidden <code>false</code>
+         *         if it was set visible
+         */
+        public boolean isHidden() {
+            return hidden;
+        }
+
+        /**
+         * Returns <code>true</code> if the column reorder was done by the user,
+         * <code>false</code> if not and it was triggered by server side code.
+         *
+         * @return <code>true</code> if event is a result of user interaction
+         */
+        public boolean isUserOriginated() {
+            return userOriginated;
+        }
+    }
+
     /**
      * A callback interface for generating description texts for an item.
      *
@@ -370,9 +455,13 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
         }
 
         @Override
-        public void columnVisibilityChanged(String id, boolean hidden,
-                boolean userOriginated) {
-            // TODO Auto-generated method stub
+        public void columnVisibilityChanged(String id, boolean hidden) {
+            Column<T, ?> column = getColumn(id);
+            ColumnState columnState = column.getState(false);
+            if (columnState.hidden != hidden) {
+                columnState.hidden = hidden;
+                fireColumnVisibilityChangeEvent(column, hidden, true);
+            }
         }
 
         @Override
@@ -852,6 +941,119 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
         public DescriptionGenerator<T> getDescriptionGenerator() {
             return descriptionGenerator;
         }
+
+        /**
+         * Sets the caption of the hiding toggle for this column. Shown in the
+         * toggle for this column in the grid's sidebar when the column is
+         * {@link #isHidable() hidable}.
+         * <p>
+         * The default value is <code>null</code>, and in that case the column's
+         * {@link #getHeaderCaption() header caption} is used.
+         * <p>
+         * <em>NOTE:</em> setting this to empty string might cause the hiding
+         * toggle to not render correctly.
+         *
+         * @since 7.5.0
+         * @param hidingToggleCaption
+         *            the text to show in the column hiding toggle
+         * @return the column itself
+         */
+        public Column<T, V> setHidingToggleCaption(String hidingToggleCaption) {
+            if (hidingToggleCaption != getHidingToggleCaption()) {
+                getState().hidingToggleCaption = hidingToggleCaption;
+            }
+            return this;
+        }
+
+        /**
+         * Gets the caption of the hiding toggle for this column.
+         *
+         * @since 7.5.0
+         * @see #setHidingToggleCaption(String)
+         * @return the caption for the hiding toggle for this column
+         */
+        public String getHidingToggleCaption() {
+            return getState(false).hidingToggleCaption;
+        }
+
+        /**
+         * Hides or shows the column. By default columns are visible before
+         * explicitly hiding them.
+         *
+         * @since 7.5.0
+         * @param hidden
+         *            <code>true</code> to hide the column, <code>false</code>
+         *            to show
+         * @return this column
+         * @throws IllegalStateException
+         *             if the column is no longer attached to any grid
+         */
+        public Column<T, V> setHidden(boolean hidden) {
+            checkColumnIsAttached();
+            if (hidden != isHidden()) {
+                getState().hidden = hidden;
+                getParent().fireColumnVisibilityChangeEvent(this, hidden,
+                        false);
+            }
+            return this;
+        }
+
+        /**
+         * Returns whether this column is hidden. Default is {@code false}.
+         *
+         * @since 7.5.0
+         * @return <code>true</code> if the column is currently hidden,
+         *         <code>false</code> otherwise
+         */
+        public boolean isHidden() {
+            return getState(false).hidden;
+        }
+
+        /**
+         * Sets whether this column can be hidden by the user. Hidable columns
+         * can be hidden and shown via the sidebar menu.
+         *
+         * @since 7.5.0
+         * @param hidable
+         *            <code>true</code> iff the column may be hidable by the
+         *            user via UI interaction
+         * @return this column
+         */
+        public Column<T, V> setHidable(boolean hidable) {
+            if (hidable != isHidable()) {
+                getState().hidable = hidable;
+            }
+            return this;
+        }
+
+        /**
+         * Returns whether this column can be hidden by the user. Default is
+         * {@code false}.
+         * <p>
+         * <em>Note:</em> the column can be programmatically hidden using
+         * {@link #setHidden(boolean)} regardless of the returned value.
+         *
+         * @since 7.5.0
+         * @return <code>true</code> if the user can hide the column,
+         *         <code>false</code> if not
+         */
+        public boolean isHidable() {
+            return getState(false).hidable;
+        }
+
+        /**
+         * Checks whether this column is attached and throws an
+         * {@link IllegalStateException} if it is not.
+         *
+         * @throws IllegalStateException
+         *             if the column is no longer attached to any grid
+         */
+        protected void checkColumnIsAttached() throws IllegalStateException {
+            if (getParent() == null) {
+                throw new IllegalStateException(
+                        "Column is no longer attached to a grid.");
+            }
+        }
     }
 
     private final class SingleSelection extends AbstractSingleSelection {
@@ -923,6 +1125,12 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
         });
     }
 
+    public <V> void fireColumnVisibilityChangeEvent(Column<T, V> column,
+            boolean hidden, boolean userOriginated) {
+        fireEvent(new ColumnVisibilityChangeEvent(this, column, hidden,
+                userOriginated));
+    }
+
     /**
      * Adds a new column to this {@link Grid} with given header caption, typed
      * renderer and value provider.
@@ -1256,6 +1464,22 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents {
         return () -> removeListener(ItemClick.class, listener);
     }
 
+    /**
+     * Registers a new column visibility change listener
+     *
+     * @param listener
+     *            the listener to register, not null
+     * @return a registration for the listener
+     */
+    public Registration addColumnVisibilityChangeListener(
+            ColumnVisibilityChangeListener listener) {
+        Objects.requireNonNull(listener, "listener cannot be null");
+        addListener(ColumnVisibilityChangeEvent.class, listener,
+                COLUMN_VISIBILITY_METHOD);
+        return () -> removeListener(ColumnVisibilityChangeEvent.class, listener,
+                COLUMN_VISIBILITY_METHOD);
+    }
+
     @Override
     protected GridState getState() {
         return getState(true);
index 63a93cac1561a61fc022fd6c0312ca9e916f465c..c789988cb588be84a000e5fa26da3e57d853c082 100644 (file)
@@ -24,5 +24,14 @@ public class ColumnState extends SharedState {
     public String id;
     public boolean sortable;
 
+    /** The caption for the column hiding toggle. */
+    public String hidingToggleCaption;
+
+    /** Whether this column is currently hidden. */
+    public boolean hidden = false;
+
+    /** Whether the column can be hidden by the user. */
+    public boolean hidable = false;
+
     public Connector renderer;
 }
index 7c9eb42b2c9d31cd09033e28f7ae5a14d644e1c1..08417b4b3385fb4a8158e20dc8bb0e843e37fb8f 100644 (file)
@@ -83,12 +83,8 @@ public interface GridServerRpc extends ServerRpc {
      *            the id of the column
      * @param hidden
      *            <code>true</code> if hidden, <code>false</code> if unhidden
-     * @param userOriginated
-     *            <code>true</code> if triggered by user, <code>false</code> if
-     *            by code
      */
-    void columnVisibilityChanged(String id, boolean hidden,
-            boolean userOriginated);
+    void columnVisibilityChanged(String id, boolean hidden);
 
     /**
      * Informs the server that a column has been resized by the user.
diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/GridColumnHiding.java b/uitest/src/main/java/com/vaadin/tests/components/grid/GridColumnHiding.java
new file mode 100644 (file)
index 0000000..7fa86b6
--- /dev/null
@@ -0,0 +1,50 @@
+package com.vaadin.tests.components.grid;
+
+import java.util.Arrays;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.tests.data.bean.Person;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.Column;
+import com.vaadin.ui.renderers.NumberRenderer;
+import com.vaadin.v7.ui.Label;
+
+public class GridColumnHiding extends AbstractTestUI {
+
+    @Override
+    protected void setup(VaadinRequest request) {
+        Grid<Person> grid = new Grid<>();
+        Column<Person, String> nameColumn = grid
+                .addColumn("Name", Person::getFirstName).setHidable(true);
+        Column<Person, Number> ageColumn = grid
+                .addColumn("Age", Person::getAge, new NumberRenderer())
+                .setHidable(true)
+                .setHidingToggleCaption("custom age column caption");
+        Column<Person, String> emailColumn = grid.addColumn("Email",
+                Person::getEmail);
+
+        Button toggleNameColumn = new Button("server side toggle name column");
+        Button toggleAgeColumn = new Button("server side toggle age column");
+        Button toggleEmailColumn = new Button(
+                "server side toggle email column");
+
+        toggleNameColumn.addClickListener(
+                event -> nameColumn.setHidden(!nameColumn.isHidden()));
+        toggleAgeColumn.addClickListener(
+                event -> ageColumn.setHidden(!ageColumn.isHidden()));
+        toggleEmailColumn.addClickListener(
+                event -> emailColumn.setHidden(!emailColumn.isHidden()));
+
+        Label visibilityChangeLabel = new Label("visibility change label");
+        grid.addColumnVisibilityChangeListener(event -> visibilityChangeLabel
+                .setValue(event.getColumn().isHidden() + ""));
+
+        grid.setItems(Arrays.asList(Person.createTestPerson1(),
+                Person.createTestPerson2()));
+
+        addComponents(grid, toggleNameColumn, toggleAgeColumn,
+                toggleEmailColumn, visibilityChangeLabel);
+    }
+}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/GridColumnHidingTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/GridColumnHidingTest.java
new file mode 100644 (file)
index 0000000..e0ec3ed
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2000-2016 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 org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.GridElement;
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.LabelElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class GridColumnHidingTest extends MultiBrowserTest {
+
+    @Test
+    public void serverHideColumns() {
+        openTestURL();
+        GridElement grid = $(GridElement.class).first();
+        ButtonElement toggleNameColumn = $(ButtonElement.class).get(0);
+        ButtonElement toggleAgeColumn = $(ButtonElement.class).get(1);
+        ButtonElement toggleEmailColumn = $(ButtonElement.class).get(2);
+
+        Assert.assertEquals("Foo", grid.getCell(0, 0).getText());
+        Assert.assertEquals("Maya", grid.getCell(1, 0).getText());
+        Assert.assertEquals("46", grid.getCell(0, 1).getText());
+        Assert.assertEquals("yeah@cool.com", grid.getCell(0, 2).getText());
+
+        toggleAgeColumn.click();
+        Assert.assertEquals("Foo", grid.getCell(0, 0).getText());
+        Assert.assertEquals("Maya", grid.getCell(1, 0).getText());
+        Assert.assertEquals("yeah@cool.com", grid.getCell(0, 1).getText());
+
+        toggleNameColumn.click();
+        Assert.assertEquals("yeah@cool.com", grid.getCell(0, 0).getText());
+
+        toggleEmailColumn.click();
+        Assert.assertFalse(isElementPresent(By.className("v-grid-cell")));
+
+        toggleAgeColumn.click();
+        toggleNameColumn.click();
+        toggleEmailColumn.click();
+        Assert.assertEquals("Foo", grid.getCell(0, 0).getText());
+        Assert.assertEquals("46", grid.getCell(0, 1).getText());
+        Assert.assertEquals("yeah@cool.com", grid.getCell(0, 2).getText());
+    }
+
+    @Test
+    public void clientHideColumns() {
+        openTestURL();
+        GridElement grid = $(GridElement.class).first();
+
+        getSidebarOpenButton(grid).click();
+        getColumnHidingToggle(grid, "custom age column caption").click();
+        Assert.assertEquals("Foo", grid.getCell(0, 0).getText());
+        Assert.assertEquals("Maya", grid.getCell(1, 0).getText());
+        Assert.assertEquals("yeah@cool.com", grid.getCell(0, 1).getText());
+        Assert.assertEquals("maya@foo.bar", grid.getCell(1, 1).getText());
+
+        getColumnHidingToggle(grid, "Name").click();
+        Assert.assertEquals("yeah@cool.com", grid.getCell(0, 0).getText());
+
+        getColumnHidingToggle(grid, "custom age column caption").click();
+        Assert.assertEquals("46", grid.getCell(0, 0).getText());
+        Assert.assertEquals("18", grid.getCell(1, 0).getText());
+        Assert.assertEquals("yeah@cool.com", grid.getCell(0, 1).getText());
+        Assert.assertEquals("maya@foo.bar", grid.getCell(1, 1).getText());
+    }
+
+    @Test
+    public void columnVisibilityChangeListener() {
+        openTestURL();
+        GridElement grid = $(GridElement.class).first();
+        LabelElement isHiddenLabel = $(LabelElement.class).get(1);
+        ButtonElement toggleNameColumn = $(ButtonElement.class).get(0);
+        ButtonElement toggleAgeColumn = $(ButtonElement.class).get(1);
+
+        Assert.assertEquals("visibility change label", isHiddenLabel.getText());
+        toggleNameColumn.click();
+        Assert.assertEquals("true", isHiddenLabel.getText());
+        toggleAgeColumn.click();
+        Assert.assertEquals("true", isHiddenLabel.getText());
+        toggleAgeColumn.click();
+        Assert.assertEquals("false", isHiddenLabel.getText());
+
+        getSidebarOpenButton(grid).click();
+        getColumnHidingToggle(grid, "Name").click();
+        Assert.assertEquals("false", isHiddenLabel.getText());
+        getColumnHidingToggle(grid, "custom age column caption").click();
+        Assert.assertEquals("true", isHiddenLabel.getText());
+        getSidebarOpenButton(grid).click();
+    }
+
+    @Test
+    public void columnTogglesVisibility() {
+        openTestURL();
+        GridElement grid = $(GridElement.class).first();
+        getSidebarOpenButton(grid).click();
+        List<WebElement> elements = getColumnHidingToggles(grid);
+        Assert.assertEquals(2, elements.size());
+        Assert.assertTrue("Name".equals(elements.get(0).getText()));
+        Assert.assertTrue(
+                "custom age column caption".equals(elements.get(1).getText()));
+    }
+
+    protected WebElement getSidebarOpenButton(GridElement grid) {
+        List<WebElement> elements = grid
+                .findElements(By.className("v-grid-sidebar-button"));
+        return elements.isEmpty() ? null : elements.get(0);
+    }
+
+    protected List<WebElement> getColumnHidingToggles(GridElement grid) {
+        WebElement sidebar = getSidebar(grid);
+        return sidebar.findElements(By.className("column-hiding-toggle"));
+    }
+
+    protected WebElement getColumnHidingToggle(GridElement grid,
+            String caption) {
+        List<WebElement> elements = getColumnHidingToggles(grid);
+        for (WebElement e : elements) {
+            if (caption.equalsIgnoreCase(e.getText())) {
+                return e;
+            }
+        }
+        return null;
+    }
+
+    protected WebElement getSidebar(GridElement grid) {
+        List<WebElement> elements = findElements(
+                By.className("v-grid-sidebar-popup"));
+        return elements.isEmpty() ? null : elements.get(0);
+    }
+}