diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-11-25 13:56:36 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2016-11-28 11:31:40 +0000 |
commit | 411b8dedb02be7ed1a9332fc1f965e583bd313cc (patch) | |
tree | 1de234c9343b5bd5ac524ee465b69669024f79de /server/src/main/java/com | |
parent | 24c541c32ce83aff9c4217f5dd9fff1fa816c13e (diff) | |
download | vaadin-framework-411b8dedb02be7ed1a9332fc1f965e583bd313cc.tar.gz vaadin-framework-411b8dedb02be7ed1a9332fc1f965e583bd313cc.zip |
Type Listing for DataProvider to allow custom filter types
Listing has been moved from AbstractListing to each individual Component.
ComboBox is now typed to String filter.
Fixes issues with declarative read of items.
Change-Id: I6918f9f8c426dcbd81546150c2cf9ed49a02bf50
Diffstat (limited to 'server/src/main/java/com')
12 files changed, 185 insertions, 68 deletions
diff --git a/server/src/main/java/com/vaadin/data/Listing.java b/server/src/main/java/com/vaadin/data/Listing.java index 8f94296057..527c913912 100644 --- a/server/src/main/java/com/vaadin/data/Listing.java +++ b/server/src/main/java/com/vaadin/data/Listing.java @@ -27,16 +27,19 @@ import com.vaadin.server.data.DataProvider; * * @param <T> * the item data type + * @param <D> + * the data provider type; used to provide constraints on the data + * provider and filter * @since 8.0 */ -public interface Listing<T> extends Serializable { +public interface Listing<T, D extends DataProvider<T, ?>> extends Serializable { /** * Returns the source of data items used by this listing. * * @return the data provider, not null */ - DataProvider<T, ?> getDataProvider(); + D getDataProvider(); /** * Sets the data provider for this listing. The data provider is queried for @@ -45,27 +48,39 @@ public interface Listing<T> extends Serializable { * @param dataProvider * the data provider, not null */ - void setDataProvider(DataProvider<T, ?> dataProvider); + void setDataProvider(D dataProvider); /** * Sets the collection of data items of this listing. + * <p> + * <strong>Note for component developers: </strong> If the component + * implementing this interface uses a custom data provider and/or filter + * types, this method should be overridden to provide the same functionality + * with the correct data provider type. This might require filter conversion + * or a completely custom implementation. * * @param items * the data items to display, not null * */ default void setItems(Collection<T> items) { - setDataProvider(DataProvider.create(items)); + setDataProvider((D) DataProvider.create(items)); } /** * Sets the data items of this listing. + * <p> + * <strong>Note for component developers: </strong> If the component + * implementing this interface uses a custom data provider and/or filter + * types, this method should be overridden to provide the same functionality + * with the correct data provider type. This might require filter conversion + * or a completely custom implementation. * * @param items * the data items to display */ default void setItems(@SuppressWarnings("unchecked") T... items) { - setDataProvider(DataProvider.create(items)); + setDataProvider((D) DataProvider.create(items)); } } diff --git a/server/src/main/java/com/vaadin/server/data/DataCommunicator.java b/server/src/main/java/com/vaadin/server/data/DataCommunicator.java index fbafff6845..88624cee22 100644 --- a/server/src/main/java/com/vaadin/server/data/DataCommunicator.java +++ b/server/src/main/java/com/vaadin/server/data/DataCommunicator.java @@ -47,6 +47,9 @@ import elemental.json.JsonObject; * {@link JsonObject}s representing each data object to be sent to the * client-side. * + * @param <T> + * the bean type + * * @since 8.0 */ public class DataCommunicator<T> extends AbstractExtension { @@ -179,7 +182,9 @@ public class DataCommunicator<T> extends AbstractExtension { private final Collection<DataGenerator<T>> generators = new LinkedHashSet<>(); private final ActiveDataHandler handler = new ActiveDataHandler(); - private DataProvider<T, ?> dataProvider = DataProvider.create(); + /** Empty default data provider */ + private DataProvider<T, ?> dataProvider = new BackEndDataProvider<>( + q -> Stream.of(), q -> 0); private final DataKeyMapper<T> keyMapper; private boolean reset = false; @@ -506,7 +511,7 @@ public class DataCommunicator<T> extends AbstractExtension { * When component is disabled then client cannot communicate to the server * side (by design, because of security reasons). It means that client will * get <b>only</b> initial chunk of data whose size is set here. - * + * * @param size * the size of initial data to send to the client */ @@ -520,9 +525,9 @@ public class DataCommunicator<T> extends AbstractExtension { /** * Get minimum size of data which will be sent to the client when data * source is set. - * + * * @see #setMinPushSize(int) - * + * * @return current minimum push size of initial data chunk which is sent to * the client when data source is set */ diff --git a/server/src/main/java/com/vaadin/ui/AbstractListing.java b/server/src/main/java/com/vaadin/ui/AbstractListing.java index ce44bb8352..8578b18673 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractListing.java +++ b/server/src/main/java/com/vaadin/ui/AbstractListing.java @@ -15,7 +15,6 @@ */ package com.vaadin.ui; -import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -38,16 +37,19 @@ import com.vaadin.ui.declarative.DesignFormatter; /** * A base class for listing components. Provides common handling for fetching * backend data items, selection logic, and server-client communication. + * <p> + * <strong>Note: </strong> concrete component implementations should implement + * the {@link Listing} interface. * * @author Vaadin Ltd. + * @since 8.0 * * @param <T> * the item data type * - * @since 8.0 + * @see Listing */ -public abstract class AbstractListing<T> extends AbstractComponent - implements Listing<T> { +public abstract class AbstractListing<T> extends AbstractComponent { /** * The item icon caption provider. */ @@ -153,13 +155,11 @@ public abstract class AbstractListing<T> extends AbstractComponent addExtension(dataCommunicator); } - @Override - public void setDataProvider(DataProvider<T, ?> dataProvider) { + protected void internalSetDataProvider(DataProvider<T, ?> dataProvider) { getDataCommunicator().setDataProvider(dataProvider); } - @Override - public DataProvider<T, ?> getDataProvider() { + protected DataProvider<T, ?> internalGetDataProvider() { return getDataCommunicator().getDataProvider(); } @@ -277,7 +277,7 @@ public abstract class AbstractListing<T> extends AbstractComponent * the DesignContext instance used in writing */ protected void writeItems(Element design, DesignContext context) { - getDataProvider().fetch(new Query<>()) + internalGetDataProvider().fetch(new Query<>()) .forEach(item -> writeItem(design, item, context)); } @@ -321,21 +321,27 @@ public abstract class AbstractListing<T> extends AbstractComponent setReadOnly(DesignAttributeHandler.readAttribute("readonly", attr, Boolean.class)); } - readItems(design, context); + + setItemCaptionGenerator(new DeclarativeCaptionGenerator<>()); + setItemIconGenerator(new DeclarativeIconGenerator<>()); + + List<T> readItems = readItems(design, context); + if (!readItems.isEmpty() && this instanceof Listing) { + ((Listing<T, ?>) this).setItems(readItems); + } } /** * Reads the data source items from the {@code design}. - * + * * @param design * The element to obtain the state from * @param context * The DesignContext instance used for parsing the design + * + * @return the items read from the design */ - protected void readItems(Element design, DesignContext context) { - setItemCaptionGenerator(new DeclarativeCaptionGenerator<>()); - setItemIconGenerator(new DeclarativeIconGenerator<>()); - } + protected abstract List<T> readItems(Element design, DesignContext context); /** * Reads an Item from a design and inserts it into the data source. @@ -361,13 +367,11 @@ public abstract class AbstractListing<T> extends AbstractComponent String serializedItem = ""; String caption = DesignFormatter.decodeFromTextNode(child.html()); - List<T> items = new ArrayList<>(); if (child.hasAttr("item")) { serializedItem = child.attr("item"); } T item = deserializeDeclarativeRepresentation(serializedItem); - items.add(item); ItemCaptionGenerator<T> captionGenerator = getItemCaptionGenerator(); if (captionGenerator instanceof DeclarativeCaptionGenerator) { @@ -403,9 +407,9 @@ public abstract class AbstractListing<T> extends AbstractComponent * Default implementation is able to handle only {@link String} as an item * type. There will be a {@link ClassCastException} if {@code T } is not a * {@link String}. - * + * * @see #serializeDeclarativeRepresentation(Object) - * + * * @param item * string to deserialize * @throws ClassCastException @@ -420,9 +424,9 @@ public abstract class AbstractListing<T> extends AbstractComponent * Serializes an {@code item} to a string for saving declarative format. * <p> * Default implementation delegates a call to {@code item.toString()}. - * + * * @see #serializeDeclarativeRepresentation(Object) - * + * * @param item * a data item * @return string representation of the {@code item}. diff --git a/server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java b/server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java index 5ae0ee4ebd..4bf1ce72e1 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java +++ b/server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -429,13 +430,14 @@ public abstract class AbstractMultiSelect<T> extends AbstractListing<T> } @Override - protected void readItems(Element design, DesignContext context) { - super.readItems(design, context); + protected List<T> readItems(Element design, DesignContext context) { Set<T> selected = new HashSet<>(); - design.children().stream() - .forEach(child -> readItem(child, selected, context)); + List<T> items = design.children().stream() + .map(child -> readItem(child, selected, context)) + .collect(Collectors.toList()); deselectAll(); selected.forEach(this::select); + return items; } /** diff --git a/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java b/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java index d2602746fe..0f2d6c81bc 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java +++ b/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java @@ -18,9 +18,11 @@ package com.vaadin.ui; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import org.jsoup.nodes.Element; @@ -326,12 +328,13 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T> } @Override - protected void readItems(Element design, DesignContext context) { - super.readItems(design, context); + protected List<T> readItems(Element design, DesignContext context) { Set<T> selected = new HashSet<>(); - design.children().stream() - .forEach(child -> readItem(child, selected, context)); + List<T> items = design.children().stream() + .map(child -> readItem(child, selected, context)) + .collect(Collectors.toList()); selected.forEach(this::setValue); + return items; } /** diff --git a/server/src/main/java/com/vaadin/ui/CheckBoxGroup.java b/server/src/main/java/com/vaadin/ui/CheckBoxGroup.java index 5098cca628..016b5ca392 100644 --- a/server/src/main/java/com/vaadin/ui/CheckBoxGroup.java +++ b/server/src/main/java/com/vaadin/ui/CheckBoxGroup.java @@ -17,6 +17,7 @@ package com.vaadin.ui; import java.util.Collection; +import java.util.List; import java.util.Set; import org.jsoup.nodes.Element; @@ -46,7 +47,7 @@ import com.vaadin.ui.declarative.DesignFormatter; * @since 8.0 */ public class CheckBoxGroup<T> extends AbstractMultiSelect<T> - implements FocusNotifier, BlurNotifier { + implements FocusNotifier, BlurNotifier, Listing<T, DataProvider<T, ?>> { /** * Constructs a new CheckBoxGroup with caption. @@ -178,9 +179,9 @@ public class CheckBoxGroup<T> extends AbstractMultiSelect<T> } @Override - protected void readItems(Element design, DesignContext context) { + protected List<T> readItems(Element design, DesignContext context) { setItemEnabledProvider(new DeclarativeItemEnabledProvider<>()); - super.readItems(design, context); + return super.readItems(design, context); } @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -222,4 +223,14 @@ public class CheckBoxGroup<T> extends AbstractMultiSelect<T> return elem; } + + @Override + public DataProvider<T, ?> getDataProvider() { + return internalGetDataProvider(); + } + + @Override + public void setDataProvider(DataProvider<T, ?> dataProvider) { + internalSetDataProvider(dataProvider); + } } diff --git a/server/src/main/java/com/vaadin/ui/ComboBox.java b/server/src/main/java/com/vaadin/ui/ComboBox.java index a932d60423..b9630766cb 100644 --- a/server/src/main/java/com/vaadin/ui/ComboBox.java +++ b/server/src/main/java/com/vaadin/ui/ComboBox.java @@ -19,6 +19,7 @@ package com.vaadin.ui; import java.io.Serializable; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -28,6 +29,7 @@ import java.util.function.Consumer; import org.jsoup.nodes.Element; import com.vaadin.data.HasValue; +import com.vaadin.data.Listing; import com.vaadin.event.FieldEvents; import com.vaadin.event.FieldEvents.BlurEvent; import com.vaadin.event.FieldEvents.BlurListener; @@ -60,8 +62,9 @@ import elemental.json.JsonObject; * @author Vaadin Ltd */ @SuppressWarnings("serial") -public class ComboBox<T> extends AbstractSingleSelect<T> implements HasValue<T>, - FieldEvents.BlurNotifier, FieldEvents.FocusNotifier { +public class ComboBox<T> extends AbstractSingleSelect<T> + implements HasValue<T>, FieldEvents.BlurNotifier, + FieldEvents.FocusNotifier, Listing<T, DataProvider<T, String>> { /** * Handler that adds a new item based on user input when the new items @@ -90,7 +93,7 @@ public class ComboBox<T> extends AbstractSingleSelect<T> implements HasValue<T>, /** * Sets a {@code style} for the {@code item}. - * + * * @param item * a data item * @param style @@ -203,21 +206,9 @@ public class ComboBox<T> extends AbstractSingleSelect<T> implements HasValue<T>, * collection of options, not null */ public ComboBox(String caption, Collection<T> options) { - this(caption, DataProvider.create(options)); - } - - /** - * Constructs a combo box with the given data provider. - * - * @param caption - * the caption to show in the containing layout, null for no - * caption - * @param dataProvider - * the data provider to use, not null - */ - public ComboBox(String caption, DataProvider<T, ?> dataProvider) { this(caption); - setDataProvider(dataProvider); + + setItems(options); } /** @@ -244,6 +235,22 @@ public class ComboBox<T> extends AbstractSingleSelect<T> implements HasValue<T>, }); } + @Override + public void setItems(Collection<T> items) { + DataProvider<T, String> provider = DataProvider.create(items) + .convertFilter(filterText -> item -> getFilter() + .apply(filterText, item)); + setDataProvider(provider); + } + + @Override + public void setItems(@SuppressWarnings("unchecked") T... items) { + DataProvider<T, String> provider = DataProvider.create(items) + .convertFilter(filterText -> item -> getFilter() + .apply(filterText, item)); + setDataProvider(provider); + } + /** * Gets the current placeholder text shown when the combo box would be * empty. @@ -577,9 +584,9 @@ public class ComboBox<T> extends AbstractSingleSelect<T> implements HasValue<T>, } @Override - protected void readItems(Element design, DesignContext context) { + protected List<T> readItems(Element design, DesignContext context) { setStyleGenerator(new DeclarativeStyleGenerator<>()); - super.readItems(design, context); + return super.readItems(design, context); } @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -603,4 +610,14 @@ public class ComboBox<T> extends AbstractSingleSelect<T> implements HasValue<T>, return item; } + @Override + public DataProvider<T, String> getDataProvider() { + return (DataProvider<T, String>) internalGetDataProvider(); + } + + @Override + public void setDataProvider(DataProvider<T, String> dataProvider) { + internalSetDataProvider(dataProvider); + } + } diff --git a/server/src/main/java/com/vaadin/ui/Grid.java b/server/src/main/java/com/vaadin/ui/Grid.java index 53e22a53d4..e6830f3b95 100644 --- a/server/src/main/java/com/vaadin/ui/Grid.java +++ b/server/src/main/java/com/vaadin/ui/Grid.java @@ -41,6 +41,7 @@ import org.jsoup.nodes.Element; import com.vaadin.data.Binder; import com.vaadin.data.BinderValidationStatus; +import com.vaadin.data.Listing; import com.vaadin.data.SelectionModel; import com.vaadin.event.ConnectorEvent; import com.vaadin.event.ContextClickEvent; @@ -51,6 +52,7 @@ import com.vaadin.server.JsonCodec; import com.vaadin.server.SerializableComparator; import com.vaadin.server.SerializableFunction; import com.vaadin.server.data.DataCommunicator; +import com.vaadin.server.data.DataProvider; import com.vaadin.server.data.SortOrder; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.Registration; @@ -90,7 +92,8 @@ import elemental.json.JsonValue; * @param <T> * the grid bean type */ -public class Grid<T> extends AbstractListing<T> implements HasComponents { +public class Grid<T> extends AbstractListing<T> + implements HasComponents, Listing<T, DataProvider<T, ?>> { @Deprecated private static final Method COLUMN_REORDER_METHOD = ReflectTools.findMethod( @@ -2976,8 +2979,19 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents { } @Override - protected void readItems(Element design, DesignContext context) { + protected List<T> readItems(Element design, DesignContext context) { // TODO see vaadin/framework8-issues#390 + return Collections.emptyList(); + } + + @Override + public DataProvider<T, ?> getDataProvider() { + return internalGetDataProvider(); + } + + @Override + public void setDataProvider(DataProvider<T, ?> dataProvider) { + internalSetDataProvider(dataProvider); } } diff --git a/server/src/main/java/com/vaadin/ui/ListSelect.java b/server/src/main/java/com/vaadin/ui/ListSelect.java index 00e0d9912d..8716bc4d05 100644 --- a/server/src/main/java/com/vaadin/ui/ListSelect.java +++ b/server/src/main/java/com/vaadin/ui/ListSelect.java @@ -17,6 +17,7 @@ package com.vaadin.ui; import java.util.Collection; +import com.vaadin.data.Listing; import com.vaadin.server.data.DataProvider; import com.vaadin.shared.ui.listselect.ListSelectState; @@ -29,7 +30,8 @@ import com.vaadin.shared.ui.listselect.ListSelectState; * @param <T> * item type */ -public class ListSelect<T> extends AbstractMultiSelect<T> { +public class ListSelect<T> extends AbstractMultiSelect<T> + implements Listing<T, DataProvider<T, ?>> { /** Default number of rows visible for select. */ // protected to allow javadoc linking @@ -121,4 +123,14 @@ public class ListSelect<T> extends AbstractMultiSelect<T> { protected ListSelectState getState(boolean markAsDirty) { return (ListSelectState) super.getState(markAsDirty); } + + @Override + public DataProvider<T, ?> getDataProvider() { + return internalGetDataProvider(); + } + + @Override + public void setDataProvider(DataProvider<T, ?> dataProvider) { + internalSetDataProvider(dataProvider); + } } diff --git a/server/src/main/java/com/vaadin/ui/NativeSelect.java b/server/src/main/java/com/vaadin/ui/NativeSelect.java index b68ea6c14d..e68dd4fad7 100644 --- a/server/src/main/java/com/vaadin/ui/NativeSelect.java +++ b/server/src/main/java/com/vaadin/ui/NativeSelect.java @@ -18,6 +18,7 @@ package com.vaadin.ui; import java.util.Collection; +import com.vaadin.data.Listing; import com.vaadin.event.FieldEvents.BlurEvent; import com.vaadin.event.FieldEvents.BlurListener; import com.vaadin.event.FieldEvents.BlurNotifier; @@ -43,7 +44,7 @@ import com.vaadin.shared.ui.nativeselect.NativeSelectState; * @see com.vaadin.ui.ComboBox */ public class NativeSelect<T> extends AbstractSingleSelect<T> - implements FocusNotifier, BlurNotifier { + implements FocusNotifier, BlurNotifier, Listing<T, DataProvider<T, ?>> { /** * Creates a new {@code NativeSelect} with an empty caption and no items. @@ -126,4 +127,14 @@ public class NativeSelect<T> extends AbstractSingleSelect<T> protected NativeSelectState getState(boolean markAsDirty) { return (NativeSelectState) super.getState(markAsDirty); } + + @Override + public DataProvider<T, ?> getDataProvider() { + return internalGetDataProvider(); + } + + @Override + public void setDataProvider(DataProvider<T, ?> dataProvider) { + internalSetDataProvider(dataProvider); + } } diff --git a/server/src/main/java/com/vaadin/ui/RadioButtonGroup.java b/server/src/main/java/com/vaadin/ui/RadioButtonGroup.java index 5ee3a7b807..325efd0457 100644 --- a/server/src/main/java/com/vaadin/ui/RadioButtonGroup.java +++ b/server/src/main/java/com/vaadin/ui/RadioButtonGroup.java @@ -17,6 +17,7 @@ package com.vaadin.ui; import java.util.Collection; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -53,7 +54,7 @@ import elemental.json.JsonObject; * @since 8.0 */ public class RadioButtonGroup<T> extends AbstractSingleSelect<T> - implements FocusNotifier, BlurNotifier { + implements FocusNotifier, BlurNotifier, Listing<T, DataProvider<T, ?>> { private SerializablePredicate<T> itemEnabledProvider = item -> true; @@ -247,9 +248,9 @@ public class RadioButtonGroup<T> extends AbstractSingleSelect<T> } @Override - protected void readItems(Element design, DesignContext context) { + protected List<T> readItems(Element design, DesignContext context) { setItemEnabledProvider(new DeclarativeItemEnabledProvider<>()); - super.readItems(design, context); + return super.readItems(design, context); } @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -291,4 +292,14 @@ public class RadioButtonGroup<T> extends AbstractSingleSelect<T> return elem; } + + @Override + public DataProvider<T, ?> getDataProvider() { + return internalGetDataProvider(); + } + + @Override + public void setDataProvider(DataProvider<T, ?> dataProvider) { + internalSetDataProvider(dataProvider); + } } diff --git a/server/src/main/java/com/vaadin/ui/TwinColSelect.java b/server/src/main/java/com/vaadin/ui/TwinColSelect.java index 2d6b97a99a..37b79a6bac 100644 --- a/server/src/main/java/com/vaadin/ui/TwinColSelect.java +++ b/server/src/main/java/com/vaadin/ui/TwinColSelect.java @@ -18,6 +18,7 @@ package com.vaadin.ui; import java.util.Collection; +import com.vaadin.data.Listing; import com.vaadin.server.data.DataProvider; import com.vaadin.shared.ui.twincolselect.TwinColSelectState; @@ -30,7 +31,8 @@ import com.vaadin.shared.ui.twincolselect.TwinColSelectState; * @param <T> * item type */ -public class TwinColSelect<T> extends AbstractMultiSelect<T> { +public class TwinColSelect<T> extends AbstractMultiSelect<T> + implements Listing<T, DataProvider<T, ?>> { /** * Constructs a new TwinColSelect. @@ -156,4 +158,14 @@ public class TwinColSelect<T> extends AbstractMultiSelect<T> { return (TwinColSelectState) super.getState(markAsDirty); } + @Override + public DataProvider<T, ?> getDataProvider() { + return internalGetDataProvider(); + } + + @Override + public void setDataProvider(DataProvider<T, ?> dataProvider) { + internalSetDataProvider(dataProvider); + } + } |