Browse Source

Reimplement basic Grid renderers

Change-Id: Ic855143d23cc7735d00130806df45b6579ba0d5c
tags/8.0.0.alpha1
Leif Åstrand 7 years ago
parent
commit
3d3f12d92b
19 changed files with 1149 additions and 43 deletions
  1. 39
    0
      client/src/main/java/com/vaadin/client/connectors/grid/AbstractGridRendererConnector.java
  2. 22
    6
      client/src/main/java/com/vaadin/client/connectors/grid/ColumnConnector.java
  3. 33
    0
      client/src/main/java/com/vaadin/client/connectors/grid/DateRendererConnector.java
  4. 34
    0
      client/src/main/java/com/vaadin/client/connectors/grid/NumberRendererConnector.java
  5. 35
    0
      client/src/main/java/com/vaadin/client/connectors/grid/ProgressBarRendererConnector.java
  6. 35
    0
      client/src/main/java/com/vaadin/client/connectors/grid/TextRendererConnector.java
  7. 43
    0
      client/src/main/java/com/vaadin/client/connectors/grid/UnsafeHtmlRendererConnector.java
  8. 96
    24
      server/src/main/java/com/vaadin/ui/Grid.java
  9. 139
    0
      server/src/main/java/com/vaadin/ui/renderers/AbstractRenderer.java
  10. 238
    0
      server/src/main/java/com/vaadin/ui/renderers/DateRenderer.java
  11. 46
    0
      server/src/main/java/com/vaadin/ui/renderers/HtmlRenderer.java
  12. 205
    0
      server/src/main/java/com/vaadin/ui/renderers/NumberRenderer.java
  13. 45
    0
      server/src/main/java/com/vaadin/ui/renderers/ProgressBarRenderer.java
  14. 69
    0
      server/src/main/java/com/vaadin/ui/renderers/Renderer.java
  15. 47
    0
      server/src/main/java/com/vaadin/ui/renderers/TextRenderer.java
  16. 1
    1
      server/src/test/java/com/vaadin/tests/server/component/grid/GridTest.java
  17. 3
    0
      shared/src/main/java/com/vaadin/shared/ui/grid/ColumnState.java
  18. 16
    9
      uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java
  19. 3
    3
      uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridContentTest.java

+ 39
- 0
client/src/main/java/com/vaadin/client/connectors/grid/AbstractGridRendererConnector.java View File

@@ -0,0 +1,39 @@
/*
* 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.client.connectors.grid;

import com.vaadin.client.connectors.AbstractRendererConnector;

/**
* An abstract base class for renderer connectors. A renderer connector is used
* to link a client-side {@link Renderer} to a server-side
* {@link com.vaadin.client.renderers.Renderer Renderer}. As a connector, it can
* use the regular Vaadin RPC and shared state mechanism to pass additional
* state and information between the client and the server. This base class
* itself only uses the basic {@link com.vaadin.shared.communication.SharedState
* SharedState} and no RPC interfaces.
*
* @param <T>
* the presentation type of the renderer
*
* @since 7.4
* @author Vaadin Ltd
*/
public abstract class AbstractGridRendererConnector<T>
extends AbstractRendererConnector<T> {
// getRowKey and getColumnId will be needed here later on
}

+ 22
- 6
client/src/main/java/com/vaadin/client/connectors/grid/ColumnConnector.java View File

@@ -17,6 +17,7 @@ package com.vaadin.client.connectors.grid;

