Browse Source

Refactor editor API to use Binding instead of a component generator (#8368)

Fixes #8366
tags/8.0.0.beta2
Leif Åstrand 7 years ago
parent
commit
839c37a6cc

+ 15
- 18
documentation/components/components-grid.asciidoc View File

@@ -692,11 +692,12 @@ editor. In the editor, the input fields can be edited, as well as navigated with
kbd:[Tab] and kbd:[Shift+Tab] keys. If validation fails, an error is displayed and the user
can correct the inputs.

The [classname]#Editor# is accessible via [methodname]#getEditor()#, and to enable editing, you need to call [methodname]#setEnabled(true) on it.
The [classname]#Editor# is accessible via [methodname]#getEditor()#, and to enable editing, you need to call [methodname]#setEnabled(true)# on it.

The editor is based on [classname]#Binder# which is used to bind the data
to the editor. See <<dummy/../../../framework/datamodel/datamodel-forms.asciidoc#datamodel.forms.beans,"Binding Beans to Forms">> for more information on setting up field components and validation by using [classname]#Binder.
The [classname]#Binder# needs to be set with [methodname]#setBinder# in [classname]#Editor#.
The editor is based on [classname]#Binder# which is used to bind the data to the editor.
See <<dummy/../../../framework/datamodel/datamodel-forms.asciidoc#datamodel.forms.beans,"Binding Beans to Forms">> for more information on setting up field components and validation by using [classname]#Binder#.
For each column that should be editable, a binding should be created in the editor binder and then the column is configured to use that binding.
For simple cases where no conversion or validation is needed, it is also possible to directly use `setEditorComponent` on a `Column` to only define the editor component and a setter that updates the row object when saving.

[source, java]
----
@@ -707,26 +708,22 @@ Grid<Todo> grid = new Grid<>();

TextField taskField = new TextField();
CheckBox doneField = new CheckBox();
Binder<Todo> binder = new Binder<>();

binder.bind(taskField, Todo::getTask, Todo::setTask);
binder.bind(doneField, Todo::isDone, Todo::setDone);
Binder<Todo> binder = grid.getEditor().getBinder();

grid.getEditor().setBinder(binder);
grid.getEditor().setEnabled(true);
Binding<Todo, Boolean> doneBinding = binder.bind(
doneField, Todo::isDone, Todo::setDone);

Column<Todo, String> column = grid
.addColumn(todo -> String.valueOf(todo.isDone()));
Column<Todo, String> column = grid.addColumn(
todo -> String.valueOf(todo.isDone()));
column.setWidth(75);
column.setEditorComponent(doneField);

grid.addColumn(Todo::getTask).setEditorComponent(taskField);
----
column.setEditorBinding(doneBinding);

It is possible to customize the used editor component for each column and row,
by using [methodname]#setEditorComponentGenerator(EditorComponentGenerator)# in
[classname]#Column#.
grid.addColumn(Todo::getTask).setEditorComponent(
taskField, Todo::setTask).setExpandRatio(1);

grid.getEditor().setEnabled(true);
----

[[components.grid.editing.buffered]]
=== Buffered / Unbuffered Mode

+ 120
- 75
server/src/main/java/com/vaadin/ui/Grid.java View File

@@ -42,7 +42,9 @@ import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.vaadin.data.Binder;
import com.vaadin.data.Binder.Binding;
import com.vaadin.data.HasDataProvider;
import com.vaadin.data.HasValue;
import com.vaadin.data.ValueProvider;
import com.vaadin.data.provider.DataCommunicator;
import com.vaadin.data.provider.DataProvider;
@@ -63,6 +65,7 @@ import com.vaadin.server.Extension;
import com.vaadin.server.JsonCodec;
import com.vaadin.server.SerializableComparator;
import com.vaadin.server.SerializableFunction;
import com.vaadin.server.Setter;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.Registration;
import com.vaadin.shared.data.DataCommunicatorConstants;
@@ -84,7 +87,6 @@ import com.vaadin.ui.components.grid.ColumnVisibilityChangeListener;
import com.vaadin.ui.components.grid.DescriptionGenerator;
import com.vaadin.ui.components.grid.DetailsGenerator;
import com.vaadin.ui.components.grid.Editor;
import com.vaadin.ui.components.grid.EditorComponentGenerator;
import com.vaadin.ui.components.grid.EditorImpl;
import com.vaadin.ui.components.grid.Footer;
import com.vaadin.ui.components.grid.FooterCell;
@@ -560,8 +562,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,

assert columnInternalIds.length == directions.length : "Column and sort direction counts don't match.";

List<GridSortOrder<T>> list = new ArrayList<>(
directions.length);
List<GridSortOrder<T>> list = new ArrayList<>(directions.length);
for (int i = 0; i < columnInternalIds.length; ++i) {
Column<T, ?> column = columnKeys.get(columnInternalIds[i]);
list.add(new GridSortOrder<>(column, directions[i]));
@@ -784,7 +785,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
private StyleGenerator<T> styleGenerator = item -> null;
private DescriptionGenerator<T> descriptionGenerator;

private EditorComponentGenerator<T> componentGenerator;
private Binding<T, ?> editorBinding;

private String userId;

@@ -793,12 +794,13 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
* provider.
*
* @param valueProvider
* the function to get values from items
* the function to get values from items, not
* <code>null</code>
* @param renderer
* the type of value
* the type of value, not <code>null</code>
*/
protected Column(ValueProvider<T, ? extends V> valueProvider,
Renderer<V> renderer) {
Renderer<V> renderer) {
Objects.requireNonNull(valueProvider,
"Value provider can't be null");
Objects.requireNonNull(renderer, "Renderer can't be null");
@@ -819,7 +821,8 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
Class<V> valueType = renderer.getPresentationType();

if (Comparable.class.isAssignableFrom(valueType)) {
comparator = (a, b) -> compareComparables(valueProvider.apply(a), valueProvider.apply(b));
comparator = (a, b) -> compareComparables(
valueProvider.apply(a), valueProvider.apply(b));
state.sortable = true;
} else if (Number.class.isAssignableFrom(valueType)) {
/*
@@ -827,7 +830,8 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
* Provide explicit comparison support in this case even though
* Number itself isn't Comparable.
*/
comparator = (a, b) -> compareNumbers((Number) valueProvider.apply(a),
comparator = (a, b) -> compareNumbers(
(Number) valueProvider.apply(a),
(Number) valueProvider.apply(b));
state.sortable = true;
} else {
@@ -837,7 +841,8 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,

@SuppressWarnings("unchecked")
private static int compareComparables(Object a, Object b) {
return ((Comparator) Comparator.nullsLast(Comparator.naturalOrder())).compare(a, b);
return ((Comparator) Comparator
.nullsLast(Comparator.naturalOrder())).compare(a, b);
}

@SuppressWarnings("unchecked")
@@ -845,17 +850,20 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
Number valueA = a != null ? a : Double.POSITIVE_INFINITY;
Number valueB = b != null ? b : Double.POSITIVE_INFINITY;
// Most Number implementations are Comparable
if (valueA instanceof Comparable && valueA.getClass().isInstance(valueB)) {
if (valueA instanceof Comparable
&& valueA.getClass().isInstance(valueB)) {
return ((Comparable<Number>) valueA).compareTo(valueB);
} else if (valueA.equals(valueB)) {
return 0;
} else {
// Fall back to comparing based on potentially truncated values
int compare = Long.compare(valueA.longValue(), valueB.longValue());
int compare = Long.compare(valueA.longValue(),
valueB.longValue());
if (compare == 0) {
// This might still produce 0 even though the values are not
// equals, but there's nothing more we can do about that
compare = Double.compare(valueA.doubleValue(), valueB.doubleValue());
compare = Double.compare(valueA.doubleValue(),
valueB.doubleValue());
}
return compare;
}
@@ -979,7 +987,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
"Column identifier cannot be changed");
}
this.userId = id;
getParent().setColumnId(id, this);
getGrid().setColumnId(id, this);
return this;
}

@@ -1018,7 +1026,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
Objects.requireNonNull(caption, "Header caption can't be null");
getState().caption = caption;

HeaderRow row = getParent().getDefaultHeaderRow();
HeaderRow row = getGrid().getDefaultHeaderRow();
if (row != null) {
row.getCell(this).setText(caption);
}
@@ -1128,7 +1136,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
Objects.requireNonNull(cellStyleGenerator,
"Cell style generator must not be null");
this.styleGenerator = cellStyleGenerator;
getParent().getDataCommunicator().reset();
getGrid().getDataCommunicator().reset();
return this;
}

@@ -1154,7 +1162,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
public Column<T, V> setDescriptionGenerator(
DescriptionGenerator<T> cellDescriptionGenerator) {
this.descriptionGenerator = cellDescriptionGenerator;
getParent().getDataCommunicator().reset();
getGrid().getDataCommunicator().reset();
return this;
}

@@ -1202,7 +1210,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
checkColumnIsAttached();
if (expandRatio != getExpandRatio()) {
getState().expandRatio = expandRatio;
getParent().markAsDirty();
getGrid().markAsDirty();
}
return this;
}
@@ -1267,8 +1275,8 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
}
if (pixelWidth != getWidth()) {
getState().width = pixelWidth;
getParent().markAsDirty();
getParent().fireColumnResizeEvent(this, false);
getGrid().markAsDirty();
getGrid().fireColumnResizeEvent(this, false);
}
return this;
}
@@ -1297,8 +1305,8 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
checkColumnIsAttached();
if (!isWidthUndefined()) {
getState().width = -1;
getParent().markAsDirty();
getParent().fireColumnResizeEvent(this, false);
getGrid().markAsDirty();
getGrid().fireColumnResizeEvent(this, false);
}
return this;
}
@@ -1324,7 +1332,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
+ maxwidth + ")");
}
getState().minWidth = pixels;
getParent().markAsDirty();
getGrid().markAsDirty();
return this;
}

