--- /dev/null
+/*
+ * 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
+}
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;
@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;
@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")
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
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.
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,
}
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
}
/**
- * 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));
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}.
*
--- /dev/null
+/*
+ * 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();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
@Before
public void setUp() {
grid = new Grid<>();
- grid.addColumn("foo", String.class, Function.identity());
+ grid.addColumn("foo", Function.identity());
}
@Test
*/
package com.vaadin.shared.ui.grid;
+import com.vaadin.shared.Connector;
import com.vaadin.shared.communication.SharedState;
public class ColumnState extends SharedState {
public String caption;
public String id;
public boolean sortable;
+
+ public Connector renderer;
}
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;
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 {
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()));
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"));
}
}