import com.vaadin.client.ServerConnector;
import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.connectors.AbstractRendererConnector;
import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.client.widgets.Grid.Column;
import com.vaadin.shared.data.DataCommunicatorConstants;
@@ -35,7 +36,7 @@ import elemental.json.JsonValue;
@Connect(com.vaadin.ui.Grid.Column.class)
public class ColumnConnector extends AbstractExtensionConnector {

private Column<JsonValue, JsonObject> column;
private Column<Object, JsonObject> column;

/* This parent is needed because it's no longer available in onUnregister */
private GridConnector parent;
@@ -43,15 +44,30 @@ public class ColumnConnector extends AbstractExtensionConnector {
@Override
protected void extend(ServerConnector target) {
parent = getParent();
column = new Column<JsonValue, JsonObject>() {
String columnId = getState().id;
column = new Column<Object, JsonObject>() {

@Override
public JsonValue getValue(JsonObject row) {
return row.getObject(DataCommunicatorConstants.DATA)
.get(getState().id);
public Object getValue(JsonObject row) {
final JsonObject rowData = row
.getObject(DataCommunicatorConstants.DATA);

if (rowData.hasKey(columnId)) {
final JsonValue columnValue = rowData.get(columnId);

return getRendererConnector().decode(columnValue);
}

return null;
}
};
getParent().addColumn(column, getState().id);
column.setRenderer(getRendererConnector().getRenderer());
getParent().addColumn(column, columnId);
}

@SuppressWarnings("unchecked")
private AbstractRendererConnector<Object> getRendererConnector() {
return (AbstractRendererConnector<Object>) getState().renderer;
}

@OnStateChange("caption")

+ 33
- 0
client/src/main/java/com/vaadin/client/connectors/grid/DateRendererConnector.java View File

@@ -0,0 +1,33 @@
/*
* 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.client.connectors.grid;

import com.vaadin.shared.ui.Connect;

/**
* A connector for {@link com.vaadin.ui.renderers.DateRenderer DateRenderer}.
* <p>
* The server-side Renderer operates on dates, but the data is serialized as a
* string, and displayed as-is on the client side. This is to be able to support
* the server's locale.
*
* @since 7.4
* @author Vaadin Ltd
*/
@Connect(com.vaadin.ui.renderers.DateRenderer.class)
public class DateRendererConnector extends TextRendererConnector {
// No implementation needed
}

+ 34
- 0
client/src/main/java/com/vaadin/client/connectors/grid/NumberRendererConnector.java View File

@@ -0,0 +1,34 @@
/*
* 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.client.connectors.grid;

import com.vaadin.shared.ui.Connect;

/**
* A connector for {@link com.vaadin.ui.renderers.NumberRenderer
* NumberRenderer}.
* <p>
* The server-side Renderer operates on numbers, but the data is serialized as a
* string, and displayed as-is on the client side. This is to be able to support
* the server's locale.
*
* @since 7.4
* @author Vaadin Ltd
*/
@Connect(com.vaadin.ui.renderers.NumberRenderer.class)
public class NumberRendererConnector extends TextRendererConnector {
// no implementation needed
}

+ 35
- 0
client/src/main/java/com/vaadin/client/connectors/grid/ProgressBarRendererConnector.java View File

@@ -0,0 +1,35 @@
/*
* 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.client.connectors.grid;

import com.vaadin.client.renderers.ProgressBarRenderer;
import com.vaadin.shared.ui.Connect;

/**
* A connector for {@link ProgressBarRenderer}.
*
* @since 7.4
* @author Vaadin Ltd
*/
@Connect(com.vaadin.ui.renderers.ProgressBarRenderer.class)
public class ProgressBarRendererConnector
extends AbstractGridRendererConnector<Double> {

@Override
public ProgressBarRenderer getRenderer() {
return (ProgressBarRenderer) super.getRenderer();
}
}

+ 35
- 0
client/src/main/java/com/vaadin/client/connectors/grid/TextRendererConnector.java View File

@@ -0,0 +1,35 @@
/*
* 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.client.connectors.grid;

import com.vaadin.client.renderers.TextRenderer;
import com.vaadin.shared.ui.Connect;

/**
* A connector for {@link TextRenderer}.
*
* @since 7.4
* @author Vaadin Ltd
*/
@Connect(com.vaadin.ui.renderers.TextRenderer.class)
public class TextRendererConnector
extends AbstractGridRendererConnector<String> {

@Override
public TextRenderer getRenderer() {
return (TextRenderer) super.getRenderer();
}
}

+ 43
- 0
client/src/main/java/com/vaadin/client/connectors/grid/UnsafeHtmlRendererConnector.java View File

@@ -0,0 +1,43 @@
/*
* 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.client.connectors.grid;

import com.vaadin.client.renderers.Renderer;
import com.vaadin.client.widget.grid.RendererCellReference;
import com.vaadin.shared.ui.Connect;

/**
* A connector for {@link UnsafeHtmlRenderer}
*
* @since 7.4
* @author Vaadin Ltd
*/
@Connect(com.vaadin.ui.renderers.HtmlRenderer.class)
public class UnsafeHtmlRendererConnector
extends AbstractGridRendererConnector<String> {

public static class UnsafeHtmlRenderer implements Renderer<String> {
@Override
public void render(RendererCellReference cell, String data) {
cell.getElement().setInnerHTML(data);
}
}

@Override
public UnsafeHtmlRenderer getRenderer() {
return (UnsafeHtmlRenderer) super.getRenderer();
}
}

+ 96
- 24
server/src/main/java/com/vaadin/ui/Grid.java View File

@@ -46,9 +46,12 @@ import com.vaadin.shared.ui.grid.GridConstants.Section;
import com.vaadin.shared.ui.grid.GridServerRpc;
import com.vaadin.shared.ui.grid.GridState;
import com.vaadin.shared.ui.grid.HeightMode;
import com.vaadin.ui.renderers.Renderer;
import com.vaadin.ui.renderers.TextRenderer;

import elemental.json.Json;
import elemental.json.JsonObject;
import elemental.json.JsonValue;

/**
* A grid component for displaying tabular data.
@@ -305,49 +308,99 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>>
public static class Column<T, V> extends AbstractExtension
implements DataGenerator<T> {

private Function<T, V> valueProvider;
private final Function<T, ? extends V> valueProvider;

private Function<SortDirection, Stream<SortOrder<String>>> sortOrderProvider;
private Comparator<T> comparator;

/**
* Constructs a new Column configuration with given header caption and
* value provider.
* Constructs a new Column configuration with given header caption,
* renderer and value provider.
*
* @param caption
* the header caption
* @param valueType
* the type of value
* @param valueProvider
* the function to get values from items
* @param renderer
* the type of value
*/
protected Column(String caption, Class<V> valueType,
Function<T, V> valueProvider) {
protected Column(String caption, Function<T, ? extends V> valueProvider,
Renderer<V> renderer) {
Objects.requireNonNull(caption, "Header caption can't be null");
Objects.requireNonNull(valueProvider,
"Value provider can't be null");
Objects.requireNonNull(valueType, "Value type can't be null");
Objects.requireNonNull(renderer, "Renderer can't be null");

ColumnState state = getState();

this.valueProvider = valueProvider;
getState().caption = caption;
state.renderer = renderer;

state.caption = caption;
sortOrderProvider = d -> Stream.of();

// Add the renderer as a child extension of this extension, thus
// ensuring the renderer will be unregistered when this column is
// removed
addExtension(renderer);

Class<V> valueType = renderer.getPresentationType();

if (Comparable.class.isAssignableFrom(valueType)) {
comparator = (a, b) -> {
@SuppressWarnings("unchecked")
Comparable<V> comp = (Comparable<V>) valueProvider.apply(a);
return comp.compareTo(valueProvider.apply(b));
};
getState().sortable = true;
state.sortable = true;
} else if (Number.class.isAssignableFrom(valueType)) {
/*
* Value type will be Number whenever using NumberRenderer.
* Provide explicit comparison support in this case even though
* Number itself isn't Comparable.
*/
comparator = (a, b) -> {
return compareNumbers((Number) valueProvider.apply(a),
(Number) valueProvider.apply(b));
};
state.sortable = true;
} else {
getState().sortable = false;
state.sortable = false;
}
}

@SuppressWarnings("unchecked")
private static int compareNumbers(Number a, Number b) {
assert a.getClass() == b.getClass();

// Most Number implementations are Comparable
if (a instanceof Comparable && a.getClass().isInstance(b)) {
return ((Comparable<Number>) a).compareTo(b);
} else if (a.equals(b)) {
return 0;
} else {
// Fall back to comparing based on potentially truncated values
int compare = Long.compare(a.longValue(), b.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(a.doubleValue(), b.doubleValue());
}
return compare;
}
}

@Override
public void generateData(T data, JsonObject jsonObject) {
assert getState(
false).id != null : "No communication ID set for column "
+ getState(false).caption;
ColumnState state = getState(false);

String communicationId = state.id;

assert communicationId != null : "No communication ID set for column "
+ state.caption;

@SuppressWarnings("unchecked")
Renderer<V> renderer = (Renderer<V>) state.renderer;

if (!jsonObject.hasKey(DataCommunicatorConstants.DATA)) {
jsonObject.put(DataCommunicatorConstants.DATA,
@@ -355,9 +408,12 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>>
}
JsonObject obj = jsonObject
.getObject(DataCommunicatorConstants.DATA);
// Since we dont' have renderers yet, use a dummy toString for
// data.
obj.put(getState(false).id, valueProvider.apply(data).toString());

V providerValue = valueProvider.apply(data);

JsonValue rendererValue = renderer.encode(providerValue);

obj.put(communicationId, rendererValue);
}

@Override
@@ -538,23 +594,23 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>>
}

/**
* Adds a new column to this {@link Grid} with given header caption and
* value provider.
* Adds a new column to this {@link Grid} with given header caption,
* renderer and value provider.
*
* @param caption
* the header caption
* @param valueType
* the column value class
* @param valueProvider
* the value provider
* @param renderer
* the column value class
* @param <V>
* the column value type
*
* @return the new column
*/
public <V> Column<T, V> addColumn(String caption, Class<V> valueType,
Function<T, V> valueProvider) {
Column<T, V> c = new Column<>(caption, valueType, valueProvider);
public <V> Column<T, V> addColumn(String caption, Function<T, ? extends V> valueProvider,
Renderer<V> renderer) {
Column<T, V> c = new Column<>(caption, valueProvider, renderer);

c.extend(this);
c.setId(columnKeys.key(c));
@@ -564,6 +620,22 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>>
return c;
}

/**
* Adds a new text column to this {@link Grid} with given header caption
* string value provider. The column will use a {@link TextRenderer}.
*
* @param caption
* the header caption
* @param valueProvider
* the value provider
*
* @return the new column
*/
public Column<T, String> addColumn(String caption,
Function<T, String> valueProvider) {
return addColumn(caption, valueProvider, new TextRenderer());
}

/**
* Removes the given column from this {@link Grid}.
*

+ 139
- 0
server/src/main/java/com/vaadin/ui/renderers/AbstractRenderer.java View File

@@ -0,0 +1,139 @@
/*
* 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.renderers;

import java.util.Objects;

import com.vaadin.server.AbstractClientConnector;
import com.vaadin.server.AbstractExtension;
import com.vaadin.server.JsonCodec;
import com.vaadin.ui.Grid.Column;

import elemental.json.JsonValue;

/**
* An abstract base class for server-side
* {@link com.vaadin.ui.renderers.Renderer Grid renderers}. This class currently
* extends the AbstractExtension superclass, but this fact should be regarded as
* an implementation detail and subject to change in a future major or minor
* Vaadin version.
*
* @param <T>
* the type this renderer knows how to present
*/
public abstract class AbstractRenderer<T> extends AbstractExtension
implements Renderer<T> {
private final Class<T> presentationType;

private final String nullRepresentation;

/**
* Creates a new renderer with the given presentation type and null
* representation.
*
* @param presentationType
* the data type that this renderer displays, not
* <code>null</code>
* @param nullRepresentation
* a string that will be sent to the client instead of a regular
* value in case the actual cell value is <code>null</code>. May
* be <code>null</code>.
*/
protected AbstractRenderer(Class<T> presentationType,
String nullRepresentation) {
Objects.requireNonNull(presentationType,
"Presentation type cannot be null");
this.presentationType = presentationType;
this.nullRepresentation = nullRepresentation;
}

/**
* Creates a new renderer with the given presentation type. No null
* representation will be used.
*
* @param presentationType
* the data type that this renderer displays, not
* <code>null</code>
*/
protected AbstractRenderer(Class<T> presentationType) {
this(presentationType, null);
}

/**
* This method is inherited from AbstractExtension but should never be
* called directly with an AbstractRenderer.
*/
@Deprecated
@Override
@SuppressWarnings("rawtypes")
protected Class<Column> getSupportedParentType() {
return Column.class;
}

/**
* This method is inherited from AbstractExtension but should never be
* called directly with an AbstractRenderer.
*/
@Deprecated
@Override
protected void extend(AbstractClientConnector target) {
super.extend(target);
}

@Override
public Class<T> getPresentationType() {
return presentationType;
}

@Override
public JsonValue encode(T value) {
if (value == null) {
return encode(getNullRepresentation(), String.class);
} else {
return encode(value, getPresentationType());
}
}

/**
* Null representation for the renderer
*
* @return a textual representation of {@code null}
*/
protected String getNullRepresentation() {
return nullRepresentation;
}

/**
* Encodes the given value to JSON.
* <p>
* This is a helper method that can be invoked by an {@link #encode(Object)
* encode(T)} override if serializing a value of type other than
* {@link #getPresentationType() the presentation type} is desired. For
* instance, a {@code Renderer<Date>} could first turn a date value into a
* formatted string and return {@code encode(dateString, String.class)}.
*
* @param value
* the value to be encoded
* @param type
* the type of the value
* @return a JSON representation of the given value
*/
protected <U> JsonValue encode(U value, Class<U> type) {
return JsonCodec
.encode(value, null, type, getUI().getConnectorTracker())
.getEncodedValue();
}
}

+ 238
- 0
server/src/main/java/com/vaadin/ui/renderers/DateRenderer.java View File

@@ -0,0 +1,238 @@
/*
* 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.renderers;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import elemental.json.JsonValue;

/**
* A renderer for presenting date values.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class DateRenderer extends AbstractRenderer<Date> {
private final Locale locale;
private final String formatString;
private final DateFormat dateFormat;

/**
* Creates a new date renderer.
* <p>
* The renderer is configured to render with the {@link Date#toString()}
* representation for the default locale.
*/
public DateRenderer() {
this(Locale.getDefault(), "");
}

/**
* Creates a new date renderer.
* <p>
* The renderer is configured to render with the {@link Date#toString()}
* representation for the given locale.
*
* @param locale
* the locale in which to present dates
* @throws IllegalArgumentException
* if {@code locale} is {@code null}
*/
public DateRenderer(Locale locale) throws IllegalArgumentException {
this("%s", locale, "");
}

/**
* Creates a new date renderer.
* <p>
* The renderer is configured to render with the {@link Date#toString()}
* representation for the given locale.
*
* @param locale
* the locale in which to present dates
* @param nullRepresentation
* the textual representation of {@code null} value
* @throws IllegalArgumentException
* if {@code locale} is {@code null}
*/
public DateRenderer(Locale locale, String nullRepresentation)
throws IllegalArgumentException {
this("%s", locale, nullRepresentation);
}

/**
* Creates a new date renderer.
* <p>
* The renderer is configured to render with the given string format, as
* displayed in the default locale.
*
* @param formatString
* the format string with which to format the date
* @throws IllegalArgumentException
* if {@code formatString} is {@code null}
* @see <a href=
* "http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax">Format
* String Syntax</a>
*/
public DateRenderer(String formatString) throws IllegalArgumentException {
this(formatString, "");
}

/**
* Creates a new date renderer.
* <p>
* The renderer is configured to render with the given string format, as
* displayed in the default locale.
*
* @param formatString
* the format string with which to format the date
* @param nullRepresentation
* the textual representation of {@code null} value
* @throws IllegalArgumentException
* if {@code formatString} is {@code null}
* @see <a href=
* "http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax">Format
* String Syntax</a>
*/
public DateRenderer(String formatString, String nullRepresentation)
throws IllegalArgumentException {
this(formatString, Locale.getDefault(), nullRepresentation);
}

/**
* Creates a new date renderer.
* <p>
* The renderer is configured to render with the given string format, as
* displayed in the given locale.
*
* @param formatString
* the format string to format the date with
* @param locale
* the locale to use
* @throws IllegalArgumentException
* if either argument is {@code null}
* @see <a href=
* "http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax">Format
* String Syntax</a>
*/
public DateRenderer(String formatString, Locale locale)
throws IllegalArgumentException {
this(formatString, locale, "");
}

/**
* Creates a new date renderer.
* <p>
* The renderer is configured to render with the given string format, as
* displayed in the given locale.
*
* @param formatString
* the format string to format the date with
* @param locale
* the locale to use
* @param nullRepresentation
* the textual representation of {@code null} value
* @throws IllegalArgumentException
* if either argument is {@code null}
* @see <a href=
* "http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax">Format
* String Syntax</a>
*/
public DateRenderer(String formatString, Locale locale,
String nullRepresentation) throws IllegalArgumentException {
super(Date.class, nullRepresentation);

if (formatString == null) {
throw new IllegalArgumentException("format string may not be null");
}

if (locale == null) {
throw new IllegalArgumentException("locale may not be null");
}

this.locale = locale;
this.formatString = formatString;
dateFormat = null;
}

/**
* Creates a new date renderer.
* <p>
* The renderer is configured to render with he given date format.
*
* @param dateFormat
* the date format to use when rendering dates
* @throws IllegalArgumentException
* if {@code dateFormat} is {@code null}
*/
public DateRenderer(DateFormat dateFormat) throws IllegalArgumentException {
this(dateFormat, "");
}

/**
* Creates a new date renderer.
* <p>
* The renderer is configured to render with he given date format.
*
* @param dateFormat
* the date format to use when rendering dates
* @throws IllegalArgumentException
* if {@code dateFormat} is {@code null}
*/
public DateRenderer(DateFormat dateFormat, String nullRepresentation)
throws IllegalArgumentException {
super(Date.class, nullRepresentation);
if (dateFormat == null) {
throw new IllegalArgumentException("date format may not be null");
}

locale = null;
formatString = null;
this.dateFormat = dateFormat;
}

@Override
public String getNullRepresentation() {
return super.getNullRepresentation();
}

@Override
public JsonValue encode(Date value) {
String dateString;
if (value == null) {
dateString = getNullRepresentation();
} else if (dateFormat != null) {
dateString = dateFormat.format(value);
} else {
dateString = String.format(locale, formatString, value);
}
return encode(dateString, String.class);
}

@Override
public String toString() {
final String fieldInfo;
if (dateFormat != null) {
fieldInfo = "dateFormat: " + dateFormat.toString();
} else {
fieldInfo = "locale: " + locale + ", formatString: " + formatString;
}

return String.format("%s [%s]", getClass().getSimpleName(), fieldInfo);
}
}

+ 46
- 0
server/src/main/java/com/vaadin/ui/renderers/HtmlRenderer.java View File

@@ -0,0 +1,46 @@
/*
* 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.renderers;

/**
* A renderer for presenting HTML content.
*
* @author Vaadin Ltd
* @since 7.4
*/
public class HtmlRenderer extends AbstractRenderer<String> {
/**
* Creates a new HTML renderer.
*
* @param nullRepresentation
* the html representation of {@code null} value
*/
public HtmlRenderer(String nullRepresentation) {
super(String.class, nullRepresentation);
}

/**
* Creates a new HTML renderer.
*/
public HtmlRenderer() {
this("");
}

@Override
public String getNullRepresentation() {
return super.getNullRepresentation();
}
}

+ 205
- 0
server/src/main/java/com/vaadin/ui/renderers/NumberRenderer.java View File

@@ -0,0 +1,205 @@
/*
* 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.renderers;

import java.text.NumberFormat;
import java.util.Locale;

import elemental.json.JsonValue;

/**
* A renderer for presenting number values.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class NumberRenderer extends AbstractRenderer<Number> {
private final Locale locale;
private final NumberFormat numberFormat;
private final String formatString;

/**
* Creates a new number renderer.
* <p/>
* The renderer is configured to render with the number's natural string
* representation in the default locale.
*/
public NumberRenderer() {
this(Locale.getDefault());
}

/**
* Creates a new number renderer.
* <p/>
* The renderer is configured to render the number as defined with the given
* number format.
*
* @param numberFormat
* the number format with which to display numbers
* @throws IllegalArgumentException
* if {@code numberFormat} is {@code null}
*/
public NumberRenderer(NumberFormat numberFormat) {
this(numberFormat, "");
}

/**
* Creates a new number renderer.
* <p/>
* The renderer is configured to render the number as defined with the given
* number format.
*
* @param numberFormat
* the number format with which to display numbers
* @param nullRepresentation
* the textual representation of {@code null} value
* @throws IllegalArgumentException
* if {@code numberFormat} is {@code null}
*/
public NumberRenderer(NumberFormat numberFormat, String nullRepresentation)
throws IllegalArgumentException {
super(Number.class, nullRepresentation);

if (numberFormat == null) {
throw new IllegalArgumentException("Number format may not be null");
}

locale = null;
this.numberFormat = numberFormat;
formatString = null;
}

/**
* Creates a new number renderer.
* <p/>
* The renderer is configured to render with the number's natural string
* representation in the given locale.
*
* @param locale
* the locale in which to display numbers
* @throws IllegalArgumentException
* if {@code locale} is {@code null}
*/
public NumberRenderer(Locale locale) throws IllegalArgumentException {
this("%s", locale);
}

/**
* Creates a new number renderer.
* <p/>
* The renderer is configured to render with the number's natural string
* representation in the given locale.
*
* @param formatString
* the format string with which to format the number
* @param locale
* the locale in which to display numbers
* @throws IllegalArgumentException
* if {@code locale} is {@code null}
*/
public NumberRenderer(String formatString, Locale locale)
throws IllegalArgumentException {
this(formatString, locale, ""); // This will call #toString() during
// formatting
}

/**
* Creates a new number renderer.
* <p/>
* The renderer is configured to render with the given format string in the
* default locale.
*
* @param formatString
* the format string with which to format the number
* @throws IllegalArgumentException
* if {@code formatString} is {@code null}
* @see <a href=
* "http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax">Format
* String Syntax</a>
*/
public NumberRenderer(String formatString) throws IllegalArgumentException {
this(formatString, Locale.getDefault(), "");
}

/**
* Creates a new number renderer.
* <p/>
* The renderer is configured to render with the given format string in the
* given locale.
*
* @param formatString
* the format string with which to format the number
* @param locale
* the locale in which to present numbers
* @throws IllegalArgumentException
* if either argument is {@code null}
* @see <a href=
* "http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax">Format
* String Syntax</a>
*/
public NumberRenderer(String formatString, Locale locale,
String nullRepresentation) {
super(Number.class, nullRepresentation);

if (formatString == null) {
throw new IllegalArgumentException("Format string may not be null");
}

if (locale == null) {
throw new IllegalArgumentException("Locale may not be null");
}

this.locale = locale;
numberFormat = null;
this.formatString = formatString;
}

@Override
public JsonValue encode(Number value) {
String stringValue;
if (value == null) {
stringValue = getNullRepresentation();
} else if (formatString != null && locale != null) {
stringValue = String.format(locale, formatString, value);
} else if (numberFormat != null) {
stringValue = numberFormat.format(value);
} else {
throw new IllegalStateException(String.format(
"Internal bug: " + "%s is in an illegal state: "
+ "[locale: %s, numberFormat: %s, formatString: %s]",
getClass().getSimpleName(), locale, numberFormat,
formatString));
}
return encode(stringValue, String.class);
}

@Override
public String toString() {
final String fieldInfo;
if (numberFormat != null) {
fieldInfo = "numberFormat: " + numberFormat.toString();
} else {
fieldInfo = "locale: " + locale + ", formatString: " + formatString;
}

return String.format("%s [%s]", getClass().getSimpleName(), fieldInfo);
}

@Override
public String getNullRepresentation() {
return super.getNullRepresentation();
}
}

+ 45
- 0
server/src/main/java/com/vaadin/ui/renderers/ProgressBarRenderer.java View File

@@ -0,0 +1,45 @@
/*
* 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.renderers;

import elemental.json.JsonValue;

/**
* A renderer that represents double values between 0 and 1 as a graphical
* progress bar.
*
* @author Vaadin Ltd
* @since 7.4
*/
public class ProgressBarRenderer extends AbstractRenderer<Double> {

/**
* Creates a new text renderer
*/
public ProgressBarRenderer() {
super(Double.class, null);
}

@Override
public JsonValue encode(Double value) {
if (value != null) {
value = Math.max(Math.min(value, 1), 0);
} else {
value = 0d;
}
return super.encode(value);
}
}

+ 69
- 0
server/src/main/java/com/vaadin/ui/renderers/Renderer.java View File

@@ -0,0 +1,69 @@
/*
* 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.renderers;

import com.vaadin.server.ClientConnector;
import com.vaadin.server.Extension;

import elemental.json.JsonValue;

/**
* A ClientConnector for controlling client-side
* {@link com.vaadin.client.renderers.Renderer Grid renderers}. Renderers
* currently extend the Extension interface, but this fact should be regarded as
* an implementation detail and subject to change in a future major or minor
* Vaadin revision.
*
* @param <T>
* the type this renderer knows how to present
*
* @since 7.4
* @author Vaadin Ltd
*/
public interface Renderer<T> extends Extension {

/**
* Returns the class literal corresponding to the presentation type T.
*
* @return the class literal of T
*/
Class<T> getPresentationType();

/**
* Encodes the given value into a {@link JsonValue}.
*
* @param value
* the value to encode
* @return a JSON representation of the given value
*/
JsonValue encode(T value);

/**
* This method is inherited from Extension but should never be called
* directly with a Renderer.
*/
@Override
@Deprecated
void remove();

/**
* This method is inherited from Extension but should never be called
* directly with a Renderer.
*/
@Override
@Deprecated
void setParent(ClientConnector parent);
}

+ 47
- 0
server/src/main/java/com/vaadin/ui/renderers/TextRenderer.java View File

@@ -0,0 +1,47 @@
/*
* 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.renderers;

/**
* A renderer for presenting simple plain-text string values.
*
* @since 7.4
* @author Vaadin Ltd
*/
public class TextRenderer extends AbstractRenderer<String> {

/**
* Creates a new text renderer
*/
public TextRenderer() {
this("");
}

/**
* Creates a new text renderer
*
* @param nullRepresentation
* the textual representation of {@code null} value
*/
public TextRenderer(String nullRepresentation) {
super(String.class, nullRepresentation);
}

@Override
public String getNullRepresentation() {
return super.getNullRepresentation();
}
}

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

@@ -17,7 +17,7 @@ public class GridTest {
@Before
public void setUp() {
grid = new Grid<>();
grid.addColumn("foo", String.class, Function.identity());
grid.addColumn("foo", Function.identity());
}

@Test

+ 3
- 0
shared/src/main/java/com/vaadin/shared/ui/grid/ColumnState.java View File

@@ -15,6 +15,7 @@
*/
package com.vaadin.shared.ui.grid;

import com.vaadin.shared.Connector;
import com.vaadin.shared.communication.SharedState;

public class ColumnState extends SharedState {
@@ -22,4 +23,6 @@ public class ColumnState extends SharedState {
public String caption;
public String id;
public boolean sortable;

public Connector renderer;
}

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

@@ -1,7 +1,6 @@
package com.vaadin.tests.components.grid.basics;

import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@@ -25,6 +24,10 @@ import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.renderers.DateRenderer;
import com.vaadin.ui.renderers.HtmlRenderer;
import com.vaadin.ui.renderers.NumberRenderer;
import com.vaadin.ui.renderers.ProgressBarRenderer;

@Widgetset("com.vaadin.DefaultWidgetSet")
public class GridBasics extends AbstractTestUIWithLog {
@@ -113,16 +116,20 @@ public class GridBasics extends AbstractTestUIWithLog {
grid = new Grid<>();
grid.setItems(data);

grid.addColumn("Column 0", String.class,
grid.addColumn("Column 0",
dataObj -> "(" + dataObj.getRowNumber() + ", 0)");
grid.addColumn("Column 1", String.class,
grid.addColumn("Column 1",
dataObj -> "(" + dataObj.getRowNumber() + ", 1)");
grid.addColumn("Row Number", Integer.class, DataObject::getRowNumber);
grid.addColumn("Date", Date.class, DataObject::getDate);
grid.addColumn("HTML String", String.class, DataObject::getHtmlString);
grid.addColumn("Big Random", Integer.class, DataObject::getBigRandom);
grid.addColumn("Small Random", Integer.class,
DataObject::getSmallRandom);

grid.addColumn("Row Number", DataObject::getRowNumber,
new NumberRenderer());
grid.addColumn("Date", DataObject::getDate, new DateRenderer());
grid.addColumn("HTML String", DataObject::getHtmlString,
new HtmlRenderer());
grid.addColumn("Big Random", DataObject::getBigRandom,
new NumberRenderer());
grid.addColumn("Small Random", data -> data.getSmallRandom() / 5d,
new ProgressBarRenderer());

((SingleSelection<DataObject>) grid.getSelectionModel())
.addSelectionListener(e -> log("Selected: " + e.getValue()));

+ 3
- 3
uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridContentTest.java View File

@@ -5,13 +5,13 @@ import org.junit.Test;

public class GridContentTest extends GridBasicsTest {

@Test(expected = AssertionError.class)
@Test
public void testHtmlRenderer() {
DataObject first = getTestData().findFirst().orElse(null);
Assert.assertEquals("Text content should match row number",
first.getRowNumber().toString(),
getGridElement().getCell(0, 2).getText());
getGridElement().getCell(0, 4).getText());
Assert.assertEquals("HTML content did not match", first.getHtmlString(),
getGridElement().getCell(0, 2).getAttribute("innerHTML"));
getGridElement().getCell(0, 4).getAttribute("innerHTML"));
}
}

Loading…
Cancel
Save