@@ -1361,7 +1369,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
}

getState().maxWidth = pixels;
getParent().markAsDirty();
getGrid().markAsDirty();
return this;
}

@@ -1389,7 +1397,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
checkColumnIsAttached();
if (resizable != isResizable()) {
getState().resizable = resizable;
getParent().markAsDirty();
getGrid().markAsDirty();
}
return this;
}
@@ -1444,8 +1452,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
checkColumnIsAttached();
if (hidden != isHidden()) {
getState().hidden = hidden;
getParent().fireColumnVisibilityChangeEvent(this, hidden,
false);
getGrid().fireColumnVisibilityChangeEvent(this, hidden, false);
}
return this;
}
@@ -1511,17 +1518,19 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,

/**
* Sets whether this Column has a component displayed in Editor or not.
* A column can only be editable if an editor component or binding has
* been set.
*
* @param editable
* {@code true} if column is editable; {@code false} if not
* @return this column
*
* @see #setEditorComponent(Component)
* @see #setEditorComponentGenerator(EditorComponentGenerator)
* @see #setEditorComponent(HasValue, Setter)
* @see #setEditorBinding(Binding)
*/
public Column<T, V> setEditable(boolean editable) {
Objects.requireNonNull(componentGenerator,
"Column has no editor component defined");
Objects.requireNonNull(editorBinding,
"Column has no editor binding or component defined");
getState().editable = editable;
return this;
}
@@ -1537,56 +1546,91 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
}

