Skip to content

Commit

Permalink
Type Listing for DataProvider to allow custom filter types
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Teemu Suo-Anttila authored and Vaadin Code Review committed Nov 28, 2016
1 parent 24c541c commit 411b8de
Show file tree
Hide file tree
Showing 41 changed files with 342 additions and 165 deletions.
25 changes: 20 additions & 5 deletions server/src/main/java/com/vaadin/data/Listing.java
Expand Up @@ -27,16 +27,19 @@
*
* @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
Expand All @@ -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));
}

}
Expand Up @@ -47,6 +47,9 @@
* {@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 {
Expand Down Expand Up @@ -179,7 +182,9 @@ public void destroyData(T data) {
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;
Expand Down Expand Up @@ -506,7 +511,7 @@ public void setDataProvider(DataProvider<T, ?> dataProvider) {
* 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
*/
Expand All @@ -520,9 +525,9 @@ public void setMinPushSize(int size) {
/**
* 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
*/
Expand Down
46 changes: 25 additions & 21 deletions server/src/main/java/com/vaadin/ui/AbstractListing.java
Expand Up @@ -15,7 +15,6 @@
*/
package com.vaadin.ui;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

Expand All @@ -38,16 +37,19 @@
/**
* 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.
*/
Expand Down Expand Up @@ -153,13 +155,11 @@ protected AbstractListing(DataCommunicator<T> dataCommunicator) {
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();
}

Expand Down Expand Up @@ -277,7 +277,7 @@ public void writeDesign(Element design, DesignContext designContext) {
* 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));
}

Expand Down Expand Up @@ -321,21 +321,27 @@ public void readDesign(Element design, DesignContext context) {
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.
Expand All @@ -361,13 +367,11 @@ protected T readItem(Element child, DesignContext context) {

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) {
Expand Down Expand Up @@ -403,9 +407,9 @@ protected T readItem(Element child, DesignContext context) {
* 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
Expand All @@ -420,9 +424,9 @@ protected T deserializeDeclarativeRepresentation(String item) {
* 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}.
Expand Down
10 changes: 6 additions & 4 deletions server/src/main/java/com/vaadin/ui/AbstractMultiSelect.java
Expand Up @@ -20,6 +20,7 @@
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;
Expand Down Expand Up @@ -429,13 +430,14 @@ protected Element writeItem(Element design, T item, DesignContext context) {
}

@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;
}

/**
Expand Down
11 changes: 7 additions & 4 deletions server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java
Expand Up @@ -18,9 +18,11 @@
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;

Expand Down Expand Up @@ -326,12 +328,13 @@ protected Element writeItem(Element design, T item, DesignContext context) {
}

@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;
}

/**
Expand Down
17 changes: 14 additions & 3 deletions server/src/main/java/com/vaadin/ui/CheckBoxGroup.java
Expand Up @@ -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;
Expand Down Expand Up @@ -46,7 +47,7 @@
* @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.
Expand Down Expand Up @@ -178,9 +179,9 @@ public void removeBlurListener(BlurListener listener) {
}

@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" })
Expand Down Expand Up @@ -222,4 +223,14 @@ protected Element writeItem(Element design, T item, DesignContext context) {

return elem;
}

@Override
public DataProvider<T, ?> getDataProvider() {
return internalGetDataProvider();
}

@Override
public void setDataProvider(DataProvider<T, ?> dataProvider) {
internalSetDataProvider(dataProvider);
}
}

0 comments on commit 411b8de

Please sign in to comment.