public static class Column<T, V> extends AbstractExtension {
private final ValueProvider<T, V> valueProvider;
+ private ValueProvider<V, ?> presentationProvider;
private SortOrderProvider sortOrderProvider = direction -> {
String id = getId();
assert communicationId != null : "No communication ID set for column "
+ state.caption;
- @SuppressWarnings("unchecked")
- Renderer<V> renderer = (Renderer<V>) state.renderer;
-
JsonObject obj = getDataObject(jsonObject,
DataCommunicatorConstants.DATA);
- V providerValue = valueProvider.apply(item);
-
- // Make Grid track components.
- if (renderer instanceof ComponentRenderer
- && providerValue instanceof Component) {
- addComponent(item, (Component) providerValue);
- }
- JsonValue rendererValue = renderer.encode(providerValue);
-
- obj.put(communicationId, rendererValue);
+ obj.put(communicationId, generateRendererValue(item,
+ presentationProvider, state.renderer));
String style = styleGenerator.apply(item);
if (style != null && !style.isEmpty()) {
* the function to get values from items, not
* <code>null</code>
* @param renderer
- * the type of value, not <code>null</code>
+ * the value renderer, not <code>null</code>
*/
protected Column(ValueProvider<T, V> valueProvider,
Renderer<? super V> renderer) {
+ this(valueProvider, ValueProvider.identity(), renderer);
+ }
+
+ /**
+ * Constructs a new Column configuration with given renderer and value
+ * provider.
+ * <p>
+ * For a more complete explanation on presentation provider, see
+ * {@link #setRenderer(ValueProvider, Renderer)}.
+ *
+ * @param valueProvider
+ * the function to get values from items, not
+ * <code>null</code>
+ * @param presentationProvider
+ * the function to get presentations from the value of this
+ * column, not <code>null</code>. For more details, see {@link #setRenderer(ValueProvider, Renderer)}
+ * @param renderer
+ * the presentation renderer, not <code>null</code>
+ * @param <P>
+ * the presentation type
+ *
+ * @since 8.1
+ */
+ protected <P> Column(ValueProvider<T, V> valueProvider,
+ ValueProvider<V, P> presentationProvider,
+ Renderer<? super P> renderer) {
Objects.requireNonNull(valueProvider,
"Value provider can't be null");
+ Objects.requireNonNull(presentationProvider,
+ "Presentation provider can't be null");
Objects.requireNonNull(renderer, "Renderer can't be null");
ColumnState state = getState();
this.valueProvider = valueProvider;
- state.renderer = renderer;
+ this.presentationProvider = presentationProvider;
+ state.renderer = renderer;
state.caption = "";
// Add the renderer as a child extension of this extension, thus
// removed
addExtension(renderer);
- Class<? super V> valueType = renderer.getPresentationType();
+ Class<? super P> valueType = renderer.getPresentationType();
if (Comparable.class.isAssignableFrom(valueType)) {
comparator = (a, b) -> compareComparables(
}
}
+ @SuppressWarnings("unchecked")
+ private <P> JsonValue generateRendererValue(T item,
+ ValueProvider<V, P> presentationProvider, Connector renderer) {
+ P presentationValue = presentationProvider
+ .apply(valueProvider.apply(item));
+
+ // Make Grid track components.
+ if (renderer instanceof ComponentRenderer
+ && presentationValue instanceof Component) {
+ addComponent(item, (Component) presentationValue);
+ }
+ return ((Renderer<P>) renderer).encode(presentationValue);
+ }
+
private void addComponent(T item, Component component) {
if (activeComponents.containsKey(item)) {
if (activeComponents.get(item).equals(component)) {
* @since 8.0.3
*/
public Column<T, V> setRenderer(Renderer<? super V> renderer) {
- Objects.requireNonNull(renderer, "Renderer can't be null");
+ return setRenderer(ValueProvider.identity(), renderer);
+ }
+
+ /**
+ * Sets the Renderer for this Column. Setting the renderer will cause
+ * all currently available row data to be recreated and sent to the
+ * client.
+ * <p>
+ * The presentation provider is a method that takes the value of this
+ * column on a single row, and maps that to a value that the renderer
+ * accepts. This feature can be used for storing a complex value in a
+ * column for editing, but providing a simplified presentation for the
+ * user when not editing.
+ *
+ * @param presentationProvider
+ * the function to get presentations from the value of this
+ * column, not {@code null}
+ * @param renderer
+ * the new renderer, not {@code null}
+ *
+ * @param <P>
+ * the presentation type
+ *
+ * @return this column
+ *
+ * @since 8.1
+ */
+ public <P> Column<T, V> setRenderer(
+ ValueProvider<V, P> presentationProvider,
+ Renderer<? super P> renderer) {
+ Objects.requireNonNull(renderer, "Renderer can not be null");
+ Objects.requireNonNull(presentationProvider,
+ "Presentation provider can not be null");
// Remove old renderer
Connector oldRenderer = getState().renderer;
// Set new renderer
getState().renderer = renderer;
addExtension(renderer);
+ this.presentationProvider = presentationProvider;
// Trigger redraw
getGrid().getDataCommunicator().reset();
* @return the renderer
* @since 8.1
*/
- public Renderer<? super V> getRenderer() {
- return (Renderer<? super V>) getState().renderer;
+ public Renderer<?> getRenderer() {
+ return (Renderer<?>) getState().renderer;
}
/**
* @return the grid that this column belongs to, or <code>null</code> if
* this column has not yet been associated with any grid
*/
+ @SuppressWarnings("unchecked")
protected Grid<T> getGrid() {
return (Grid<T>) getParent();
}
* @param valueProvider
* the value provider
* @param renderer
- * the column value class
+ * the column value renderer
* @param <V>
* the column value type
*
*/
public <V> Column<T, V> addColumn(ValueProvider<T, V> valueProvider,
AbstractRenderer<? super T, ? super V> renderer) {
+ return addColumn(valueProvider, ValueProvider.identity(), renderer);
+ }
+
+ /**
+ * Adds a new column to this {@link Grid} with value provider and
+ * presentation provider.
+ * <p>
+ * <strong>Note:</strong> The presentation type for this method is set to be
+ * String. To use any custom renderer with the presentation provider, use
+ * {@link #addColumn(ValueProvider, ValueProvider, AbstractRenderer)}.
+ *
+ * @param valueProvider
+ * the value provider
+ * @param presentationProvider
+ * the value presentation provider
+ * @param <V>
+ * the column value type
+ *
+ * @see #addColumn(ValueProvider, ValueProvider, AbstractRenderer)
+ *
+ * @return the new column
+ * @since 8.1
+ */
+ public <V> Column<T, V> addColumn(ValueProvider<T, V> valueProvider,
+ ValueProvider<V, String> presentationProvider) {
+ return addColumn(valueProvider, presentationProvider,
+ new TextRenderer());
+ }
+
+ /**
+ * Adds a new column to this {@link Grid} with value provider, presentation
+ * provider and typed renderer.
+ *
+ * <p>
+ * The presentation provider is a method that takes the value from the value
+ * provider, and maps that to a value that the renderer accepts. This
+ * feature can be used for storing a complex value in a column for editing,
+ * but providing a simplified presentation for the user when not editing.
+ *
+ * @param valueProvider
+ * the value provider
+ * @param presentationProvider
+ * the value presentation provider
+ * @param renderer
+ * the column value renderer
+ * @param <V>
+ * the column value type
+ * @param <P>
+ * the column presentation type
+ *
+ * @return the new column
+ *
+ * @see AbstractRenderer
+ * @since 8.1
+ */
+ public <V, P> Column<T, V> addColumn(ValueProvider<T, V> valueProvider,
+ ValueProvider<V, P> presentationProvider,
+ AbstractRenderer<? super T, ? super P> renderer) {
String generatedIdentifier = getGeneratedIdentifier();
- Column<T, V> column = createColumn(valueProvider, renderer);
+ Column<T, V> column = createColumn(valueProvider, presentationProvider,
+ renderer);
addColumn(generatedIdentifier, column);
return column;
}
}
/**
- * Creates a column instance from a value provider and a renderer.
+ * Creates a column instance from a value provider, presentation provider
+ * and a renderer.
*
* @param valueProvider
* the value provider
+ * @param presentationProvider
+ * the presentation provider
* @param renderer
* the renderer
* @return a new column instance
* @param <V>
* the column value type
+ * @param <P>
+ * the column presentation type
*
- * @since 8.0.3
+ * @since 8.1
*/
- protected <V> Column<T, V> createColumn(ValueProvider<T, V> valueProvider,
- AbstractRenderer<? super T, ? super V> renderer) {
- return new Column<>(valueProvider, renderer);
+ protected <V, P> Column<T, V> createColumn(
+ ValueProvider<T, V> valueProvider,
+ ValueProvider<V, P> presentationProvider,
+ AbstractRenderer<? super T, ? super P> renderer) {
+ return new Column<>(valueProvider, presentationProvider, renderer);
}
private void addColumn(String identifier, Column<T, ?> column) {
column = addColumn(id);
} else {
DeclarativeValueProvider<T> provider = new DeclarativeValueProvider<>();
- column = createColumn(provider, new HtmlRenderer());
+ column = createColumn(provider, ValueProvider.identity(),
+ new HtmlRenderer());
addColumn(getGeneratedIdentifier(), column);
if (id != null) {
column.setId(id);
--- /dev/null
+package com.vaadin.tests.components.grid;
+
+import com.vaadin.data.HasValue;
+import com.vaadin.server.ErrorMessage;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.Registration;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.tests.data.bean.Address;
+import com.vaadin.tests.data.bean.Person;
+import com.vaadin.ui.Composite;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.renderers.TextRenderer;
+
+/**
+ * An example for using a different value and presentation types in a Grid
+ * column.
+ */
+public class GridColumnPresentation extends AbstractTestUI {
+
+ /**
+ * Dummy HasValue for Address.
+ */
+ private static class AddressField extends Composite
+ implements HasValue<Address> {
+
+ Address address;
+ private Label label;
+
+ public AddressField() {
+ super();
+
+ label = new Label();
+ setCompositionRoot(label);
+ }
+
+ @Override
+ public void setValue(Address value) {
+ Address oldAddress = address;
+ address = value;
+ label.setValue(String.valueOf(address));
+ fireEvent(new ValueChangeEvent<>(this, oldAddress, false));
+ }
+
+ @Override
+ public Address getValue() {
+ return address;
+ }
+
+ @Override
+ public Registration addValueChangeListener(
+ ValueChangeListener<Address> listener) {
+ return addListener(ValueChangeEvent.class, listener,
+ ValueChangeListener.VALUE_CHANGE_METHOD);
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return super.isReadOnly();
+ }
+
+ @Override
+ public void setReadOnly(boolean readOnly) {
+ super.setReadOnly(readOnly);
+ }
+
+ @Override
+ public boolean isRequiredIndicatorVisible() {
+ return super.isRequiredIndicatorVisible();
+ }
+
+ @Override
+ public void setRequiredIndicatorVisible(boolean visible) {
+ super.setRequiredIndicatorVisible(visible);
+ }
+
+ @Override
+ public void setComponentError(ErrorMessage componentError) {
+ label.setComponentError(componentError);
+ }
+ }
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ Grid<Person> personGrid = new Grid<>();
+ personGrid.setItems(Person.createTestPerson1(),
+ Person.createTestPerson2());
+ personGrid.addColumn(Person::getAddress)
+ .setRenderer(
+ address -> address.getCity() + " "
+ + address.getCountry().name(),
+ new TextRenderer())
+ .setCaption("Address")
+ .setEditorComponent(new AddressField(), Person::setAddress);
+ personGrid.getEditor().setEnabled(true);
+ addComponent(personGrid);
+ }
+
+}