]> source.dussan.org Git - vaadin-framework.git/commitdiff
Grid columns can now be marked as non-editable (#16538)
authorJohannes Dahlström <johannesd@vaadin.com>
Wed, 4 Feb 2015 16:33:30 +0000 (18:33 +0200)
committerJohannes Dahlström <johannesd@vaadin.com>
Thu, 5 Feb 2015 15:47:46 +0000 (15:47 +0000)
Non-editable columns are not assigned editor fields. When the editor is active,
any non-editable content is not displayed (this should changein the future).
This is separate from setting the property or editor field read-only - in those
cases the field is still used to display the data which may not be desired and
will fail if there is no converter.

Also add Column.setEditorField(Field<?>) and the corresponding getter.

Change-Id: Ice17c357895cb63a8e1bfd6abaffc1d803399e98

client/src/com/vaadin/client/connectors/GridConnector.java
client/src/com/vaadin/client/widgets/Grid.java
server/src/com/vaadin/ui/Grid.java
server/tests/src/com/vaadin/tests/server/component/grid/GridColumns.java
shared/src/com/vaadin/shared/ui/grid/GridColumnState.java
uitest/src/com/vaadin/testbench/elements/GridElement.java
uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java
uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java
uitest/src/com/vaadin/tests/widgetset/client/grid/GridBasicClientFeaturesWidget.java

index 827e366de08f3419109894c4e852991445a1406d..8d383ab0aedfc1a4fc0d1ae71bae49ebdf7f0a2f 100644 (file)
@@ -756,6 +756,7 @@ public class GridConnector extends AbstractHasComponentsConnector implements
         column.setExpandRatio(state.expandRatio);
 
         column.setSortable(state.sortable);
+        column.setEditable(state.editable);
         column.setEditorConnector((AbstractFieldConnector) state.editorConnector);
     }
 
