]> source.dussan.org Git - vaadin-framework.git/commitdiff
Make it possible to disallow user selection in Grid (#8144)
authorArtur <artur@vaadin.com>
Mon, 30 Jan 2017 11:47:55 +0000 (13:47 +0200)
committerGitHub <noreply@github.com>
Mon, 30 Jan 2017 11:47:55 +0000 (13:47 +0200)
Fixes #7880

18 files changed:
client/src/main/java/com/vaadin/client/connectors/MultiSelectionModelConnector.java
client/src/main/java/com/vaadin/client/connectors/SingleSelectionModelConnector.java
client/src/main/java/com/vaadin/client/widget/grid/selection/ClickSelectHandler.java
client/src/main/java/com/vaadin/client/widget/grid/selection/HasUserSelectionAllowed.java [new file with mode: 0644]
client/src/main/java/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java
client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionModelMulti.java
client/src/main/java/com/vaadin/client/widget/grid/selection/SelectionModelSingle.java
client/src/main/java/com/vaadin/client/widget/grid/selection/SpaceSelectHandler.java
client/src/main/java/com/vaadin/client/widgets/Grid.java
documentation/components/components-grid.asciidoc
server/src/main/java/com/vaadin/ui/Grid.java
server/src/test/java/com/vaadin/tests/server/component/grid/MultiSelectionModelTest.java
server/src/test/java/com/vaadin/tests/server/component/grid/SingleSelectionModelTest.java
server/src/test/java/com/vaadin/ui/ComponentTest.java [new file with mode: 0644]
shared/src/main/java/com/vaadin/shared/ui/grid/selection/MultiSelectionModelState.java
shared/src/main/java/com/vaadin/shared/ui/grid/selection/SingleSelectionModelState.java
uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
uitest/src/test/java/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java

index 748e9b1acfadf456f8be30d0b085ae8e99903e5c..5c0a84bd5f7285589da394a6e841e5501def71ec 100644 (file)
@@ -22,6 +22,7 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.logging.Logger;
 
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.user.client.ui.CheckBox;
@@ -35,12 +36,15 @@ import com.vaadin.client.widget.grid.DataAvailableEvent;
 import com.vaadin.client.widget.grid.DataAvailableHandler;
 import com.vaadin.client.widget.grid.events.SelectAllEvent;
 import com.vaadin.client.widget.grid.events.SelectAllHandler;
+import com.vaadin.client.widget.grid.selection.HasUserSelectionAllowed;
 import com.vaadin.client.widget.grid.selection.MultiSelectionRenderer;
 import com.vaadin.client.widget.grid.selection.SelectionModel;
 import com.vaadin.client.widget.grid.selection.SelectionModel.Multi;
 import com.vaadin.client.widget.grid.selection.SpaceSelectHandler;
 import com.vaadin.client.widgets.Grid;
+import com.vaadin.client.widgets.Grid.Column;
 import com.vaadin.client.widgets.Grid.HeaderCell;
+import com.vaadin.client.widgets.Grid.SelectionColumn;
 import com.vaadin.shared.ui.Connect;
 import com.vaadin.shared.ui.grid.GridState;
 import com.vaadin.shared.ui.grid.Range;
@@ -94,8 +98,30 @@ public class MultiSelectionModelConnector extends
         }
     }
 
+    @OnStateChange("userSelectionAllowed")
+    void updateUserSelectionAllowed() {
+        if (selectionModel instanceof HasUserSelectionAllowed) {
+            ((HasUserSelectionAllowed) selectionModel)
+                    .setUserSelectionAllowed(getState().userSelectionAllowed);
+        } else {
+            getLogger().warning("userSelectionAllowed set to "
+                    + getState().userSelectionAllowed
+                    + " but the selection model does not implement "
+                    + HasUserSelectionAllowed.class.getSimpleName());
+        }
+    }
+
+    private static Logger getLogger() {
+        return Logger.getLogger(MultiSelectionModelConnector.class.getName());
+    }
+
+    /**
+     * The default multi selection model used for this connector.
+     *
+     */
     protected class MultiSelectionModel extends AbstractSelectionModel
-            implements SelectionModel.Multi.Batched<JsonObject> {
+            implements SelectionModel.Multi.Batched<JsonObject>,
+            HasUserSelectionAllowed<JsonObject> {
 
         private ComplexRenderer<Boolean> renderer = null;
         private Set<RowHandle<JsonObject>> selected = new HashSet<RowHandle<JsonObject>>();
@@ -104,6 +130,7 @@ public class MultiSelectionModelConnector extends
         private HandlerRegistration dataAvailable;
         private Range availableRows;
         private boolean batchSelect = false;
+        private boolean userSelectionAllowed = true;
 
         @Override
         public void setGrid(Grid<JsonObject> grid) {
@@ -382,5 +409,21 @@ public class MultiSelectionModelConnector extends
         public Collection<JsonObject> getDeselectedRowsBatch() {
             return Collections.unmodifiableSet(getRows(deselected));
         }
+
+        @Override
+        public boolean isUserSelectionAllowed() {
+            return userSelectionAllowed;
+        }
+
+        @Override
+        public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+            this.userSelectionAllowed = userSelectionAllowed;
+            for (Column<?, ?> c : getGrid().getColumns()) {
+                if (c instanceof SelectionColumn) {
+                    ((SelectionColumn) c)
+                            .setUserSelectionAllowed(userSelectionAllowed);
+                }
+            }
+        }
     }
 }
index 55c1eddf6137c9716fd7004b4cadee9b2669148f..7cd30e40ef23759fef568b0c3d3866a7f3e898f7 100644 (file)
  */
 package com.vaadin.client.connectors;
 
