Change-Id: Ic855143d23cc7735d00130806df45b6579ba0d5ctags/8.0.0.alpha1
@@ -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 | |||
} |
@@ -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") |
@@ -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 | |||
} |
@@ -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 | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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}. | |||
* |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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 |
@@ -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; | |||
} |
@@ -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())); |
@@ -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")); | |||
} | |||
} |