index a870a732b5d90235c0dbc31fffd842f27e337128..303b94763d5d0463bab6acb6c218e73deeabd468 100644 (file)
@@ -1254,11 +1254,13 @@ public class Grid<T> extends ResizeComposite implements
 
         /**
          * Returns the editor widget associated with the given column. If the
-         * editor is not active, returns null.
+         * editor is not active or the column is not
+         * {@link Grid.Column#isEditable() editable}, returns null.
          * 
          * @param column
          *            the column
-         * @return the widget if the editor is open, null otherwise
+         * @return the widget if the editor is open and the column is editable,
+         *         null otherwise
          */
         protected Widget getWidget(Column<?, T> column) {
             return columnToWidget.get(column);
@@ -1305,14 +1307,12 @@ public class Grid<T> extends ResizeComposite implements
                 editorOverlay.appendChild(cell);
 
                 Column<?, T> column = grid.getColumn(i);
-                if (column == grid.selectionColumn) {
-                    continue;
-                }
-
-                Widget editor = getHandler().getWidget(column);
-                if (editor != null) {
-                    columnToWidget.put(column, editor);
-                    attachWidget(editor, cell);
+                if (column.isEditable()) {
+                    Widget editor = getHandler().getWidget(column);
+                    if (editor != null) {
+                        columnToWidget.put(column, editor);
+                        attachWidget(editor, cell);
+                    }
                 }
             }
 
@@ -1987,6 +1987,7 @@ public class Grid<T> extends ResizeComposite implements
     }
 
     public final class SelectionColumn extends Column<Boolean, T> {
+
         private boolean initDone = false;
 
         SelectionColumn(final Renderer<Boolean> selectColumnRenderer) {
@@ -2022,6 +2023,8 @@ public class Grid<T> extends ResizeComposite implements
 
             setWidth(-1);
 
+            setEditable(false);
+
             initDone = true;
         }
 
@@ -2074,6 +2077,17 @@ public class Grid<T> extends ResizeComposite implements
         public double getMinimumWidth() {
             return -1;
         }
+
+        @Override
+        public Column<Boolean, T> setEditable(boolean editable) {
+            if (initDone) {
+                throw new UnsupportedOperationException(
+                        "can't set the selection column editable");
+            }
+            super.setEditable(editable);
+            return this;
+        }
+
     }
 
     /**
@@ -2738,6 +2752,8 @@ public class Grid<T> extends ResizeComposite implements
 
         private boolean sortable = false;
 
+        private boolean editable = true;
+
         private String headerCaption = "";
 
         private double minimumWidthPx = GridConstants.DEFAULT_MIN_WIDTH;
@@ -3159,6 +3175,43 @@ public class Grid<T> extends ResizeComposite implements
             return expandRatio;
         }
 
+        /**
+         * Sets whether the values in this column should be editable by the user
+         * when the row editor is active. By default columns are editable.
+         * 
+         * @param editable
+         *            {@code true} to set this column editable, {@code false}
+         *            otherwise
+         * @return this column
+         * 
+         * @throws IllegalStateException
+         *             if the editor is currently active
+         * 
+         * @see Grid#editRow(int)
+         * @see Grid#isEditorActive()
+         */
+        public Column<C, T> setEditable(boolean editable) {
+            if (editable != this.editable && grid.isEditorActive()) {
+                throw new IllegalStateException(
+                        "Cannot change column editable status while the editor is active");
+            }
+            this.editable = editable;
+            return this;
+        }
+
+        /**
+         * Returns whether the values in this column are editable by the user
+         * when the row editor is active.
+         * 
+         * @return {@code true} if this column is editable, {@code false}
+         *         otherwise
+         *
+         * @see #setEditable(boolean)
+         */
+        public boolean isEditable() {
+            return editable;
+        }
+
         private void scheduleColumnWidthRecalculator() {
             if (grid != null) {
                 grid.autoColumnWidthsRecalculator.schedule();
@@ -5781,6 +5834,15 @@ public class Grid<T> extends ResizeComposite implements
         editor.editRow(rowIndex);
     }
 
+    /**
+     * Returns whether the editor is currently open on some row.
+     * 
+     * @return {@code true} if the editor is active, {@code false} otherwise.
+     */
+    public boolean isEditorActive() {
+        return editor.getState() != State.INACTIVE;
+    }
+
     /**
      * Saves any unsaved changes in the editor to the data source.
      * 
index 125cc5a05a386fbfc365880cb4291c49611cceb4..69e23ecd92f4df5e962a6555852c9a12f7a857d6 100644 (file)
@@ -1982,7 +1982,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
         }
 
         /**
-         * Return the property id for the backing property of this Column
+         * Returns the property id for the backing property of this Column
          * 
          * @return property id
          */
@@ -2302,11 +2302,14 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
         }
 
         /**
-         * Should sorting controls be available for the column
+         * Sets whether the column should be sortable by the user. The grid can
+         * be sorted by a sortable column by clicking or tapping the column's
+         * default header. Programmatic sorting using the Grid.sort methods is
+         * not affected by this setting.
          * 
          * @param sortable
-         *            <code>true</code> if the sorting controls should be
-         *            visible.
+         *            <code>true</code> if the user should be able to sort the
+         *            column, false otherwise
          * @return the column itself
          */
         public Column setSortable(boolean sortable) {
@@ -2334,7 +2337,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
         }
 
         /**
-         * Are the sorting controls visible in the column header
+         * Returns whether the user is able to sort the grid by this column.
+         * 
+         * @return true if the column is sortable by the user, false otherwise
          */
         public boolean isSortable() {
             return state.sortable;
@@ -2361,8 +2366,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
          * and 2, respectively. The column with a <strong>ratio of 0 is exactly
          * as wide as its contents requires</strong>. The column with a ratio of
          * 1 is as wide as it needs, <strong>plus a third of any excess
-         * space</strong>, bceause we have 3 parts total, and this column
-         * reservs only one of those. The column with a ratio of 2, is as wide
+         * space</strong>, because we have 3 parts total, and this column
+         * reserves only one of those. The column with a ratio of 2, is as wide
          * as it needs to be, <strong>plus two thirds</strong> of the excess
          * width.
          * 
@@ -2384,7 +2389,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
         }
 
         /**
-         * Gets the column's expand ratio.
+         * Returns the column's expand ratio.
          * 
          * @return the column's expand ratio
          * @see #setExpandRatio(int)
@@ -2431,7 +2436,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
         }
 
         /**
-         * Gets the minimum width for this column.
+         * Return the minimum width for this column.
          * 
          * @return the minimum width for this column
          * @see #setMinimumWidth(double)
@@ -2468,7 +2473,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
         }
 
         /**
-         * Gets the maximum width for this column.
+         * Returns the maximum width for this column.
          * 
          * @return the maximum width for this column
          * @see #setMaximumWidth(double)
@@ -2476,6 +2481,79 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
         public double getMaximumWidth() {
             return getState().maxWidth;
         }
+
+        /**
+         * Sets whether the properties corresponding to this column should be
+         * editable when the item editor is active. By default columns are
+         * editable.
+         * <p>
+         * Values in non-editable columns are currently not displayed when the
+         * editor is active, but this will probably change in the future. They
+         * are not automatically assigned an editor field and, if one is
+         * manually assigned, it is not used. Columns that cannot (or should
+         * not) be edited even in principle should be set non-editable.
+         * 
+         * @param editable
+         *            {@code true} if this column should be editable,
+         *            {@code false} otherwise
+         * @return this column
+         *
+         * @throws IllegalStateException
+         *             if the editor is currently active
+         *
+         * @see Grid#editItem(Object)
+         * @see Grid#isEditorActive()
+         */
+        public Column setEditable(boolean editable) {
+            checkColumnIsAttached();
+            if (grid.isEditorActive()) {
+                throw new IllegalStateException(
+                        "Cannot change column editable status while the editor is active");
+            }
+            getState().editable = editable;
+            grid.markAsDirty();
+            return this;
+        }
+
+        /**
+         * Returns whether the properties corresponding to this column should be
+         * editable when the item editor is active.
+         * 
+         * @return {@code true} if this column is editable, {@code false}
+         *         otherwise
+         * 
+         * @see Grid#editItem(Object)
+         * @see #setEditable(boolean)
+         */
+
+        public boolean isEditable() {
+            return getState().editable;
+        }
+
+        /**
+         * Sets the field component used to edit the properties in this column
+         * when the item editor is active. Please refer to
+         * {@link Grid#setEditorField(Object, Field)} for more information.
+         * 
+         * @param editor
+         *            the editor field, cannot be null
+         * @return this column
+         */
+        public Column setEditorField(Field<?> editor) {
+            grid.setEditorField(getPropertyId(), editor);
+            return this;
+        }
+
+        /**
+         * Returns the editor field used to edit the properties in this column
+         * when the item editor is active. Please refer to
+         * {@link Grid#getEditorField(Object)} for more information.
+         * 
+         * @return the editor field or null if this column is not editable
+         */
+        public Field<?> getEditorField() {
+            return grid.getEditorField(getPropertyId());
+        }
     }
 
     /**
@@ -4616,6 +4694,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
 
     /**
      * Gets the field component that represents a property in the item editor.
+     * Returns null if the corresponding column is not
+     * {@link Column#isEditable() editable}.
      * <p>
      * When {@link #editItem(Object) editItem} is called, fields are
      * automatically created and bound for any unbound properties.
@@ -4627,7 +4707,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
      * 
      * @param propertyId
      *            the property id of the property for which to find the field
-     * @return the bound field, never null
+     * @return the bound field or null if the respective column is not editable
      * 
      * @throws IllegalArgumentException
      *             if there is no column for the provided property id
@@ -4638,6 +4718,10 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
     public Field<?> getEditorField(Object propertyId) {
         checkColumnExists(propertyId);
 
+        if (!getColumn(propertyId).isEditable()) {
+            return null;
+        }
+
         Field<?> editor = editorFieldGroup.getField(propertyId);
         if (editor == null) {
             editor = editorFieldGroup.buildAndBind(propertyId);
@@ -4651,7 +4735,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
     }
 
     /**
-     * Opens the editor interface for the provided item.
+     * Opens the editor interface for the provided item. Scrolls the Grid to
+     * bring the item to view if it is not already visible.
      * 
      * @param itemId
      *            the id of the item to edit
@@ -4683,11 +4768,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier,
         editorFieldGroup.setItemDataSource(item);
 
         for (Column column : getColumns()) {
-            Object propertyId = column.getPropertyId();
-
-            Field<?> editor = getEditorField(propertyId);
-
-            getColumn(propertyId).getState().editorConnector = editor;
+            column.getState().editorConnector = getEditorField(column
+                    .getPropertyId());
         }
     }
 
index 5e96f4eeae1e63167e10d23f8af038b8246188bd..ab17e473931e0603f7800f9125f15c218815e616 100644 (file)
@@ -19,6 +19,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -37,6 +38,7 @@ import com.vaadin.shared.ui.grid.GridState;
 import com.vaadin.shared.util.SharedUtil;
 import com.vaadin.ui.Grid;
 import com.vaadin.ui.Grid.Column;
+import com.vaadin.ui.TextField;
 
 public class GridColumns {
 
@@ -242,6 +244,35 @@ public class GridColumns {
         noSortColumn.setSortable(true);
     }
 
+    @Test
+    public void testColumnsEditableByDefault() {
+        for (Column c : grid.getColumns()) {
+            assertTrue(c + " should be editable", c.isEditable());
+        }
+    }
+
+    @Test
+    public void testPropertyAndColumnEditorFieldsMatch() {
+        grid.setEditorField("column1", new TextField());
+        assertSame(grid.getEditorField("column1"), grid.getColumn("column1")
+                .getEditorField());
+
+        grid.getColumn("column2").setEditorField(new TextField());
+        assertSame(grid.getEditorField("column2"), grid.getColumn("column2")
+                .getEditorField());
+    }
+
+    @Test
+    public void testUneditableColumnHasNoField() {
+        Column col = grid.getColumn("column1");
+
+        col.setEditable(false);
+
+        assertFalse("Column should be uneditable", col.isEditable());
+        assertNull("Uneditable column should not be auto-assigned a Field",
+                col.getEditorField());
+    }
+
     private GridColumnState getColumnState(Object propertyId) {
         String columnId = columnIdMapper.key(propertyId);
         for (GridColumnState columnState : state.columns) {
index 070d1467369374dd9c339117aadd6f3a3897920f..4c5b2c3a028d65c00b5cdefef6a400576820a8fe 100644 (file)
@@ -45,6 +45,12 @@ public class GridColumnState implements Serializable {
      */
     public Connector rendererConnector;
 