+import java.util.logging.Logger;
+
 import com.vaadin.client.ServerConnector;
 import com.vaadin.client.annotations.OnStateChange;
 import com.vaadin.client.data.DataSource.RowHandle;
 import com.vaadin.client.renderers.Renderer;
 import com.vaadin.client.widget.grid.selection.ClickSelectHandler;
+import com.vaadin.client.widget.grid.selection.HasUserSelectionAllowed;
 import com.vaadin.client.widget.grid.selection.SelectionModel;
 import com.vaadin.client.widget.grid.selection.SelectionModel.Single;
 import com.vaadin.client.widget.grid.selection.SpaceSelectHandler;
@@ -75,14 +78,34 @@ public class SingleSelectionModelConnector extends
         selectionModel.setDeselectAllowed(getState().deselectAllowed);
     }
 
+    @OnStateChange("userSelectionAllowed")
+    void updateUserSelectionAllowed() {
+
+        if (selectionModel instanceof HasUserSelectionAllowed) {
+            ((HasUserSelectionAllowed) selectionModel)
+                    .setUserSelectionAllowed(getState().userSelectionAllowed);
+        } else {
+            getLogger().warning("userSelectionAllowed set to "
+                    + getState().userSelectionAllowed
+                    + " but the selection model does not implement "
+                    + HasUserSelectionAllowed.class.getSimpleName());
+        }
+    }
+
+    private static Logger getLogger() {
+        return Logger.getLogger(SingleSelectionModelConnector.class.getName());
+    }
+
     /**
      * SingleSelectionModel without a selection column renderer.
      */
     public class SingleSelectionModel extends AbstractSelectionModel
-            implements SelectionModel.Single<JsonObject> {
+            implements SelectionModel.Single<JsonObject>,
+            HasUserSelectionAllowed<JsonObject> {
 
         private RowHandle<JsonObject> selectedRow;
         private boolean deselectAllowed;
+        private boolean userSelectionAllowed = true;
 
         @Override
         public Renderer<Boolean> getSelectionColumnRenderer() {
@@ -182,5 +205,16 @@ public class SingleSelectionModelConnector extends
         public boolean isDeselectAllowed() {
             return deselectAllowed;
         }
+
+        @Override
+        public boolean isUserSelectionAllowed() {
+            return userSelectionAllowed;
+        }
+
+        @Override
+        public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+            this.userSelectionAllowed = userSelectionAllowed;
+        }
+
     }
 }