/**
* Sets a static editor component for this column.
* Sets an editor binding for this column. The {@link Binding} is used
* when a row is in editor mode to define how to populate an editor
* component based on the edited row and how to update an item based on
* the value in the editor component.
* <p>
* <strong>Note:</strong> The same component cannot be used for multiple
* columns.
* To create a binding to use with a column, define a binding for the
* editor binder (<code>grid.getEditor().getBinder()</code>) using e.g.
* {@link Binder#forField(HasValue)}. You can also use
* {@link #setEditorComponent(HasValue, Setter)} if no validator or
* converter is needed for the binding.
* <p>
* The {@link HasValue} that the binding is defined to use must be a
* {@link Component}.
*
* @param component
* the editor component
* @param binding
* the binding to use for this column
* @return this column
*
* @see #setEditorComponent(HasValue, Setter)
* @see Binding
* @see Grid#getEditor()
* @see Editor#getBinder()
* @see Editor#setBinder(Binder)
* @see #setEditorComponentGenerator(EditorComponentGenerator)
*/
public Column<T, V> setEditorComponent(Component component) {
Objects.requireNonNull(component,
"null is not a valid editor field");
return setEditorComponentGenerator(t -> component);
public Column<T, V> setEditorBinding(Binding<T, ?> binding) {
Objects.requireNonNull(binding, "null is not a valid editor field");

if (!(binding.getField() instanceof Component)) {
throw new IllegalArgumentException(
"Binding target must be a component.");
}

this.editorBinding = binding;

return setEditable(true);
}

/**
* Sets a component generator to provide an editor component for this
* Column. This method can be used to generate any dynamic component to
* be displayed in the editor row.
* Gets the binder binding that is currently used for this column.
*
* @return the used binder binding, or <code>null</code> if no binding
* is configured
*
* @see #setEditorBinding(Binding)
*/
public Binding<T, ?> getEditorBinding() {
return editorBinding;
}

/**
* Sets a component and setter to use for editing values of this column
* in the editor row. This is a shorthand for use in simple cases where
* no validator or converter is needed. Use
* {@link #setEditorBinding(Binding)} to support more complex cases.
* <p>
* <strong>Note:</strong> The same component cannot be used for multiple
* columns.
*
* @param componentGenerator
* the editor component generator
* @param editorComponent
* the editor component
* @param setter
* a setter that stores the component value in the row item
* @return this column
*
* @see EditorComponentGenerator
* @see #setEditorComponent(Component)
* @see Grid#getEditor()
*/
public Column<T, V> setEditorComponentGenerator(
EditorComponentGenerator<T> componentGenerator) {
Objects.requireNonNull(componentGenerator);
this.componentGenerator = componentGenerator;
return setEditable(true);
public <C extends HasValue<V> & Component> Column<T, V> setEditorComponent(
C editorComponent, Setter<T, V> setter) {
Objects.requireNonNull(editorComponent,
"Editor component cannot be null");
Objects.requireNonNull(setter, "Setter cannot be null");

Binding<T, V> binding = getGrid().getEditor().getBinder()
.bind(editorComponent, valueProvider::apply, setter);

return setEditorBinding(binding);
}

/**
* Gets the editor component generator for this Column.
*
* @return editor component generator
* Gets the grid that this column belongs to.
*
* @see EditorComponentGenerator
* @return the grid that this column belongs to, or <code>null</code> if
* this column has not yet been associated with any grid
*/
public EditorComponentGenerator<T> getEditorComponentGenerator() {
return componentGenerator;
protected Grid<T> getGrid() {
return getParent();
}

/**
@@ -1597,7 +1641,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
* if the column is no longer attached to any grid
*/
protected void checkColumnIsAttached() throws IllegalStateException {
if (getParent() == null) {
if (getGrid() == null) {
throw new IllegalStateException(
"Column is no longer attached to a grid.");
}
@@ -1621,7 +1665,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
ColumnState defaultState = new ColumnState();

if (getId() == null) {
setId("column" + getParent().getColumns().indexOf(this));
setId("column" + getGrid().getColumns().indexOf(this));
}

DesignAttributeHandler.writeAttribute("column-id", attributes,
@@ -1672,6 +1716,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
* @param designContext
* the design context
*/
@SuppressWarnings("unchecked")
protected void readDesign(Element design, DesignContext designContext) {
Attributes attributes = design.attributes();

@@ -1690,9 +1735,10 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
* inline data type. It will work incorrectly for other types
* but we don't support them anyway.
*/
setEditorComponentGenerator(item -> new TextField(
Optional.ofNullable(valueProvider.apply(item))
.map(Object::toString).orElse("")));
setEditorComponent((HasValue<V> & Component) new TextField(),
(item, value) -> {
// Ignore user value since we don't know the setter
});
setEditable(DesignAttributeHandler.readAttribute("editable",
attributes, boolean.class));
}
@@ -1840,7 +1886,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,

/**
* Creates a new {@code Grid} using the given caption
*
*
* @param caption
* the caption of the grid
*/
@@ -1852,7 +1898,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
/**
* Creates a new {@code Grid} using the given caption and
* {@code DataProvider}
*
*
* @param caption
* the caption of the grid
* @param dataProvider
@@ -1865,7 +1911,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,

/**
* Creates a new {@code Grid} using the given {@code DataProvider}
*
*
* @param dataProvider
* the data provider, not {@code null}
*/
@@ -1877,7 +1923,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
/**
* Creates a new {@code Grid} using the given caption and collection of
* items
*
*
* @param caption
* the caption of the grid
* @param items
@@ -2833,9 +2879,8 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
*
*/
public void sort(Column<T, ?> column, SortDirection direction) {
setSortOrder(
Collections
.singletonList(new GridSortOrder<>(column, direction)));
setSortOrder(Collections
.singletonList(new GridSortOrder<>(column, direction)));
}

/**
@@ -3287,9 +3332,9 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,

protected SerializableComparator<T> createSortingComparator() {
BinaryOperator<SerializableComparator<T>> operator = (comparator1,
comparator2) -> SerializableComparator
.asInstance((Comparator<T> & Serializable) comparator1
.thenComparing(comparator2));
comparator2) -> SerializableComparator
.asInstance((Comparator<T> & Serializable) comparator1
.thenComparing(comparator2));
return sortOrder.stream().map(
order -> order.getSorted().getComparator(order.getDirection()))
.reduce((x, y) -> 0, operator);

+ 0
- 45
server/src/main/java/com/vaadin/ui/components/grid/EditorComponentGenerator.java View File

@@ -1,45 +0,0 @@
/*
* 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 com.vaadin.server.SerializableFunction;
import com.vaadin.ui.Component;

/**
* A callback interface for generating an editor component corresponding to an
* editable column of a grid. The generated component will be used in the grid
* editor to edit the value of the column for the selected grid row.
*
* @author Vaadin Ltd.
* @since 8.0
*
* @param <BEAN>
* the bean type this generator is compatible with
*/
@FunctionalInterface
public interface EditorComponentGenerator<BEAN>
extends SerializableFunction<BEAN, Component> {

/**
* Gets a component for a given {@code bean}.
*
* @param bean
* the bean this component will be used to edit
* @return the generated component
*/
@Override
public Component apply(BEAN bean);
}

+ 7
- 2
server/src/main/java/com/vaadin/ui/components/grid/EditorImpl.java View File

@@ -24,6 +24,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.vaadin.data.Binder;
import com.vaadin.data.Binder.Binding;
import com.vaadin.data.BinderValidationStatus;
import com.vaadin.data.BinderValidationStatusHandler;
import com.vaadin.shared.ui.grid.editor.EditorClientRpc;
@@ -216,8 +217,12 @@ public class EditorImpl<T> extends AbstractGridExtension<T>

getParent().getColumns().stream().filter(Column::isEditable)
.forEach(c -> {
Component component = c.getEditorComponentGenerator()
.apply(edited);
Binding<T, ?> binding = c.getEditorBinding();

assert binding
.getField() instanceof Component : "Grid should enforce that the binding field is a component";

Component component = (Component) binding.getField();
addComponentToGrid(component);
columnFields.put(c, component);
getState().columnFields.put(getInternalIdForColumn(c),

+ 2
- 1
server/src/test/java/com/vaadin/tests/server/component/grid/GridDeclarativeTest.java View File

@@ -37,6 +37,7 @@ import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.Column;
import com.vaadin.ui.Grid.SelectionMode;
import com.vaadin.ui.Label;
import com.vaadin.ui.TextField;
import com.vaadin.ui.components.grid.FooterCell;
import com.vaadin.ui.components.grid.FooterRow;
import com.vaadin.ui.components.grid.HeaderCell;
@@ -175,7 +176,7 @@ public class GridDeclarativeTest extends AbstractListingDeclarativeTest<Grid> {
boolean sortable = false;
column1.setSortable(sortable);
boolean editable = true;
column1.setEditorComponentGenerator(component -> null);
column1.setEditorComponent(new TextField(), Person::setLastName);
column1.setEditable(editable);
boolean resizable = false;
column1.setResizable(resizable);

+ 8
- 7
uitest/src/main/java/com/vaadin/tests/components/grid/GridCheckBoxDisplay.java View File

@@ -20,6 +20,7 @@ import java.util.Arrays;
import java.util.List;

import com.vaadin.data.Binder;
import com.vaadin.data.Binder.Binding;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractReindeerTestUI;
import com.vaadin.ui.CheckBox;
@@ -41,21 +42,21 @@ public class GridCheckBoxDisplay extends AbstractReindeerTestUI {

TextField taskField = new TextField();
CheckBox doneField = new CheckBox();
Binder<Todo> binder = new Binder<>();

binder.bind(taskField, Todo::getTask, Todo::setTask);
binder.bind(doneField, Todo::isDone, Todo::setDone);
Binder<Todo> binder = grid.getEditor().getBinder();

grid.getEditor().setBinder(binder);
grid.getEditor().setEnabled(true);
Binding<Todo, Boolean> doneBinding = binder.bind(doneField,
Todo::isDone, Todo::setDone);

Column<Todo, String> column = grid
.addColumn(todo -> String.valueOf(todo.isDone()));
column.setWidth(75);
column.setEditorComponent(doneField);
column.setEditorBinding(doneBinding);

grid.addColumn(Todo::getTask).setExpandRatio(1)
.setEditorComponent(taskField);
.setEditorComponent(taskField, Todo::setTask);

grid.getEditor().setEnabled(true);

grid.setSelectionMode(Grid.SelectionMode.SINGLE);


+ 1
- 1
uitest/src/main/java/com/vaadin/tests/components/grid/GridEditingWithNoScrollBars.java View File

@@ -41,7 +41,7 @@ public class GridEditingWithNoScrollBars extends AbstractTestUI {
stCombo.setEmptySelectionAllowed(false);
stCombo.setSizeFull();

column.setEditorComponent(stCombo);
column.setEditorComponent(stCombo, Person::setLastName);

grid.setSelectionMode(SelectionMode.SINGLE);
grid.getEditor().setEnabled(true);

+ 16
- 36
uitest/src/main/java/com/vaadin/tests/components/grid/GridEditorCustomField.java View File

@@ -15,11 +15,7 @@
*/
package com.vaadin.tests.components.grid;

import java.util.HashSet;
import java.util.Set;

import com.vaadin.annotations.Theme;
import com.vaadin.data.Binder;
import com.vaadin.data.provider.ListDataProvider;
import com.vaadin.data.provider.Query;
import com.vaadin.server.VaadinRequest;
@@ -42,52 +38,36 @@ public class GridEditorCustomField extends AbstractTestUIWithLog {

@Override
protected void setup(VaadinRequest request) {
Grid<ComplexPerson> grid = createGrid();

ListDataProvider<ComplexPerson> dataProvider = ComplexPerson
.createDataProvider(100);

grid.setDataProvider(dataProvider);

Set<String> cities = new HashSet<>();
dataProvider.fetch(new Query<>()).forEach(person -> {
cities.add(person.getAddress().getCity());
});
CustomCitySelect cityEditor = new CustomCitySelect(
cities.toArray(new String[cities.size()]));
String[] cities = dataProvider.fetch(new Query<>())
.map(person -> person.getAddress().getCity()).distinct()
.toArray(String[]::new);
CustomCitySelect cityEditor = new CustomCitySelect(cities);

TextField firstNameField = new TextField();
TextField lastNameField = new TextField();
Binder<ComplexPerson> binder = new Binder<>();

binder.bind(firstNameField, ComplexPerson::getFirstName,
ComplexPerson::setFirstName);
binder.bind(lastNameField, ComplexPerson::getLastName,
ComplexPerson::setLastName);
binder.bind(cityEditor, person -> person.getAddress().getCity(),
(person, city) -> person.getAddress().setCity(city));

grid.getEditor().setBinder(binder);
grid.getColumn(ADDRESS_CITY_IDENTIFIER).setEditorComponent(cityEditor);
grid.getColumn(FIRST_NAME_IDENTIFIER)
.setEditorComponent(firstNameField);
grid.getColumn(LAST_NAME_IDENTIFIER).setEditorComponent(lastNameField);

addComponent(grid);
}

private Grid<ComplexPerson> createGrid() {
Grid<ComplexPerson> grid = new Grid<>();
grid.setWidth("800px");
grid.addColumn(person -> person.getFirstName())
.setId(FIRST_NAME_IDENTIFIER).setCaption("First Name");
.setId(FIRST_NAME_IDENTIFIER).setCaption("First Name")
.setEditorComponent(firstNameField,
ComplexPerson::setFirstName);
grid.addColumn(person -> person.getLastName())
.setId(LAST_NAME_IDENTIFIER).setCaption("Last Name");
.setId(LAST_NAME_IDENTIFIER).setCaption("Last Name")
.setEditorComponent(lastNameField, ComplexPerson::setLastName);
grid.addColumn(person -> person.getAddress().getCity())
.setId(ADDRESS_CITY_IDENTIFIER).setCaption("City Name");
.setId(ADDRESS_CITY_IDENTIFIER).setCaption("City Name")
.setEditorComponent(cityEditor,
(person, city) -> person.getAddress().setCity(city));

grid.getEditor().setEnabled(true);

return grid;
grid.setDataProvider(dataProvider);

addComponent(grid);
}

public static class CustomCitySelect extends CustomField<String> {

+ 6
- 8
uitest/src/main/java/com/vaadin/tests/components/grid/GridEditorMultiselect.java View File

@@ -3,6 +3,7 @@ package com.vaadin.tests.components.grid;
import java.util.stream.IntStream;

import com.vaadin.data.Binder;
import com.vaadin.data.Binder.Binding;
import com.vaadin.data.converter.StringToIntegerConverter;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
@@ -24,17 +25,14 @@ public class GridEditorMultiselect extends AbstractTestUI {
.addColumn(Person::getAge, new NumberRenderer())
.setCaption("age");

Binder<Person> binder = new Binder<>();
grid.getEditor().setBinder(binder);
Binder<Person> binder = grid.getEditor().getBinder();

TextField name = new TextField();
nameColumn.setEditorComponent(name);
binder.bind(name, Person::getFirstName, Person::setFirstName);
nameColumn.setEditorComponent(new TextField(), Person::setFirstName);

TextField age = new TextField();
ageColumn.setEditorComponent(age);
binder.forField(age).withConverter(new StringToIntegerConverter(""))
Binding<Person, Integer> ageBinding = binder.forField(new TextField())
.withConverter(new StringToIntegerConverter(""))
.bind(Person::getAge, Person::setAge);
ageColumn.setEditorBinding(ageBinding);

grid.setItems(IntStream.range(0, 30).mapToObj(this::createPerson));


+ 3
- 11
uitest/src/main/java/com/vaadin/tests/components/grid/GridEditorUI.java View File

@@ -19,7 +19,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;

import com.vaadin.data.Binder;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.tests.util.Person;
@@ -67,9 +66,6 @@ public class GridEditorUI extends AbstractTestUI {
protected Grid<Person> createGrid() {
Grid<Person> grid = new Grid<>();

Binder<Person> binder = new Binder<>();
grid.getEditor().setBinder(binder);

grid.addColumn(Person::getEmail).setCaption("Email");
Column<Person, String> fistNameColumn = grid
.addColumn(Person::getFirstName).setCaption("First Name");
@@ -88,19 +84,15 @@ public class GridEditorUI extends AbstractTestUI {
grid.getEditor().setEnabled(true);

PasswordField passwordField = new PasswordField();
fistNameColumn.setEditorComponent(passwordField);
binder.bind(passwordField, Person::getFirstName, Person::setFirstName);
fistNameColumn.setEditorComponent(passwordField, Person::setFirstName);

TextField lastNameEditor = new TextField();
lastNameColumn.setEditorComponent(lastNameEditor);
lastNameColumn.setEditorComponent(lastNameEditor, Person::setLastName);
lastNameEditor.setMaxLength(50);
binder.bind(lastNameEditor, Person::getLastName, Person::setLastName);

TextField phoneEditor = new TextField();
phoneEditor.setReadOnly(true);
phoneColumn.setEditorComponent(phoneEditor);
binder.bind(phoneEditor, Person::getPhoneNumber,
Person::setPhoneNumber);
phoneColumn.setEditorComponent(phoneEditor, Person::setPhoneNumber);

return grid;
}

+ 12
- 9
uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java View File

@@ -16,6 +16,7 @@ import java.util.stream.Stream;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Widgetset;
import com.vaadin.data.Binder;
import com.vaadin.data.Binder.Binding;
import com.vaadin.data.converter.StringToIntegerConverter;
import com.vaadin.event.selection.MultiSelectionEvent;
import com.vaadin.event.selection.SingleSelectionEvent;
@@ -199,38 +200,40 @@ public class GridBasics extends AbstractTestUIWithLog {
TextField coordinates = new TextField();
TextField rowNumber = new TextField();

binder.bind(html, DataObject::getHtmlString, DataObject::setHtmlString);
binder.forField(smallRandom)
Binding<DataObject, Integer> smallRandomBinding = binder
.forField(smallRandom)
.withConverter(new StringToIntegerConverter(
"Could not convert value to Integer"))
.withValidator(i -> i >= 0 && i < 5,
"Small random needs to be in range [0..5)")
.bind(DataObject::getSmallRandom, DataObject::setSmallRandom);
binder.bind(coordinates, DataObject::getCoordinates,
DataObject::setCoordinates);
binder.forField(rowNumber)
Binding<DataObject, Integer> rowNumberBinding = binder
.forField(rowNumber)
.withConverter(new StringToIntegerConverter(
"Could not convert value to Integer"))
.bind(DataObject::getRowNumber, DataObject::setRowNumber);

grid.addColumn(DataObject::getCoordinates)
.setCaption(COLUMN_CAPTIONS[0]).setEditorComponent(coordinates);
.setCaption(COLUMN_CAPTIONS[0])
.setEditorComponent(coordinates, DataObject::setCoordinates);
grid.addColumn(dataObj -> "(" + dataObj.getRowNumber() + ", 1)")
.setCaption(COLUMN_CAPTIONS[1]);
grid.addColumn(dataObj -> "(" + dataObj.getRowNumber() + ", 2)")
.setCaption(COLUMN_CAPTIONS[2]);

grid.addColumn(DataObject::getRowNumber, new NumberRenderer())
.setCaption(COLUMN_CAPTIONS[3]).setEditorComponent(rowNumber);
.setCaption(COLUMN_CAPTIONS[3])
.setEditorBinding(rowNumberBinding);
grid.addColumn(DataObject::getDate, new DateRenderer())
.setCaption(COLUMN_CAPTIONS[4]);
grid.addColumn(DataObject::getHtmlString, new HtmlRenderer())
.setCaption(COLUMN_CAPTIONS[5]).setEditorComponent(html);
.setCaption(COLUMN_CAPTIONS[5])
.setEditorComponent(html, DataObject::setHtmlString);
grid.addColumn(DataObject::getBigRandom, new NumberRenderer())
.setCaption(COLUMN_CAPTIONS[6]);
grid.addColumn(data -> data.getSmallRandom() / 5d,
new ProgressBarRenderer()).setCaption(COLUMN_CAPTIONS[7])
.setEditorComponent(smallRandom);
.setEditorBinding(smallRandomBinding);

selectionListenerRegistration = ((SingleSelectionModelImpl<DataObject>) grid
.getSelectionModel())

Loading…
Cancel
Save