diff options
author | Pekka Hyvönen <pekka@vaadin.com> | 2016-11-07 09:16:37 +0200 |
---|---|---|
committer | Ilia Motornyi <elmot@vaadin.com> | 2016-11-10 07:49:08 +0000 |
commit | 39c15034076015a16cd056adf9dc422335985543 (patch) | |
tree | 8bb235b285e69cb48b83de067152f06d7c076e8d /server/src/main/java/com/vaadin/ui | |
parent | 0f42869ce1f81270141e94f169f1447febaff446 (diff) | |
download | vaadin-framework-39c15034076015a16cd056adf9dc422335985543.tar.gz vaadin-framework-39c15034076015a16cd056adf9dc422335985543.zip |
Remove HasValue from Grid
Extracts grid single selection into separate class, which
is an extension like in V7. Using an extension makes it
possible to easily add multiselect and no-select modes back,
and support custom selection models.
Adds Grid:asSingleSelect() SingleSelect so that grid can be
used as a Select in a binder.
Removes all remaining references to SelectionModels in Listings.
Renames SingleSelectionChangeEvent to SingleSelectionEvent, because
then it is unified with selection listener and MultiSelectionEvent.
Fixes vaadin/framework8-issues#424
Fixes vaadin/framework8-issues#425
Change-Id: Ie22bef29cfd4336c3f65d4e63531c578b8dd76a3
Diffstat (limited to 'server/src/main/java/com/vaadin/ui')
5 files changed, 371 insertions, 211 deletions
diff --git a/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java b/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java index 7125139d8a..2ffcedde15 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java +++ b/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java @@ -22,7 +22,7 @@ import java.util.Optional; import com.vaadin.data.HasValue; import com.vaadin.data.SelectionModel; import com.vaadin.data.SelectionModel.Single; -import com.vaadin.event.selection.SingleSelectionChangeEvent; +import com.vaadin.event.selection.SingleSelectionEvent; import com.vaadin.event.selection.SingleSelectionListener; import com.vaadin.server.data.DataCommunicator; import com.vaadin.shared.Registration; @@ -49,7 +49,7 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T> @Deprecated private static final Method SELECTION_CHANGE_METHOD = ReflectTools .findMethod(SingleSelectionListener.class, "accept", - SingleSelectionChangeEvent.class); + SingleSelectionEvent.class); /** * Creates a new {@code AbstractListing} with a default data communicator. @@ -92,11 +92,11 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T> * the value change listener, not null * @return a registration for the listener */ - public Registration addSelectionListener( + public Registration addSelectionChangeListener( SingleSelectionListener<T> listener) { - addListener(SingleSelectionChangeEvent.class, listener, + addListener(SingleSelectionEvent.class, listener, SELECTION_CHANGE_METHOD); - return () -> removeListener(SingleSelectionChangeEvent.class, listener); + return () -> removeListener(SingleSelectionEvent.class, listener); } /** @@ -158,7 +158,7 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T> @Override public Registration addValueChangeListener( HasValue.ValueChangeListener<T> listener) { - return addSelectionListener(event -> listener.accept( + return addSelectionChangeListener(event -> listener.accept( new ValueChangeEvent<>(this, event.isUserOriginated()))); } @@ -192,18 +192,6 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T> return super.isReadOnly(); } - public void deselect(T item) { - Objects.requireNonNull(item, "deselected item cannot be null"); - if (isSelected(item)) { - setSelectedFromServer(null); - } - } - - public void select(T item) { - Objects.requireNonNull(item, "selected item cannot be null"); - setSelectedFromServer(item); - } - /** * Returns the communication key of the selected item or {@code null} if no * item is selected. @@ -245,7 +233,7 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T> } doSetSelectedKey(key); - fireEvent(new SingleSelectionChangeEvent<>(AbstractSingleSelect.this, + fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this, true)); } @@ -266,7 +254,7 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T> } doSetSelectedKey(key); - fireEvent(new SingleSelectionChangeEvent<>(AbstractSingleSelect.this, + fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this, false)); } diff --git a/server/src/main/java/com/vaadin/ui/ComboBox.java b/server/src/main/java/com/vaadin/ui/ComboBox.java index 097ae30bc7..d4df2236f7 100644 --- a/server/src/main/java/com/vaadin/ui/ComboBox.java +++ b/server/src/main/java/com/vaadin/ui/ComboBox.java @@ -524,7 +524,7 @@ public class ComboBox<T> extends AbstractSingleSelect<T> implements HasValue<T>, @Override public Registration addValueChangeListener( HasValue.ValueChangeListener<T> listener) { - return addSelectionListener(event -> { + return addSelectionChangeListener(event -> { listener.accept(new ValueChangeEvent<>(event.getComponent(), this, event.isUserOriginated())); }); diff --git a/server/src/main/java/com/vaadin/ui/Grid.java b/server/src/main/java/com/vaadin/ui/Grid.java index 63c8fe3e6f..42aab6a7e4 100644 --- a/server/src/main/java/com/vaadin/ui/Grid.java +++ b/server/src/main/java/com/vaadin/ui/Grid.java @@ -30,19 +30,19 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import com.vaadin.data.SelectionModel.Single; +import com.vaadin.data.Binder; +import com.vaadin.data.SelectionModel; import com.vaadin.event.ConnectorEvent; import com.vaadin.event.ContextClickEvent; import com.vaadin.event.EventListener; -import com.vaadin.event.selection.SingleSelectionChangeEvent; import com.vaadin.server.EncodeResult; +import com.vaadin.server.Extension; import com.vaadin.server.JsonCodec; import com.vaadin.server.SerializableComparator; import com.vaadin.server.SerializableFunction; @@ -50,7 +50,6 @@ import com.vaadin.server.data.SortOrder; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.Registration; import com.vaadin.shared.data.DataCommunicatorConstants; -import com.vaadin.shared.data.selection.SelectionServerRpc; import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.shared.ui.grid.ColumnState; import com.vaadin.shared.ui.grid.GridConstants; @@ -65,6 +64,7 @@ import com.vaadin.ui.Grid.FooterRow; import com.vaadin.ui.components.grid.Footer; import com.vaadin.ui.components.grid.Header; import com.vaadin.ui.components.grid.Header.Row; +import com.vaadin.ui.components.grid.SingleSelectionModel; import com.vaadin.ui.renderers.AbstractRenderer; import com.vaadin.ui.renderers.Renderer; import com.vaadin.ui.renderers.TextRenderer; @@ -83,7 +83,7 @@ import elemental.json.JsonValue; * @param <T> * the grid bean type */ -public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { +public class Grid<T> extends AbstractListing<T> implements HasComponents { @Deprecated private static final Method COLUMN_REORDER_METHOD = ReflectTools.findMethod( @@ -121,6 +121,27 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { } /** + * The server-side interface that controls Grid's selection state. + * SelectionModel should extend {@link AbstractGridExtension}. + * + * @param <T> + * the grid bean type + */ + public interface GridSelectionModel<T> + extends SelectionModel<T>, Extension { + + /** + * Removes this selection model from the grid. + * <p> + * Must call super {@link Extension#remove()} to detach the extension, + * and fire an selection change event for the selection model (with an + * empty selection). + */ + @Override + void remove(); + } + + /** * An event listener for column resize events in the Grid. */ @FunctionalInterface @@ -602,8 +623,8 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { .hasKey(diffStateKey) : "Field name has changed"; Type type = null; try { - type = (getState(false).getClass() - .getDeclaredField(diffStateKey).getGenericType()); + type = getState(false).getClass() + .getDeclaredField(diffStateKey).getGenericType(); } catch (NoSuchFieldException | SecurityException e) { e.printStackTrace(); } @@ -1488,163 +1509,6 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { } } - private final class SingleSelection implements Single<T> { - private T selectedItem = null; - - SingleSelection() { - addDataGenerator((item, json) -> { - if (isSelected(item)) { - json.put(DataCommunicatorConstants.SELECTED, true); - } - }); - registerRpc(new SelectionServerRpc() { - - @Override - public void select(String key) { - setSelectedFromClient(key); - } - - @Override - public void deselect(String key) { - if (isKeySelected(key)) { - setSelectedFromClient(null); - } - } - }); - } - - @Override - public Optional<T> getSelectedItem() { - return Optional.ofNullable(selectedItem); - } - - @Override - public void deselect(T item) { - Objects.requireNonNull(item, "deselected item cannot be null"); - if (isSelected(item)) { - setSelectedFromServer(null); - } - } - - @Override - public void select(T item) { - Objects.requireNonNull(item, "selected item cannot be null"); - setSelectedFromServer(item); - } - - /** - * Returns whether the given key maps to the currently selected item. - * - * @param key - * the key to test or {@code null} to test whether nothing is - * selected - * @return {@code true} if the key equals the key of the currently - * selected item (or {@code null} if no selection), - * {@code false} otherwise. - */ - protected boolean isKeySelected(String key) { - return Objects.equals(key, getSelectedKey()); - } - - /** - * Returns the communication key of the selected item or {@code null} if - * no item is selected. - * - * @return the key of the selected item if any, {@code null} otherwise. - */ - protected String getSelectedKey() { - return itemToKey(selectedItem); - } - - /** - * Sets the selected item based on the given communication key. If the - * key is {@code null}, clears the current selection if any. - * - * @param key - * the key of the selected item or {@code null} to clear - * selection - */ - protected void doSetSelectedKey(String key) { - if (selectedItem != null) { - getDataCommunicator().refresh(selectedItem); - } - selectedItem = keyToItem(key); - if (selectedItem != null) { - getDataCommunicator().refresh(selectedItem); - } - } - - /** - * Sets the selection based on a client request. Does nothing if the - * select component is {@linkplain Component#isReadOnly()} or if the - * selection would not change. Otherwise updates the selection and fires - * a selection change event with {@code isUserOriginated == true}. - * - * @param key - * the key of the item to select or {@code null} to clear - * selection - */ - protected void setSelectedFromClient(String key) { - if (isReadOnly()) { - return; - } - if (isKeySelected(key)) { - return; - } - - doSetSelectedKey(key); - fireEvent(new SingleSelectionChangeEvent<>(Grid.this, true)); - } - - /** - * Sets the selection based on server API call. Does nothing if the - * selection would not change; otherwise updates the selection and fires - * a selection change event with {@code isUserOriginated == false}. - * - * @param item - * the item to select or {@code null} to clear selection - */ - protected void setSelectedFromServer(T item) { - // TODO creates a key if item not in data source - String key = itemToKey(item); - - if (isKeySelected(key) || isSelected(item)) { - return; - } - - doSetSelectedKey(key); - fireEvent(new SingleSelectionChangeEvent<>(Grid.this, false)); - } - - /** - * Returns the communication key assigned to the given item. - * - * @param item - * the item whose key to return - * @return the assigned key - */ - protected String itemToKey(T item) { - if (item == null) { - return null; - } else { - // TODO creates a key if item not in data source - return getDataCommunicator().getKeyMapper().key(item); - } - } - - /** - * Returns the item that the given key is assigned to, or {@code null} - * if there is no such item. - * - * @param key - * the key whose item to return - * @return the associated item if any, {@code null} otherwise. - */ - protected T keyToItem(String key) { - return getDataCommunicator().getKeyMapper().get(key); - } - } - /** * A header row in a Grid. */ @@ -1835,17 +1699,18 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { private int counter = 0; - private Single<T> selectionModel; + private GridSelectionModel<T> selectionModel; /** * Constructor for the {@link Grid} component. */ public Grid() { - setSelectionModel(new SingleSelection()); registerRpc(new GridServerRpcImpl()); setDefaultHeaderRow(appendHeaderRow()); + selectionModel = new SingleSelectionModel<>(this); + detailsManager = new DetailsManager<>(); addExtension(detailsManager); addDataGenerator(detailsManager); @@ -2690,30 +2555,40 @@ public class Grid<T> extends AbstractSingleSelect<T> implements HasComponents { * * @return the selection model, not null */ - public Single<T> getSelectionModel() { + public GridSelectionModel<T> getSelectionModel() { assert selectionModel != null : "No selection model set by " + getClass().getName() + " constructor"; return selectionModel; } - @Override - public Optional<T> getSelectedItem() { - return getSelectionModel().getSelectedItem(); + /** + * Use this grid as a single select in {@link Binder}. + * <p> + * Sets the grid to single select mode, if not yet so. + * + * @return the single select wrapper that can be used in binder + */ + public SingleSelect<T> asSingleSelect() { + GridSelectionModel<T> model = getSelectionModel(); + if (!(model instanceof SingleSelectionModel)) { + model = new SingleSelectionModel<>(this); + setSelectionModel(model); + } + + return ((SingleSelectionModel<T>) model).asSingleSelect(); } /** * Sets the selection model for this listing. + * <p> + * The default selection model is {@link SingleSelectionModel}. * * @param model - * the selection model to use, not null + * the selection model to use, not {@code null} */ - protected void setSelectionModel(Single<T> model) { - if (selectionModel != null) { - throw new IllegalStateException( - "A selection model can't be changed."); - } - + protected void setSelectionModel(GridSelectionModel<T> model) { Objects.requireNonNull(model, "selection model cannot be null"); + selectionModel.remove(); selectionModel = model; } diff --git a/server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerSelect.java b/server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerSelect.java index ec200082ab..f762aae827 100644 --- a/server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerSelect.java +++ b/server/src/main/java/com/vaadin/ui/components/colorpicker/ColorPickerSelect.java @@ -62,7 +62,7 @@ public class ColorPickerSelect extends CustomField<Color> { range.setWidth("100%"); range.addValueChangeListener(this::valueChange); - range.select(ColorRange.ALL); + range.setValue(ColorRange.ALL); layout.addComponent(range); @@ -90,20 +90,20 @@ public class ColorPickerSelect extends CustomField<Color> { for (int row = 0; row < rows; row++) { for (int col = 0; col < columns; col++) { - if (row < (rows - 1)) { + if (row < rows - 1) { // Create the color grid by varying the saturation and value // Calculate new hue value - float hue = ((float) col / (float) columns); + float hue = (float) col / (float) columns; float saturation = 1f; float value = 1f; // For the upper half use value=1 and variable // saturation - if (row < (rows / 2)) { - saturation = ((row + 1f) / (rows / 2f)); + if (row < rows / 2) { + saturation = (row + 1f) / (rows / 2f); } else { - value = 1f - ((row - (rows / 2f)) / (rows / 2f)); + value = 1f - (row - rows / 2f) / (rows / 2f); } colors[row][col] = new Color( @@ -112,7 +112,7 @@ public class ColorPickerSelect extends CustomField<Color> { // The last row should have the black&white gradient float hue = 0f; float saturation = 0f; - float value = 1f - ((float) col / (float) columns); + float value = 1f - (float) col / (float) columns; colors[row][col] = new Color( Color.HSVtoRGB(hue, saturation, value)); @@ -151,13 +151,11 @@ public class ColorPickerSelect extends CustomField<Color> { saturation = 1f; value = 1f; - if (index <= ((rows * columns) / 2)) { - saturation = index - / (((float) rows * (float) columns) / 2f); + if (index <= rows * columns / 2) { + saturation = index / ((float) rows * (float) columns / 2f); } else { - index -= ((rows * columns) / 2); - value = 1f - - index / (((float) rows * (float) columns) / 2f); + index -= rows * columns / 2; + value = 1f - index / ((float) rows * (float) columns / 2f); } colors[row][col] = new Color( diff --git a/server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModel.java b/server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModel.java new file mode 100644 index 0000000000..bf2f55648e --- /dev/null +++ b/server/src/main/java/com/vaadin/ui/components/grid/SingleSelectionModel.java @@ -0,0 +1,299 @@ +/* + * 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.components.grid; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +import com.vaadin.data.SelectionModel; +import com.vaadin.event.selection.SingleSelectionEvent; +import com.vaadin.event.selection.SingleSelectionListener; +import com.vaadin.shared.Registration; +import com.vaadin.shared.data.DataCommunicatorConstants; +import com.vaadin.shared.data.selection.SelectionServerRpc; +import com.vaadin.ui.Component; +import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.AbstractGridExtension; +import com.vaadin.ui.Grid.GridSelectionModel; +import com.vaadin.ui.SingleSelect; +import com.vaadin.util.ReflectTools; + +import elemental.json.JsonObject; + +/** + * Single selection model for grid. + * + * @author Vaadin Ltd. + * @since 8.0 + * + * @param <T> + * the type of the selected item in grid. + */ +public class SingleSelectionModel<T> extends AbstractGridExtension<T> + implements GridSelectionModel<T>, SelectionModel.Single<T> { + + private static final Method SELECTION_CHANGE_METHOD = ReflectTools + .findMethod(SingleSelectionListener.class, "accept", + SingleSelectionEvent.class); + + private final Grid<T> grid; + private T selectedItem = null; + + /** + * Constructs a new single selection model for the given grid. + * + * @param grid + * the grid to bind the selection model into + */ + public SingleSelectionModel(Grid<T> grid) { + this.grid = grid; + extend(grid); + registerRpc(new SelectionServerRpc() { + + @Override + public void select(String key) { + setSelectedFromClient(key); + } + + @Override + public void deselect(String key) { + if (isKeySelected(key)) { + setSelectedFromClient(null); + } + } + }); + } + + /** + * Adds a selection change listener to this select. The listener is called + * when the value of this select is changed either by the user or + * programmatically. + * + * @param listener + * the value change listener, not null + * @return a registration for the listener + */ + public Registration addSelectionChangeListener( + SingleSelectionListener<T> listener) { + addListener(SingleSelectionEvent.class, listener, + SELECTION_CHANGE_METHOD); + return () -> removeListener(SingleSelectionEvent.class, listener); + } + + @Override + public Optional<T> getSelectedItem() { + return Optional.ofNullable(selectedItem); + } + + @Override + public void deselect(T item) { + Objects.requireNonNull(item, "deselected item cannot be null"); + if (isSelected(item)) { + setSelectedFromServer(null); + } + } + + @Override + public void select(T item) { + Objects.requireNonNull(item, "selected item cannot be null"); + setSelectedFromServer(item); + } + + /** + * Returns whether the given key maps to the currently selected item. + * + * @param key + * the key to test or {@code null} to test whether nothing is + * selected + * @return {@code true} if the key equals the key of the currently selected + * item (or {@code null} if no selection), {@code false} otherwise. + */ + protected boolean isKeySelected(String key) { + return Objects.equals(key, getSelectedKey()); + } + + /** + * Returns the communication key of the selected item or {@code null} if no + * item is selected. + * + * @return the key of the selected item if any, {@code null} otherwise. + */ + protected String getSelectedKey() { + return itemToKey(selectedItem); + } + + /** + * Sets the selected item based on the given communication key. If the key + * is {@code null}, clears the current selection if any. + * + * @param key + * the key of the selected item or {@code null} to clear + * selection + */ + protected void doSetSelectedKey(String key) { + if (selectedItem != null) { + grid.getDataCommunicator().refresh(selectedItem); + } + selectedItem = getData(key); + if (selectedItem != null) { + grid.getDataCommunicator().refresh(selectedItem); + } + } + + /** + * Sets the selection based on a client request. Does nothing if the select + * component is {@linkplain Component#isReadOnly()} or if the selection + * would not change. Otherwise updates the selection and fires a selection + * change event with {@code isUserOriginated == true}. + * + * @param key + * the key of the item to select or {@code null} to clear + * selection + */ + protected void setSelectedFromClient(String key) { + if (isKeySelected(key)) { + return; + } + + doSetSelectedKey(key); + fireEvent( + new SingleSelectionEvent<>(grid, asSingleSelect(), true)); + } + + /** + * Sets the selection based on server API call. Does nothing if the + * selection would not change; otherwise updates the selection and fires a + * selection change event with {@code isUserOriginated == false}. + * + * @param item + * the item to select or {@code null} to clear selection + */ + protected void setSelectedFromServer(T item) { + // TODO creates a key if item not in data source + String key = itemToKey(item); + + if (isSelected(item) || isKeySelected(key)) { + return; + } + + doSetSelectedKey(key); + fireEvent(new SingleSelectionEvent<>(grid, asSingleSelect(), + false)); + } + + /** + * Returns the communication key assigned to the given item. + * + * @param item + * the item whose key to return + * @return the assigned key + */ + protected String itemToKey(T item) { + if (item == null) { + return null; + } else { + // TODO creates a key if item not in data source + return grid.getDataCommunicator().getKeyMapper().key(item); + } + } + + @Override + public Set<T> getSelectedItems() { + if (selectedItem != null) { + return new HashSet<>(Arrays.asList(selectedItem)); + } else { + return Collections.emptySet(); + } + } + + @Override + public void generateData(T item, JsonObject jsonObject) { + if (isSelected(item)) { + jsonObject.put(DataCommunicatorConstants.SELECTED, true); + } + } + + @Override + public void remove() { + // when selection model changes, firing an event for selection change + // event fired before removing so that parent is still intact (in case + // needed) + selectedItem = null; + fireEvent(new SingleSelectionEvent<>(grid, asSingleSelect(), + false)); + + super.remove(); + } + + /** + * Gets a wrapper for using this grid as a single select in a binder. + * + * @return a single select wrapper for grid + */ + public SingleSelect<T> asSingleSelect() { + return new SingleSelect<T>() { + + @Override + public void setValue(T value) { + SingleSelectionModel.this.setSelectedFromServer(value); + } + + @Override + public T getValue() { + return SingleSelectionModel.this.getSelectedItem().orElse(null); + } + + @Override + public Registration addValueChangeListener( + com.vaadin.data.HasValue.ValueChangeListener<T> listener) { + return SingleSelectionModel.this.addSelectionChangeListener( + event -> listener.accept(event)); + } + + @Override + public void setRequiredIndicatorVisible( + boolean requiredIndicatorVisible) { + // TODO support required indicator when grid is used in binder ? + throw new UnsupportedOperationException( + "Required indicator is not supported for Grid."); + } + + @Override + public boolean isRequiredIndicatorVisible() { + throw new UnsupportedOperationException( + "Required indicator is not supported for Grid."); + } + + @Override + public void setReadOnly(boolean readOnly) { + // TODO support read only when grid is used in binder ? + throw new UnsupportedOperationException( + "Read only is not supported for Grid."); + } + + @Override + public boolean isReadOnly() { + throw new UnsupportedOperationException( + "Read only is not supported for Grid."); + } + }; + } +}
\ No newline at end of file |