\ No newline at end of file
index e7be08f141fecbd62dbcc14134f8544fe30ada9f..7ace1eb4a49aa1454bce42e15bb404b2dd2c1eb1 100644 (file)
@@ -36,6 +36,10 @@ public class ClickSelectHandler<T> {
 
         @Override
         public void onClick(GridClickEvent event) {
+            if (!grid.isUserSelectionAllowed()) {
+                return;
+            }
+
             T row = (T) event.getTargetCell().getRow();
             if (!grid.isSelected(row)) {
                 grid.select(row);
diff --git a/client/src/main/java/com/vaadin/client/widget/grid/selection/HasUserSelectionAllowed.java b/client/src/main/java/com/vaadin/client/widget/grid/selection/HasUserSelectionAllowed.java
new file mode 100644 (file)
index 0000000..de4eda3
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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.client.widget.grid.selection;
+
+/**
+ * Interface implemented by selection models which support disabling client side
+ * selection while still allowing programmatic selection on the server.
+ *
+ * @param <T>
+ *            Grid's row type
+ */
+public interface HasUserSelectionAllowed<T> extends SelectionModel<T> {
+
+    /**
+     * Checks if the user is allowed to change the selection.
+     * 
+     * @return <code>true</code> if the user is allowed to change the selection,
+     *         <code>false</code> otherwise
+     */
+    public boolean isUserSelectionAllowed();
+
+    /**
+     * Sets whether the user is allowed to change the selection.
+     * 
+     * @param userSelectionAllowed
+     *            <code>true</code> if the user is allowed to change the
+     *            selection, <code>false</code> otherwise
+     */
+    public void setUserSelectionAllowed(boolean userSelectionAllowed);
+
+}
index b27a4a2eedbb26f6291523ffe8595433ff050a4b..9c8f60c0cdd95a84490f4d75b6a5fa274bd4b511 100644 (file)
@@ -632,7 +632,8 @@ public class MultiSelectionRenderer<T>
     public void render(final RendererCellReference cell, final Boolean data,
             CheckBox checkBox) {
         checkBox.setValue(data, false);
-        checkBox.setEnabled(grid.isEnabled() && !grid.isEditorActive());
+        checkBox.setEnabled(grid.isEnabled() && !grid.isEditorActive()
+                && grid.isUserSelectionAllowed());
     }
 
     @Override
@@ -770,6 +771,9 @@ public class MultiSelectionRenderer<T>
     }
 
     protected void setSelected(final int logicalRow, final boolean select) {
+        if (!grid.isUserSelectionAllowed()) {
+            return;
+        }
         T row = grid.getDataSource().getRow(logicalRow);
         if (select) {
             grid.select(row);
index 00c115c5c23b1287fe2543d5ecdf97ebb5b8729a..7874e03006d31ce742c191dc590f778cb9feca08 100644 (file)
@@ -33,7 +33,7 @@ import com.vaadin.client.widgets.Grid;
  * @since 7.4
  */
 public class SelectionModelMulti<T> extends AbstractRowHandleSelectionModel<T>
-        implements SelectionModel.Multi.Batched<T> {
+        implements SelectionModel.Multi.Batched<T>, HasUserSelectionAllowed<T> {
 
     private final LinkedHashSet<RowHandle<T>> selectedRows;
     private Renderer<Boolean> renderer;
@@ -45,6 +45,7 @@ public class SelectionModelMulti<T> extends AbstractRowHandleSelectionModel<T>
 
     /* Event handling for selection with space key */
     private SpaceSelectHandler<T> spaceSelectHandler;
+    private boolean userSelectionAllowed = true;
 
     public SelectionModelMulti() {
         grid = null;
@@ -270,4 +271,14 @@ public class SelectionModelMulti<T> extends AbstractRowHandleSelectionModel<T>
         }
         return rows;
     }
+
+    @Override
+    public boolean isUserSelectionAllowed() {
+        return userSelectionAllowed;
+    }
+
+    @Override
+    public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+        this.userSelectionAllowed = userSelectionAllowed;
+    }
 }
index f3df8926233f49112c619b6d684086febe522aec..217682bcd183fdc5e1055a36d0aa7ad3048a6f03 100644 (file)
@@ -29,7 +29,7 @@ import com.vaadin.client.widgets.Grid;
  * @since 7.4
  */
 public class SelectionModelSingle<T> extends AbstractRowHandleSelectionModel<T>
-        implements SelectionModel.Single<T> {
+        implements SelectionModel.Single<T>, HasUserSelectionAllowed<T> {
 
     private Grid<T> grid;
     private RowHandle<T> selectedRow;
@@ -41,6 +41,7 @@ public class SelectionModelSingle<T> extends AbstractRowHandleSelectionModel<T>
     private ClickSelectHandler<T> clickSelectHandler;
 
     private boolean deselectAllowed = true;
+    private boolean userSelectionAllowed = true;
 
     @Override
     public boolean isSelected(T row) {
@@ -172,4 +173,14 @@ public class SelectionModelSingle<T> extends AbstractRowHandleSelectionModel<T>
         }
     }
 
+    @Override
+    public boolean isUserSelectionAllowed() {
+        return userSelectionAllowed;
+    }
+
+    @Override
+    public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+        this.userSelectionAllowed = userSelectionAllowed;
+    }
+
 }
index 456f08c5b34f0fa16c0d504e15855ed28b215b15..476f3428389bdbee53dc04fca6e186e8c15be13c 100644 (file)
@@ -44,6 +44,10 @@ public class SpaceSelectHandler<T> {
 
         @Override
         public void onKeyDown(GridKeyDownEvent event) {
+            if (!grid.isUserSelectionAllowed()) {
+                return;
+            }
+
             if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE || spaceDown) {
                 return;
             }
index f796529aa786bea779c07716eadb31f93153c654..d215b3c565e1a347f97d80df328b11da4f097282 100755 (executable)
@@ -158,6 +158,7 @@ import com.vaadin.client.widget.grid.events.ScrollHandler;
 import com.vaadin.client.widget.grid.events.SelectAllEvent;
 import com.vaadin.client.widget.grid.events.SelectAllHandler;
 import com.vaadin.client.widget.grid.selection.HasSelectionHandlers;
+import com.vaadin.client.widget.grid.selection.HasUserSelectionAllowed;
 import com.vaadin.client.widget.grid.selection.MultiSelectionRenderer;
 import com.vaadin.client.widget.grid.selection.SelectionEvent;
 import com.vaadin.client.widget.grid.selection.SelectionHandler;
@@ -1922,6 +1923,9 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
                         checkBox.addClickHandler(new ClickHandler() {
                             @Override
                             public void onClick(ClickEvent event) {
+                                if (!grid.isUserSelectionAllowed()) {
+                                    return;
+                                }
                                 T row = pinnedRowHandle.getRow();
                                 if (grid.isSelected(row)) {
                                     grid.deselect(row);
@@ -2885,6 +2889,8 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
         private boolean initDone = false;
         private boolean selected = false;
         private CheckBox selectAllCheckBox;
+        private boolean userSelectionAllowed = true;
+        private boolean enabled = true;
 
         SelectionColumn(final Renderer<Boolean> selectColumnRenderer) {
             super(selectColumnRenderer);
@@ -2915,6 +2921,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
 
             if (selectAllCheckBox == null) {
                 selectAllCheckBox = GWT.create(CheckBox.class);
+                selectAllCheckBox.setEnabled(enabled && userSelectionAllowed);
                 selectAllCheckBox.setStylePrimaryName(
                         getStylePrimaryName() + SELECT_ALL_CHECKBOX_CLASSNAME);
                 selectAllCheckBox.addValueChangeHandler(
@@ -2923,6 +2930,9 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
                             @Override
                             public void onValueChange(
                                     ValueChangeEvent<Boolean> event) {
+                                if (!isUserSelectionAllowed()) {
+                                    return;
+                                }
                                 if (event.getValue()) {
                                     fireEvent(new SelectAllEvent<T>(model));
                                     selected = true;
@@ -2937,6 +2947,10 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
                 addHeaderClickHandler(new HeaderClickHandler() {
                     @Override
                     public void onClick(GridClickEvent event) {
+                        if (!userSelectionAllowed) {
+                            return;
+                        }
+
                         CellReference<?> targetCell = event.getTargetCell();
                         int defaultRowIndex = getHeader().getRows()
                                 .indexOf(getDefaultHeaderRow());
@@ -2956,6 +2970,10 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
                         if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE) {
                             return;
                         }
+                        if (!isUserSelectionAllowed()) {
+                            return;
+                        }
+
                         HeaderRow targetHeaderRow = getHeader()
                                 .getRow(event.getFocusedCell().getRowIndex());
                         if (!targetHeaderRow.isDefault()) {
@@ -3051,8 +3069,9 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
          *            to disable it.
          */
         public void setEnabled(boolean enabled) {
+            this.enabled = enabled;
             if (selectAllCheckBox != null) {
-                selectAllCheckBox.setEnabled(enabled);
+                selectAllCheckBox.setEnabled(enabled && userSelectionAllowed);
             }
         }
 
@@ -3060,6 +3079,26 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
         public void onEnabled(boolean enabled) {
             setEnabled(enabled);
         }
+
+        /**
+         * Sets whether the user is allowed to change the selection.
+         * 
+         * @param userSelectionAllowed
+         *            <code>true</code> if the user is allowed to change the
+         *            selection, <code>false</code> otherwise
+         */
+        public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+            if (userSelectionAllowed == this.userSelectionAllowed) {
+                return;
+            }
+
+            this.userSelectionAllowed = userSelectionAllowed;
+            // Update checkbox state
+            setEnabled(enabled);
+            // Re-render select checkboxes
+            getEscalator().getBody().refreshRows(0,
+                    getEscalator().getBody().getRowCount());
+        }
     }
 
     /**
@@ -9205,4 +9244,20 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
         }
         return null;
     }
+
+    /**
+     * Checks if selection by the user is allowed in the grid.
+     * 
+     * @return <code>true</code> if selection by the user is allowed by the
+     *         selection model (the default), <code>false</code> otherwise
+     */
+    public boolean isUserSelectionAllowed() {
+        if (!(getSelectionModel() instanceof HasUserSelectionAllowed)) {
+            // Selection model does not support toggling user selection allowed
+            // - old default is to always allow selection
+            return true;
+        }
+        return ((HasUserSelectionAllowed) getSelectionModel())
+                .isUserSelectionAllowed();
+    }
 }
index 9b465a71b020003cd79e0c68937ab66855614618..931c50ee2a3f2620821e416963c5e4149268e7b3 100644 (file)
@@ -327,6 +327,19 @@ grid.addSelectionListener(selection -> { // Java 8
 });
 ----
 
+[[components.grid.selection.disallowuser]]
+=== Disallowing User Selection
+It is possible to prevent the user from changing the selection in grid for both single- and multi-selection models:
+
+[source, java]
+----
+HasUserSelectionAllowed model = (HasUserSelectionAllowed) grid.getSelectionModel();
+model.setUserSelectionAllowed(false);
+----
+
+[NOTE]
+Both `SingleSelectionModel` and `MultiSelectModel` implement `HasUserSelectionAllowed` so the cast is generally safe.
+
 
 [[components.grid.selection.clicks]]
 === Focus and Clicks
index 1efc09110437b3347324d5ddd4081ea032e44dad..f96b485cc0db4f65414f72e1f0bc8f8e787c1488 100644 (file)
@@ -105,6 +105,7 @@ import com.vaadin.shared.ui.grid.selection.MultiSelectionModelState;
 import com.vaadin.shared.ui.grid.selection.SingleSelectionModelServerRpc;
 import com.vaadin.shared.ui.grid.selection.SingleSelectionModelState;
 import com.vaadin.shared.util.SharedUtil;
+import com.vaadin.ui.Grid.SelectionModel.HasUserSelectionAllowed;
 import com.vaadin.ui.declarative.DesignAttributeHandler;
 import com.vaadin.ui.declarative.DesignContext;
 import com.vaadin.ui.declarative.DesignException;
@@ -569,11 +570,10 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
             }
         }
 
-        private void bindFields(List<Field<?>> fields,
-                Item itemDataSource) {
+        private void bindFields(List<Field<?>> fields, Item itemDataSource) {
             for (Field<?> field : fields) {
-                if (itemDataSource.getItemProperty(getPropertyId(field))
-                        != null) {
+                if (itemDataSource
+                        .getItemProperty(getPropertyId(field)) != null) {
                     bind(field, getPropertyId(field));
                 }
             }
@@ -1105,6 +1105,34 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
      * SelectionModel should extend {@link AbstractGridExtension}.
      */
     public interface SelectionModel extends Serializable, Extension {
+
+        /**
+         * Interface implemented by selection models which support disabling
+         * client side selection while still allowing programmatic selection on
+         * the server.
+         *
+         */
+        public interface HasUserSelectionAllowed extends SelectionModel {
+
+            /**
+             * Checks if the user is allowed to change the selection.
+             * 
+             * @return <code>true</code> if the user is allowed to change the
+             *         selection, <code>false</code> otherwise
+             */
+            public boolean isUserSelectionAllowed();
+
+            /**
+             * Sets whether the user is allowed to change the selection.
+             * 
+             * @param userSelectionAllowed
+             *            <code>true</code> if the user is allowed to change the
+             *            selection, <code>false</code> otherwise
+             */
+            public void setUserSelectionAllowed(boolean userSelectionAllowed);
+
+        }
+
         /**
          * Checks whether an item is selected or not.
          *
@@ -1464,7 +1492,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
      * A default implementation of a {@link SelectionModel.Single}
      */
     public static class SingleSelectionModel extends AbstractSelectionModel
-            implements SelectionModel.Single {
+            implements SelectionModel.Single, HasUserSelectionAllowed {
 
         @Override
         protected void extend(AbstractClientConnector target) {
@@ -1473,6 +1501,11 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
 
                 @Override
                 public void select(String rowKey) {
+                    if (!isUserSelectionAllowed()) {
+                        throw new IllegalStateException(
+                                "Client tried to select '" + rowKey
+                                        + "' although user selection is disallowed");
+                    }
                     SingleSelectionModel.this.select(getItemId(rowKey), false);
                 }
             });
@@ -1563,6 +1596,21 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
         protected SingleSelectionModelState getState() {
             return (SingleSelectionModelState) super.getState();
         }
+
+        @Override
+        protected SingleSelectionModelState getState(boolean markAsDirty) {
+            return (SingleSelectionModelState) super.getState(markAsDirty);
+        }
+
+        @Override
+        public boolean isUserSelectionAllowed() {
+            return getState(false).userSelectionAllowed;
+        }
+
+        @Override
+        public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+            getState().userSelectionAllowed = userSelectionAllowed;
+        }
     }
 
     /**
@@ -1590,13 +1638,15 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
         public void reset() {
             // NOOP
         }
+
     }
 
     /**
      * A default implementation of a {@link SelectionModel.Multi}
      */
     public static class MultiSelectionModel extends AbstractSelectionModel
-            implements SelectionModel.Multi {
+            implements SelectionModel.Multi,
+            SelectionModel.HasUserSelectionAllowed {
 
         /**
          * The default selection size limit.
@@ -1614,6 +1664,12 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
 
                 @Override
                 public void select(List<String> rowKeys) {
+                    if (!isUserSelectionAllowed()) {
+                        throw new IllegalStateException(
+                                "Client tried to select '" + rowKeys
+                                        + "' although user selection is disallowed");
+                    }
+
                     List<Object> items = new ArrayList<Object>();
                     for (String rowKey : rowKeys) {
                         items.add(getItemId(rowKey));
@@ -1623,6 +1679,12 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
 
                 @Override
                 public void deselect(List<String> rowKeys) {
+                    if (!isUserSelectionAllowed()) {
+                        throw new IllegalStateException(
+                                "Client tried to deselect '" + rowKeys
+                                        + "' although user selection is disallowed");
+                    }
+
                     List<Object> items = new ArrayList<Object>();
                     for (String rowKey : rowKeys) {
                         items.add(getItemId(rowKey));
@@ -1632,11 +1694,21 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
 
                 @Override
                 public void selectAll() {
+                    if (!isUserSelectionAllowed()) {
+                        throw new IllegalStateException(
+                                "Client tried to select all although user selection is disallowed");
+                    }
+
                     MultiSelectionModel.this.selectAll(false);
                 }
 
                 @Override
                 public void deselectAll() {
+                    if (!isUserSelectionAllowed()) {
+                        throw new IllegalStateException(
+                                "Client tried to deselect all although user selection is disallowed");
+                    }
+
                     MultiSelectionModel.this.deselectAll(false);
                 }
             });
@@ -1920,6 +1992,21 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
         protected MultiSelectionModelState getState() {
             return (MultiSelectionModelState) super.getState();
         }
+
+        @Override
+        protected MultiSelectionModelState getState(boolean markAsDirty) {
+            return (MultiSelectionModelState) super.getState(markAsDirty);
+        }
+
+        @Override
+        public boolean isUserSelectionAllowed() {
+            return getState(false).userSelectionAllowed;
+        }
+
+        @Override
+        public void setUserSelectionAllowed(boolean userSelectionAllowed) {
+            getState().userSelectionAllowed = userSelectionAllowed;
+        }
     }
 
     /**
@@ -2228,8 +2315,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
 
             Item item = cell.getItem();
             Property itemProperty = item.getItemProperty(cell.getPropertyId());
-            Object modelValue =
-                    itemProperty == null ? null : itemProperty.getValue();
+            Object modelValue = itemProperty == null ? null
+                    : itemProperty.getValue();
 
             data.put(columnKeys.key(cell.getPropertyId()), AbstractRenderer
                     .encodeValue(modelValue, renderer, converter, getLocale()));
@@ -4563,8 +4650,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
     private FieldGroup editorFieldGroup = new CustomFieldGroup();
 
     /**
-     * Poperty ID to Field mapping that stores editor fields set by {@link
-     * #setEditorField(Object, Field)}.
+     * Poperty ID to Field mapping that stores editor fields set by
+     * {@link #setEditorField(Object, Field)}.
      */
     private Map<Object, Field<?>> editorFields = new HashMap<Object, Field<?>>();
 
@@ -5271,10 +5358,12 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
     }
 
     /**
-     * Sets the column resize mode to use. The default mode is {@link ColumnResizeMode#ANIMATED}.
+     * Sets the column resize mode to use. The default mode is
+     * {@link ColumnResizeMode#ANIMATED}.
      *
-     * @param mode a ColumnResizeMode value
-
+     * @param mode
+     *            a ColumnResizeMode value
+     * 
      * @since 7.7.5
      */
     public void setColumnResizeMode(ColumnResizeMode mode) {
@@ -5282,7 +5371,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
     }
 
     /**
-     * Returns the current column resize mode. The default mode is {@link ColumnResizeMode#ANIMATED}.
+     * Returns the current column resize mode. The default mode is
+     * {@link ColumnResizeMode#ANIMATED}.
      *
      * @return a ColumnResizeMode value
      * 
@@ -6873,7 +6963,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
 
         Field<?> editor = editorFieldGroup.getField(propertyId);
 
-        // If field group has no field for this property, see if we have it stored
+        // If field group has no field for this property, see if we have it
+        // stored
         if (editor == null) {
             editor = editorFields.get(propertyId);
             if (editor != null) {
@@ -6937,9 +7028,9 @@ public class Grid extends AbstractFocusable implements SelectionNotifier,
         editorFieldGroup.setItemDataSource(item);
 
         for (Column column : getColumns()) {
-            column.getState().editorConnector =
-                    item.getItemProperty(column.getPropertyId()) == null
-                            ? null : getEditorField(column.getPropertyId());
+            column.getState().editorConnector = item
+                    .getItemProperty(column.getPropertyId()) == null ? null
+                            : getEditorField(column.getPropertyId());
         }
 
         editorActive = true;
index f07c740b6ca2165bca22307f4a18c43e6fd73e36..49856dffa9e6bbe940923410165f2396b4908260 100644 (file)
@@ -17,6 +17,7 @@ package com.vaadin.tests.server.component.grid;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 import org.junit.After;
@@ -28,8 +29,11 @@ import com.vaadin.data.Container;
 import com.vaadin.data.util.IndexedContainer;
 import com.vaadin.event.SelectionEvent;
 import com.vaadin.event.SelectionEvent.SelectionListener;
+import com.vaadin.shared.ui.grid.selection.MultiSelectionModelServerRpc;
 import com.vaadin.shared.ui.grid.selection.MultiSelectionModelState;
+import com.vaadin.ui.ComponentTest;
 import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.SelectionModel.HasUserSelectionAllowed;
 
 public class MultiSelectionModelTest {
 
@@ -187,4 +191,41 @@ public class MultiSelectionModelTest {
         }
         Assert.fail("Not all items were correctly selected");
     }
+
+    @Test(expected = IllegalStateException.class)
+    public void refuseSelectWhenUserSelectionDisallowed() {
+        ((HasUserSelectionAllowed) grid.getSelectionModel())
+                .setUserSelectionAllowed(false);
+        MultiSelectionModelServerRpc serverRpc = ComponentTest.getRpcProxy(
+                grid.getSelectionModel(), MultiSelectionModelServerRpc.class);
+        serverRpc.select(Collections.singletonList("a"));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void refuseDeselectWhenUserSelectionDisallowed() {
+        ((HasUserSelectionAllowed) grid.getSelectionModel())
+                .setUserSelectionAllowed(false);
+        MultiSelectionModelServerRpc serverRpc = ComponentTest.getRpcProxy(
+                grid.getSelectionModel(), MultiSelectionModelServerRpc.class);
+        serverRpc.deselect(Collections.singletonList("a"));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void refuseSelectAllWhenUserSelectionDisallowed() {
+        ((HasUserSelectionAllowed) grid.getSelectionModel())
+                .setUserSelectionAllowed(false);
+        MultiSelectionModelServerRpc serverRpc = ComponentTest.getRpcProxy(
+                grid.getSelectionModel(), MultiSelectionModelServerRpc.class);
+        serverRpc.selectAll();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void refuseDeselectAllWhenUserSelectionDisallowed() {
+        ((HasUserSelectionAllowed) grid.getSelectionModel())
+                .setUserSelectionAllowed(false);
+        MultiSelectionModelServerRpc serverRpc = ComponentTest.getRpcProxy(
+                grid.getSelectionModel(), MultiSelectionModelServerRpc.class);
+        serverRpc.deselectAll();
+    }
+
 }
index 8b66ab625d9ae5a308b72f9fee5b810d2d50dced..e3331cd0be6e524005a69c4d810deda35bc02504 100644 (file)
@@ -24,8 +24,11 @@ import com.vaadin.data.Container;
 import com.vaadin.data.util.IndexedContainer;
 import com.vaadin.event.SelectionEvent;
 import com.vaadin.event.SelectionEvent.SelectionListener;
+import com.vaadin.shared.ui.grid.selection.SingleSelectionModelServerRpc;
+import com.vaadin.ui.ComponentTest;
 import com.vaadin.ui.Grid;
 import com.vaadin.ui.Grid.SelectionMode;
+import com.vaadin.ui.Grid.SelectionModel.HasUserSelectionAllowed;
 import com.vaadin.ui.Grid.SingleSelectionModel;
 
 public class SingleSelectionModelTest {
@@ -150,4 +153,14 @@ public class SingleSelectionModelTest {
             }
         });
     }
+
+    @Test(expected = IllegalStateException.class)
+    public void refuseSelectionWhenUserSelectionDisallowed() {
+        ((HasUserSelectionAllowed) grid.getSelectionModel())
+                .setUserSelectionAllowed(false);
+        SingleSelectionModelServerRpc serverRpc = ComponentTest.getRpcProxy(
+                grid.getSelectionModel(), SingleSelectionModelServerRpc.class);
+        serverRpc.select("a");
+    }
+
 }
diff --git a/server/src/test/java/com/vaadin/ui/ComponentTest.java b/server/src/test/java/com/vaadin/ui/ComponentTest.java
new file mode 100644 (file)
index 0000000..7077f8b
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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.ui;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+
+import org.junit.Assert;
+
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.ServerRpcManager;
+import com.vaadin.shared.communication.ServerRpc;
+
+import elemental.json.JsonObject;
+
+/**
+ * Base class for component unit tests, providing helper methods for e.g.
+ * invoking RPC and updating diff state.
+ */
+public class ComponentTest {
+
+    /**
+     * Perform operations on the component similar to what would be done when
+     * the component state is communicated to the client, e.g. update diff state
+     * and mark as clean.
+     *
+     * @param component
+     *            the component to update
+     */
+    public static void syncToClient(AbstractComponent component) {
+        updateDiffState(component);
+        component.getUI().getConnectorTracker().markClean(component);
+    }
+
+    /**
+     * Checks if the connector has been marked dirty.
+     *
+     * @param connector
+     *            the connector to check
+     * @return <code>true</code> if the connector has been marked dirty,
+     *         <code>false</code> otherwise
+     */
+    public static boolean isDirty(ClientConnector connector) {
+        return connector.getUI().getConnectorTracker().isDirty(connector);
+    }
+
+    /**
+     * Updates the stored diff state from the current component state.
+     *
+     * @param rta
+     *            the component to update
+     */
+    public static void updateDiffState(AbstractComponent component) {
+        component.getUI().getSession().getCommunicationManager()
+                .encodeState(component, component.getState());
+
+    }
+
+    /**
+     * Gets the server rpc handler registered for a component.
+     *
+     * @param connector
+     *            the connector which listens to the RPC
+     * @param serverRpcClass
+     *            the server RPC class
+     * @return the server RPC handler
+     */
+    public static <T extends ServerRpc> T getRpcProxy(ClientConnector connector,
+            Class<T> serverRpcClass) {
+        try {
+            ServerRpcManager<?> rpcManager = connector
+                    .getRpcManager(serverRpcClass.getName());
+            Method method = ServerRpcManager.class
+                    .getDeclaredMethod("getImplementation");
+            method.setAccessible(true);
+            return serverRpcClass.cast(method.invoke(rpcManager));
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Asserts the set of properties that would be sent as state changes for the
+     * given connector.
+     *
+     * @param connector
+     *            the connector that has state changes
+     * @param message
+     *            the message to show if the properties are not as expected
+     * @param expectedProperties
+     *            names of the expected properties
+     */
+    public static void assertEncodedStateProperties(ClientConnector connector,
+            String message, String... expectedProperties) {
+        assert connector.isAttached();
+
+        JsonObject encodeState = connector.encodeState();
+
+        // Collect to HashSet so that order doesn't matter
+        Assert.assertEquals(message,
+                new HashSet<String>(Arrays.asList(expectedProperties)),
+                new HashSet<String>(Arrays.asList(encodeState.keys())));
+    }
+
+}
\ No newline at end of file
index 35da1d1e0be91bd115061beedaeb4b00d52fe11d..3fd685c98e3663d1402bd31544e2172805d1b451 100644 (file)
@@ -27,5 +27,6 @@ public class MultiSelectionModelState extends SharedState {
 
     /* Select All -checkbox status */
     public boolean allSelected;
+    public boolean userSelectionAllowed = true;
 
 }
index de06dfc61a3473d62e42a82f3a53adbb2df8845c..6355ddec7e293f9b5326fa829cf9e0e364219aa2 100644 (file)
@@ -27,4 +27,5 @@ public class SingleSelectionModelState extends SharedState {
 
     /* Allow deselecting rows */
     public boolean deselectAllowed = true;
+    public boolean userSelectionAllowed = true;
 }
index e3fdd68ed60bc1c18b1e5c7839b78f0a7bfe593a..6f1986720b3b69f15f1f62d2004972a1036c5aee 100644 (file)
@@ -75,6 +75,7 @@ import com.vaadin.ui.Grid.RowReference;
 import com.vaadin.ui.Grid.RowStyleGenerator;
 import com.vaadin.ui.Grid.SelectionMode;
 import com.vaadin.ui.Grid.SelectionModel;
+import com.vaadin.ui.Grid.SelectionModel.HasUserSelectionAllowed;
 import com.vaadin.ui.Label;
 import com.vaadin.ui.Notification;
 import com.vaadin.ui.Panel;
@@ -108,6 +109,7 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
     private int containerDelay = 0;
 
     private boolean singleSelectAllowDeselect = true;
+    private boolean allowUserSelection = true;
 
     private IndexedContainer ds;
     private Grid grid;
@@ -509,6 +511,9 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
                         } else {
                             grid.removeSelectionListener(selectionListener);
                         }
+
+                        ((HasUserSelectionAllowed) grid.getSelectionModel())
+                                .setUserSelectionAllowed(allowUserSelection);
                     }
                 });
 
@@ -804,6 +809,17 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
                         }
                     }
                 });
+        createBooleanAction("Allow user selection", "State", allowUserSelection,
+                new Command<Grid, Boolean>() {
+                    @Override
+                    public void execute(Grid c, Boolean value, Object data) {
+                        allowUserSelection = value.booleanValue();
+
+                        SelectionModel model = c.getSelectionModel();
+                        ((HasUserSelectionAllowed) model)
+                                .setUserSelectionAllowed(allowUserSelection);
+                    }
+                });
         createBooleanAction("Column Reordering Allowed", "State", false,
                 new Command<Grid, Boolean>() {
 
@@ -1268,12 +1284,14 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
                     }
                 }, null);
 
-        createBooleanAction("Simple resize mode", "Columns", false, new Command<Grid, Boolean>() {
-            @Override
-            public void execute(Grid g, Boolean value, Object data) {
-                g.setColumnResizeMode(value ? ColumnResizeMode.SIMPLE : ColumnResizeMode.ANIMATED);
-            }
-        });
+        createBooleanAction("Simple resize mode", "Columns", false,
+                new Command<Grid, Boolean>() {
+                    @Override
+                    public void execute(Grid g, Boolean value, Object data) {
+                        g.setColumnResizeMode(value ? ColumnResizeMode.SIMPLE
+                                : ColumnResizeMode.ANIMATED);
+                    }
+                });
     }
 
     private static String getColumnProperty(int c) {
index 642514393eca2fbf2e5fe876903096c8e5b89daf..b185d52c5bc7460f6ce16530ee355a5008f818eb 100644 (file)
@@ -483,6 +483,10 @@ public class GridSelectionTest extends GridBasicFeaturesTest {
         selectMenuPath("Component", "Body rows", "Select first row");
     }
 
+    private void toggleUserSelectionAllowed() {
+        selectMenuPath("Component", "State", "Allow user selection");
+    }
+
     private GridRowElement getRow(int i) {
         return getGridElement().getRow(i);
     }
@@ -526,4 +530,157 @@ public class GridSelectionTest extends GridBasicFeaturesTest {
         getGridElement().getCell(0, 0).click();
         assertTrue("row should become selected", getRow(0).isSelected());
     }
+
+    @Test
+    public void singleSelectUserSelectionDisallowedSpaceSelectionNoOp() {
+        openTestURL();
+        setSelectionModelSingle();
+        getGridElement().focus();
+        getGridElement().sendKeys(Keys.DOWN, Keys.SPACE);
+        assertTrue("row was selected when selection was allowed",
+                getRow(1).isSelected());
+        toggleUserSelectionAllowed();
+        getGridElement().sendKeys(Keys.SPACE);
+        assertTrue("deselect disallowed", getRow(1).isSelected());
+        getGridElement().sendKeys(Keys.DOWN, Keys.SPACE);
+        assertFalse("select disallowed", getRow(2).isSelected());
+        assertTrue("old selection remains", getRow(1).isSelected());
+        toggleUserSelectionAllowed();
+        getGridElement().sendKeys(Keys.SPACE);
+        assertTrue("select allowed again", getRow(2).isSelected());
+        assertFalse("old selection removed", getRow(1).isSelected());
+
+    }
+
+    @Test
+    public void singleSelectUserSelectionDisallowedClickSelectionNoOp() {
+        openTestURL();
+        setSelectionModelSingle();
+        getGridElement().getCell(1, 0).click();
+        assertTrue("selection allowed, should have been selected",
+                getRow(1).isSelected());
+        toggleUserSelectionAllowed();
+        getGridElement().getCell(1, 0).click();
+        assertTrue("deselect disallowed, should remain selected",
+                getRow(1).isSelected());
+        getGridElement().getCell(2, 0).click();
+        assertFalse("select disallowed, should not have been selected",
+                getRow(2).isSelected());
+        assertTrue("select disallowed, old selection should have remained",
+                getRow(1).isSelected());
+        toggleUserSelectionAllowed();
+        getGridElement().getCell(2, 0).click();
+        assertTrue("select allowed again, row should have been selected",
+                getRow(2).isSelected());
+        assertFalse("old selection removed", getRow(1).isSelected());
+
+    }
+
+    @Test
+    public void multiSelectUserSelectionDisallowedSpaceSelectionNoOp() {
+        openTestURL();
+        setSelectionModelMulti();
+        getGridElement().focus();
+        getGridElement().sendKeys(Keys.DOWN, Keys.SPACE);
+        assertTrue("selection allowed, should have been selected",
+                getRow(1).isSelected());
+        toggleUserSelectionAllowed();
+        getGridElement().sendKeys(Keys.SPACE);
+        assertTrue("deselect disallowed, should remain selected",
+                getRow(1).isSelected());
+        getGridElement().sendKeys(Keys.DOWN, Keys.SPACE);
+        assertFalse("select disallowed, should not have been selected",
+                getRow(2).isSelected());
+        assertTrue("select disallowed, old selection should have remained",
+                getRow(1).isSelected());
+
+        toggleUserSelectionAllowed();
+        getGridElement().sendKeys(Keys.SPACE);
+        assertTrue("select allowed again, row should have been selected",
+                getRow(2).isSelected());
+        assertTrue(
+                "select allowed again but old selection should have remained",
+                getRow(1).isSelected());
+    }
+
+    @Test
+    public void multiSelectUserSelectionDisallowedCheckboxSelectionNoOp() {
+        openTestURL();
+        setSelectionModelMulti();
+        assertTrue(getSelectionCheckbox(0).isEnabled());
+        toggleUserSelectionAllowed();
+        assertFalse(getSelectionCheckbox(0).isEnabled());
+
+        // Select by clicking on checkbox (should always fail as it is disabled)
+        getSelectionCheckbox(0).click();
+        assertFalse(getGridElement().getRow(0).isSelected());
+        // Select by clicking on cell (should fail)
+        getGridElement().getCell(0, 0).click();
+        assertFalse(getGridElement().getRow(0).isSelected());
+
+        toggleUserSelectionAllowed();
+        assertTrue(getSelectionCheckbox(0).isEnabled());
+        getSelectionCheckbox(0).click();
+        assertTrue(getGridElement().getRow(0).isSelected());
+    }
+
+    @Test
+    public void multiSelectUserSelectionDisallowedCheckboxSelectAllNoOp() {
+        openTestURL();
+        setSelectionModelMulti();
+
+        assertTrue(getSelectAllCheckbox().isEnabled());
+        toggleUserSelectionAllowed();
+        assertFalse(getSelectAllCheckbox().isEnabled());
+
+        // Select all by clicking on checkbox (should not select)
+        getSelectAllCheckbox().click();
+        assertFalse(getSelectAllCheckbox().isSelected());
+        assertFalse(getGridElement().getRow(0).isSelected());
+        assertFalse(getGridElement().getRow(10).isSelected());
+
+        // Select all by clicking on header cell (should not select)
+        getGridElement().getHeaderCell(0, 0).click();
+        assertFalse(getSelectAllCheckbox().isSelected());
+        assertFalse(getGridElement().getRow(0).isSelected());
+        assertFalse(getGridElement().getRow(10).isSelected());
+
+        toggleUserSelectionAllowed();
+
+        assertTrue(getSelectAllCheckbox().isEnabled());
+        getSelectAllCheckbox().click();
+        assertTrue(getGridElement().getRow(0).isSelected());
+        assertTrue(getGridElement().getRow(10).isSelected());
+    }
+
+    @Test
+    public void singleSelectUserSelectionDisallowedServerSelect() {
+        openTestURL();
+        setSelectionModelSingle();
+        toggleUserSelectionAllowed();
+
+        toggleFirstRowSelection();
+        assertTrue(getGridElement().getRow(0).isSelected());
+    }
+
+    @Test
+    public void multiSelectUserSelectionDisallowedServerSelect() {
+        openTestURL();
+        setSelectionModelMulti();
+        toggleUserSelectionAllowed();
+
+        toggleFirstRowSelection();
+        assertTrue(getGridElement().getRow(0).isSelected());
+    }
+
+    private WebElement getSelectAllCheckbox() {
+        return getGridElement().getHeaderCell(0, 0)
+                .findElement(By.tagName("input"));
+    }
+
+    private WebElement getSelectionCheckbox(int row) {
+        return getGridElement().getCell(row, 0)
+                .findElement(By.tagName("input"));
+    }
+
 }