+    /**
+     * Whether the values in this column are editable when the editor interface
+     * is active.
+     */
+    public boolean editable = true;
+
     /**
      * The connector for the field used to edit cells in this column when the
      * editor interface is active.
index 784e67d8c2b109809eec0924501b4731597dcb66..5a27bc14443034d0e853fec75367f8d620e0d8c5 100644 (file)
@@ -75,13 +75,30 @@ public class GridElement extends AbstractComponentElement {
          * Gets the editor field for column in given index.
          * 
          * @param colIndex
-         *            column index
+         *            the column index
          * @return the editor field for given location
+         * 
+         * @throws NoSuchElementException
+         *             if {@code isEditable(colIndex) == false}
          */
         public TestBenchElement getField(int colIndex) {
             return grid.getSubPart("#editor[" + colIndex + "]");
         }
 
+        /**
+         * Gets whether the column with the given index is editable, that is,
+         * has an associated editor field.
+         * 
+         * @param colIndex
+         *            the column index
+         * @return {@code true} if the column has an editor field, {@code false}
+         *          otherwise
+         */
+        public boolean isEditable(int colIndex) {
+            return grid
+                    .isElementPresent(By.vaadin("#editor[" + colIndex + "]"));
+        }
+
         /**
          * Saves the fields of this editor.
          * <p>
index 89fff6871b37524f74841e5ff1e0cd70ed3e41d7..fe4a31d9e781800b377307334b246ae1fb035f2a 100644 (file)
@@ -77,6 +77,7 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
     public static final String CELL_STYLE_GENERATOR_SPECIAL = "Special for 1/4 Column 1";
     private static final int MANUALLY_FORMATTED_COLUMNS = 5;
     public static final int COLUMNS = 12;
+    public static final int EDITABLE_COLUMNS = COLUMNS - 1;
     public static final int ROWS = 1000;
 
     private int containerDelay = 0;
@@ -223,7 +224,8 @@ public class GridBasicFeatures extends AbstractComponentTest<Grid> {
 
         grid.setSelectionMode(SelectionMode.NONE);
 
-        grid.getEditorField(getColumnProperty(3)).setReadOnly(true);
+        grid.getEditorField(getColumnProperty(2)).setReadOnly(true);
+        grid.getColumn(getColumnProperty(3)).setEditable(false);
 
         createGridActions();
 
index a81d374167bb0dcfd84680d0906617c8d662e605..f6f2fac074bd1771e242b15853542b2f08dfcc1e 100644 (file)
@@ -102,14 +102,14 @@ public class GridEditorClientTest extends GridBasicClientFeaturesTest {
         List<WebElement> widgets = editor.findElements(By
                 .className("gwt-TextBox"));
 
-        assertEquals(GridBasicFeatures.COLUMNS, widgets.size());
+        assertEquals(GridBasicFeatures.EDITABLE_COLUMNS, widgets.size());
 
         assertEquals("(100, 0)", widgets.get(0).getAttribute("value"));
         assertEquals("(100, 1)", widgets.get(1).getAttribute("value"));
         assertEquals("(100, 2)", widgets.get(2).getAttribute("value"));
 
-        assertEquals("100", widgets.get(7).getAttribute("value"));
-        assertEquals("<b>100</b>", widgets.get(9).getAttribute("value"));
+        assertEquals("100", widgets.get(6).getAttribute("value"));
+        assertEquals("<b>100</b>", widgets.get(8).getAttribute("value"));
     }
 
     @Test
@@ -186,6 +186,13 @@ public class GridEditorClientTest extends GridBasicClientFeaturesTest {
                         .getText());
     }
 
+    public void testUneditableColumn() {
+        selectMenuPath("Component", "Editor", "Edit row 5");
+
+        assertFalse("Uneditable column should not have an editor widget",
+                getGridElement().getEditor().isEditable(3));
+    }
+
     protected WebElement getSaveButton() {
         return getEditor().findElement(By.className("v-grid-editor-save"));
     }
@@ -193,5 +200,4 @@ public class GridEditorClientTest extends GridBasicClientFeaturesTest {
     protected WebElement getCancelButton() {
         return getEditor().findElement(By.className("v-grid-editor-cancel"));
     }
-
 }
index 566946a7eaebed6e09e4b19684bc1c7ce2ae6870..5e11af1ca50d1e342440c480aa94da52a63b88d6 100644 (file)
@@ -119,13 +119,13 @@ public class GridEditorTest extends GridBasicFeaturesTest {
         selectMenuPath(EDIT_ITEM_100);
 
         List<WebElement> widgets = getEditorWidgets();
-        assertEquals("Number of widgets", GridBasicFeatures.COLUMNS,
+        assertEquals("Number of widgets", GridBasicFeatures.EDITABLE_COLUMNS,
                 widgets.size());
 
         assertEquals("(100, 0)", widgets.get(0).getAttribute("value"));
         assertEquals("(100, 1)", widgets.get(1).getAttribute("value"));
         assertEquals("(100, 2)", widgets.get(2).getAttribute("value"));
-        assertEquals("<b>100</b>", widgets.get(9).getAttribute("value"));
+        assertEquals("<b>100</b>", widgets.get(8).getAttribute("value"));
     }
 
     @Test
@@ -191,8 +191,8 @@ public class GridEditorTest extends GridBasicFeaturesTest {
 
     private void assertEditorOpen() {
         assertNotNull("Editor is supposed to be open", getEditor());
-        assertEquals("Unexpected number of widgets", GridBasicFeatures.COLUMNS,
-                getEditorWidgets().size());
+        assertEquals("Unexpected number of widgets",
+                GridBasicFeatures.EDITABLE_COLUMNS, getEditorWidgets().size());
     }
 
     private void assertEditorClosed() {
@@ -287,6 +287,15 @@ public class GridEditorTest extends GridBasicFeaturesTest {
                 originalScrollPos, getGridVerticalScrollPos());
     }
 
+    @Test
+    public void testUneditableColumn() {
+        selectMenuPath(EDIT_ITEM_5);
+        assertEditorOpen();
+
+        assertFalse("Uneditable column should not have an editor widget",
+                getGridElement().getEditor().isEditable(3));
+    }
+
     private WebElement getSaveButton() {
         return getDriver().findElement(By.className("v-grid-editor-save"));
     }
index 7a635ad420d8f53b856675aeeeed2cbc7d9371af..41d74a11a2ad6b318f14ab67e566e6a8646d9e5e 100644 (file)
@@ -359,6 +359,8 @@ public class GridBasicClientFeaturesWidget extends
             column.setHeaderCaption("Header (0," + c + ")");
         }
 
+        grid.getColumn(3).setEditable(false);
+
         HeaderRow row = grid.getDefaultHeaderRow();
         for (int i = 0; i < col; ++i) {
             String caption = "Header (0," + i + ")";