diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2015-06-01 09:32:37 +0300 |
---|---|---|
committer | Teemu Suo-Anttila <teemusa@vaadin.com> | 2015-06-01 09:34:46 +0300 |
commit | 6677046e5e23667403b8fb0499a618495796e1c8 (patch) | |
tree | 0d4bb0bf40b16be2c9e7e6158729f5bd3ff54d22 /server | |
parent | cf563c053fdf0d6b2991eba98e1cc118a8e74e54 (diff) | |
parent | 5b92ec790e3d3949992275d54ee8ac61ad94c157 (diff) | |
download | vaadin-framework-6677046e5e23667403b8fb0499a618495796e1c8.tar.gz vaadin-framework-6677046e5e23667403b8fb0499a618495796e1c8.zip |
Merge remote-tracking branch 'origin/master' into grid-unbuffered-editor
This also refactors some event handling logic.
Change-Id: I9cf96381650076da01686c5d964eb3e7e92c24c0
Diffstat (limited to 'server')
59 files changed, 1203 insertions, 423 deletions
diff --git a/server/build.xml b/server/build.xml index 79bc6debe2..e88b53d937 100644 --- a/server/build.xml +++ b/server/build.xml @@ -26,7 +26,7 @@ <target name="jar"> <property name="server.osgi.import" - value="javax.servlet;version="2.4.0",javax.servlet.http;version="2.4.0",javax.validation;version="1.0.0.GA";resolution:=optional,org.jsoup;version="1.6.3",org.jsoup.parser;version="1.6.3",org.jsoup.nodes;version="1.6.3",org.jsoup.helper;version="1.6.3",org.jsoup.safety;version="1.6.3"" /> + value="javax.servlet;version="2.4.0",javax.servlet.http;version="2.4.0",javax.validation;version="1.0.0.GA";resolution:=optional,org.jsoup;version="1.6.3",org.jsoup.parser;version="1.6.3",org.jsoup.nodes;version="1.6.3",org.jsoup.helper;version="1.6.3",org.jsoup.safety;version="1.6.3",org.jsoup.select;version="1.6.3"" /> <property name="server.osgi.require" value="com.google.gwt.thirdparty.guava;bundle-version="16.0.1.vaadin1",com.vaadin.shared;bundle-version="${vaadin.version}",com.vaadin.push;bundle-version="${vaadin.version}";resolution:=optional,com.vaadin.sass-compiler;bundle-version="${vaadin.sass.version}";resolution:=optional" /> <antcall target="common.jar"> diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index e645ec60f7..9d18736ba8 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -50,6 +50,7 @@ import com.vaadin.server.KeyMapper; import com.vaadin.shared.data.DataProviderRpc; import com.vaadin.shared.data.DataRequestRpc; import com.vaadin.shared.ui.grid.DetailsConnectorChange; +import com.vaadin.shared.ui.grid.GridClientRpc; import com.vaadin.shared.ui.grid.GridState; import com.vaadin.shared.ui.grid.Range; import com.vaadin.shared.util.SharedUtil; @@ -135,6 +136,15 @@ public class RpcDataProviderExtension extends AbstractExtension { return String.valueOf(rollingIndex++); } + /** + * Gets the key for a given item id. Creates a new key mapping if no + * existing mapping was found for the given item id. + * + * @since 7.5.0 + * @param itemId + * the item id to get the key for + * @return the key for the given item id + */ public String getKey(Object itemId) { String key = itemIdToKey.get(itemId); if (key == null) { @@ -1124,7 +1134,7 @@ public class RpcDataProviderExtension extends AbstractExtension { Object propertyId = column.getPropertyId(); cellReference.set(propertyId); String style = generator.getStyle(cellReference); - if (style != null) { + if (style != null && !style.isEmpty()) { if (cellStyles == null) { cellStyles = Json.createObject(); } @@ -1142,7 +1152,7 @@ public class RpcDataProviderExtension extends AbstractExtension { private void setGeneratedRowStyles(RowStyleGenerator generator, JsonObject rowObject) { String rowStyle = generator.getStyle(rowReference); - if (rowStyle != null) { + if (rowStyle != null && !rowStyle.isEmpty()) { rowObject.put(GridState.JSONKEY_ROWSTYLE, rowStyle); } } @@ -1428,6 +1438,11 @@ public class RpcDataProviderExtension extends AbstractExtension { return visibleDetails.contains(itemId); } + /** + * Refreshes all visible detail sections. + * + * @since 7.5.0 + */ public void refreshDetails() { for (Object itemId : ImmutableSet.copyOf(visibleDetails)) { detailComponentManager.refresh(itemId); @@ -1443,7 +1458,12 @@ public class RpcDataProviderExtension extends AbstractExtension { return container.indexOfId(itemId); } - /** Gets the detail component manager for this data provider */ + /** + * Gets the detail component manager for this data provider + * + * @since 7.5.0 + * @return the detail component manager + * */ public DetailComponentManager getDetailComponentManager() { return detailComponentManager; } diff --git a/server/src/com/vaadin/data/util/MethodProperty.java b/server/src/com/vaadin/data/util/MethodProperty.java index 853f68b711..83279afa53 100644 --- a/server/src/com/vaadin/data/util/MethodProperty.java +++ b/server/src/com/vaadin/data/util/MethodProperty.java @@ -26,6 +26,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import com.vaadin.data.Property; +import com.vaadin.shared.util.SharedUtil; import com.vaadin.util.SerializerHelper; /** @@ -189,11 +190,7 @@ public class MethodProperty<T> extends AbstractProperty<T> { // Assure that the first letter is upper cased (it is a common // mistake to write firstName, not FirstName). - if (Character.isLowerCase(beanPropertyName.charAt(0))) { - final char[] buf = beanPropertyName.toCharArray(); - buf[0] = Character.toUpperCase(buf[0]); - beanPropertyName = new String(buf); - } + beanPropertyName = SharedUtil.capitalize(beanPropertyName); // Find the get method getMethod = null; @@ -534,8 +531,7 @@ public class MethodProperty<T> extends AbstractProperty<T> { */ static Method initGetterMethod(String propertyName, final Class<?> beanClass) throws NoSuchMethodException { - propertyName = propertyName.substring(0, 1).toUpperCase() - + propertyName.substring(1); + propertyName = SharedUtil.capitalize(propertyName); Method getMethod = null; try { @@ -772,4 +768,5 @@ public class MethodProperty<T> extends AbstractProperty<T> { private static final Logger getLogger() { return Logger.getLogger(MethodProperty.class.getName()); } + } diff --git a/server/src/com/vaadin/data/util/NestedMethodProperty.java b/server/src/com/vaadin/data/util/NestedMethodProperty.java index 0493812861..29fe62f845 100644 --- a/server/src/com/vaadin/data/util/NestedMethodProperty.java +++ b/server/src/com/vaadin/data/util/NestedMethodProperty.java @@ -26,6 +26,7 @@ import java.util.List; import com.vaadin.data.Property; import com.vaadin.data.util.MethodProperty.MethodException; +import com.vaadin.shared.util.SharedUtil; /** * Nested accessor based property for a bean. @@ -164,11 +165,8 @@ public class NestedMethodProperty<T> extends AbstractProperty<T> { try { // Assure that the first letter is upper cased (it is a common // mistake to write firstName, not FirstName). - if (Character.isLowerCase(lastSimplePropertyName.charAt(0))) { - final char[] buf = lastSimplePropertyName.toCharArray(); - buf[0] = Character.toUpperCase(buf[0]); - lastSimplePropertyName = new String(buf); - } + lastSimplePropertyName = SharedUtil + .capitalize(lastSimplePropertyName); setMethod = lastClass.getMethod("set" + lastSimplePropertyName, new Class[] { type }); diff --git a/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java b/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java index a84a3575f7..495bed74f8 100644 --- a/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java @@ -34,6 +34,8 @@ import java.util.Locale; * {@link String} for token types. Other constructors allow to configure * delimiter and token types. * + * @since 7.5.0 + * * @author Vaadin Ltd */ public class StringToCollectionConverter implements diff --git a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java index c0c660c084..f07b7ecc58 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java @@ -1012,9 +1012,15 @@ public class SQLContainer implements Container, Container.Filterable, queryDelegate.beginTransaction(); /* Perform buffered deletions */ for (RowItem item : removedItems.values()) { - if (!queryDelegate.removeRow(item)) { + try { + if (!queryDelegate.removeRow(item)) { + throw new SQLException( + "Removal failed for row with ID: " + + item.getId()); + } + } catch (IllegalArgumentException e) { throw new SQLException("Removal failed for row with ID: " - + item.getId()); + + item.getId(), e); } } /* Perform buffered modifications */ diff --git a/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java b/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java index bb000bd8f5..9a41766a31 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java @@ -213,8 +213,8 @@ public class TableQuery extends AbstractTransactionalQuery implements } finally { try { if (r != null) { - releaseConnection(r.getStatement().getConnection(), - r.getStatement(), r); + // Do not release connection, it is done in commit() + releaseConnection(null, r.getStatement(), r); } } finally { if (shouldCloseTransaction) { @@ -774,8 +774,8 @@ public class TableQuery extends AbstractTransactionalQuery implements } finally { try { if (rs != null) { - releaseConnection(rs.getStatement().getConnection(), - rs.getStatement(), rs); + // Do not release connection, it is done in commit() + releaseConnection(null, rs.getStatement(), rs); } } finally { if (shouldCloseTransaction) { diff --git a/server/src/com/vaadin/event/ShortcutAction.java b/server/src/com/vaadin/event/ShortcutAction.java index 32b909e9f2..09accae1c7 100644 --- a/server/src/com/vaadin/event/ShortcutAction.java +++ b/server/src/com/vaadin/event/ShortcutAction.java @@ -17,8 +17,6 @@ package com.vaadin.event; import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -239,42 +237,6 @@ public class ShortcutAction extends Action { } /** - * Checks whether the shortcut can be triggered with the given combination - * of keys. - * - * @param keyCode - * potential match for the {@link KeyCode} that this shortcut - * reacts to - * @param modifierKeys - * (optional) potential matches for the {@link ModifierKey}s - * required for this shortcut to react - * @return <code>true</code> if keyCode and modifierKeys are a match, - * <code>false</code> otherwise - */ - public boolean isTriggeredBy(int keyCode, int... modifierKeys) { - boolean result = false; - if (keyCode == this.keyCode) { - if (modifierKeys == null) { - result = (modifiers == null); - } else if (modifiers != null) { - List<Integer> modifierList = new ArrayList<Integer>(); - for (int modifier : modifiers) { - modifierList.add(modifier); - } - for (int modifierKey : modifierKeys) { - if (modifierList.contains(modifierKey)) { - modifierList.remove(modifierKey); - } else { - return false; - } - } - result = modifierList.isEmpty(); - } - } - return result; - } - - /** * Key codes that can be used for shortcuts * */ diff --git a/server/src/com/vaadin/server/AbstractClientConnector.java b/server/src/com/vaadin/server/AbstractClientConnector.java index 87b61c9623..0655b482ed 100644 --- a/server/src/com/vaadin/server/AbstractClientConnector.java +++ b/server/src/com/vaadin/server/AbstractClientConnector.java @@ -180,22 +180,40 @@ public abstract class AbstractClientConnector implements ClientConnector, * RPC interface implementation. Also used to deduce the type. */ protected <T extends ServerRpc> void registerRpc(T implementation) { + // Search upwards until an interface is found. It must be found as T + // extends ServerRpc Class<?> cls = implementation.getClass(); - Class<?>[] interfaces = cls.getInterfaces(); - while (interfaces.length == 0) { - // Search upwards until an interface is found. It must be found as T - // extends ServerRpc + Class<ServerRpc> serverRpcClass = getServerRpcInterface(cls); + + while (cls != null && serverRpcClass == null) { cls = cls.getSuperclass(); - interfaces = cls.getInterfaces(); + serverRpcClass = getServerRpcInterface(cls); } - if (interfaces.length != 1 - || !(ServerRpc.class.isAssignableFrom(interfaces[0]))) { + + if (serverRpcClass == null) { throw new RuntimeException( - "Use registerRpc(T implementation, Class<T> rpcInterfaceType) if the Rpc implementation implements more than one interface"); + "No interface T extends ServerRpc found in the class hierarchy."); + } + + registerRpc(implementation, serverRpcClass); + } + + @SuppressWarnings("unchecked") + private Class<ServerRpc> getServerRpcInterface(Class<?> implementationClass) { + Class<ServerRpc> serverRpcClass = null; + if (implementationClass != null) { + for (Class<?> candidateInterface : implementationClass + .getInterfaces()) { + if (ServerRpc.class.isAssignableFrom(candidateInterface)) { + if (serverRpcClass != null) { + throw new RuntimeException( + "Use registerRpc(T implementation, Class<T> rpcInterfaceType) if the Rpc implementation implements more than one interface"); + } + serverRpcClass = (Class<ServerRpc>) candidateInterface; + } + } } - @SuppressWarnings("unchecked") - Class<T> type = (Class<T>) interfaces[0]; - registerRpc(implementation, type); + return serverRpcClass; } /** diff --git a/server/src/com/vaadin/server/SystemMessages.java b/server/src/com/vaadin/server/SystemMessages.java index 51e9da5800..51cc7d497d 100644 --- a/server/src/com/vaadin/server/SystemMessages.java +++ b/server/src/com/vaadin/server/SystemMessages.java @@ -224,35 +224,6 @@ public class SystemMessages implements Serializable { } /** - * @return null to reload the application after out of sync message. - */ - public String getOutOfSyncURL() { - return outOfSyncURL; - } - - /** - * @return true to enable showing out of sync message - */ - public boolean isOutOfSyncNotificationEnabled() { - return outOfSyncNotificationEnabled; - } - - /** - * @return "Out of sync" - */ - public String getOutOfSyncCaption() { - return (outOfSyncNotificationEnabled ? outOfSyncCaption : null); - } - - /** - * @return "Something has caused us to be out of sync with the server.<br/> - * Take note of any unsaved data, and <u>click here</u> to re-sync." - */ - public String getOutOfSyncMessage() { - return (outOfSyncNotificationEnabled ? outOfSyncMessage : null); - } - - /** * Returns the URL the user should be redirected to after dismissing the * "you have to enable your cookies" message. Typically null. * diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index b30f6acf16..7aada2402d 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -871,9 +871,8 @@ public class VaadinServlet extends HttpServlet implements Constants { if (allowServePrecompressedResource(request, urlStr)) { // try to serve a precompressed version if available - URL url = new URL(urlStr + ".gz"); - connection = url.openConnection(); try { + connection = new URL(urlStr + ".gz").openConnection(); is = connection.getInputStream(); // set gzip headers response.setHeader("Content-Encoding", "gzip"); diff --git a/server/src/com/vaadin/server/communication/PushRequestHandler.java b/server/src/com/vaadin/server/communication/PushRequestHandler.java index 9e25f1d8ff..c01c74e5cd 100644 --- a/server/src/com/vaadin/server/communication/PushRequestHandler.java +++ b/server/src/com/vaadin/server/communication/PushRequestHandler.java @@ -145,7 +145,7 @@ public class PushRequestHandler implements RequestHandler, */ static AtmosphereFramework initAtmosphere( final ServletConfig vaadinServletConfig) { - AtmosphereFramework atmosphere = new AtmosphereFramework() { + AtmosphereFramework atmosphere = new AtmosphereFramework(false, false) { @Override protected void analytics() { // Overridden to disable version number check diff --git a/server/src/com/vaadin/server/communication/ServerRpcHandler.java b/server/src/com/vaadin/server/communication/ServerRpcHandler.java index 450c11f5c4..65fb144810 100644 --- a/server/src/com/vaadin/server/communication/ServerRpcHandler.java +++ b/server/src/com/vaadin/server/communication/ServerRpcHandler.java @@ -76,13 +76,14 @@ public class ServerRpcHandler implements Serializable { private final JsonArray invocations; private final int syncId; private final JsonObject json; + private final boolean resynchronize; public RpcRequest(String jsonString, VaadinRequest request) { json = JsonUtil.parse(jsonString); JsonValue token = json.get(ApplicationConstants.CSRF_TOKEN); if (token == null) { - this.csrfToken = ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE; + csrfToken = ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE; } else { String csrfToken = token.asString(); if (csrfToken.equals("")) { @@ -98,6 +99,14 @@ public class ServerRpcHandler implements Serializable { } else { syncId = -1; } + + if (json.hasKey(ApplicationConstants.RESYNCHRONIZE_ID)) { + resynchronize = json + .getBoolean(ApplicationConstants.RESYNCHRONIZE_ID); + } else { + resynchronize = false; + } + invocations = json.getArray(ApplicationConstants.RPC_INVOCATIONS); } @@ -131,6 +140,15 @@ public class ServerRpcHandler implements Serializable { } /** + * Checks if this is a request to resynchronize the client side + * + * @return true if this is a resynchronization request, false otherwise + */ + public boolean isResynchronize() { + return resynchronize; + } + + /** * Gets the entire request in JSON format, as it was received from the * client. * <p> @@ -186,6 +204,10 @@ public class ServerRpcHandler implements Serializable { ui.getConnectorTracker().cleanConcurrentlyRemovedConnectorIds( rpcRequest.getSyncId()); + + if (rpcRequest.isResynchronize()) { + ui.getSession().getCommunicationManager().repaintAll(ui); + } } /** diff --git a/server/src/com/vaadin/server/communication/UidlRequestHandler.java b/server/src/com/vaadin/server/communication/UidlRequestHandler.java index 6e338c5773..33a3669b7f 100644 --- a/server/src/com/vaadin/server/communication/UidlRequestHandler.java +++ b/server/src/com/vaadin/server/communication/UidlRequestHandler.java @@ -80,10 +80,12 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements // repaint requested or session has timed out and new one is created boolean repaintAll; - // TODO PUSH repaintAll, analyzeLayouts should be + // TODO PUSH analyzeLayouts should be // part of the message payload to make the functionality transport // agnostic + // Resynchronize is sent in the payload but will still support the + // parameter also for compatibility reasons repaintAll = (request .getParameter(ApplicationConstants.URL_PARAMETER_REPAINT_ALL) != null); diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java index fd8a72ee23..27d97d5e03 100644 --- a/server/src/com/vaadin/ui/AbstractComponent.java +++ b/server/src/com/vaadin/ui/AbstractComponent.java @@ -405,6 +405,26 @@ public abstract class AbstractComponent extends AbstractClientConnector } } + /** + * Returns the explicitly set immediate value. + * + * @return the explicitly set immediate value or null if + * {@link #setImmediate(boolean)} has not been explicitly invoked + */ + protected Boolean getExplicitImmediateValue() { + return explicitImmediateValue; + } + + /** + * Returns the immediate mode of the component. + * <p> + * Certain operations such as adding a value change listener will set the + * component into immediate mode if {@link #setImmediate(boolean)} has not + * been explicitly called with false. + * + * @return true if the component is in immediate mode (explicitly or + * implicitly set), false if the component if not in immediate mode + */ public boolean isImmediate() { if (explicitImmediateValue != null) { return explicitImmediateValue; diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java index 5c02c9e5fb..cf14d1cb96 100644 --- a/server/src/com/vaadin/ui/AbstractField.java +++ b/server/src/com/vaadin/ui/AbstractField.java @@ -1745,6 +1745,24 @@ public abstract class AbstractField<T> extends AbstractComponent implements } } + /** + * {@inheritDoc} + * <p> + * Fields are automatically set to immediate if validators have been added. + */ + @Override + public boolean isImmediate() { + if (getExplicitImmediateValue() != null) { + return getExplicitImmediateValue(); + } + // Make field immediate when there is some kind of validation present + // (validator or required). This will avoid the UI being in a wrong + // state, e.g. user entered valid data but old validation error is still + // shown + return super.isImmediate() || !getValidators().isEmpty() + || isRequired(); + } + /* * (non-Javadoc) * diff --git a/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java b/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java index 767ae66515..0854ffe9c2 100644 --- a/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java +++ b/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java @@ -298,7 +298,9 @@ public abstract class AbstractSingleComponentContainer extends * contains multiple child elements, a DesignException is thrown. This * method should be overridden by subclasses whose design may contain * non-content child elements. - * + * + * @since 7.5.0 + * * @param children * the child elements of the design that is being read * @param context diff --git a/server/src/com/vaadin/ui/CustomLayout.java b/server/src/com/vaadin/ui/CustomLayout.java index ceb47e1e7a..d64f70e95e 100644 --- a/server/src/com/vaadin/ui/CustomLayout.java +++ b/server/src/com/vaadin/ui/CustomLayout.java @@ -74,6 +74,8 @@ public class CustomLayout extends AbstractLayout implements LegacyComponent { * for setting the appropriate fields. Either * {@link #setTemplateName(String)}, that makes layout fetch the template * from theme, or {@link #setTemplateContents(String)}. + * + * @since 7.5.0 */ public CustomLayout() { setWidth(100, Unit.PERCENTAGE); diff --git a/server/src/com/vaadin/ui/DragAndDropWrapper.java b/server/src/com/vaadin/ui/DragAndDropWrapper.java index b813973861..ba912f15dc 100644 --- a/server/src/com/vaadin/ui/DragAndDropWrapper.java +++ b/server/src/com/vaadin/ui/DragAndDropWrapper.java @@ -191,6 +191,8 @@ public class DragAndDropWrapper extends CustomComponent implements DropTarget, /** * This is an internal constructor. Use * {@link DragAndDropWrapper#DragAndDropWrapper(Component)} instead. + * + * @since 7.5.0 */ @Deprecated public DragAndDropWrapper() { diff --git a/server/src/com/vaadin/ui/Flash.java b/server/src/com/vaadin/ui/Flash.java index 2d0f188b84..6e99d2fe35 100644 --- a/server/src/com/vaadin/ui/Flash.java +++ b/server/src/com/vaadin/ui/Flash.java @@ -15,6 +15,7 @@ */ package com.vaadin.ui; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -236,7 +237,15 @@ public class Flash extends AbstractEmbedded { @Override public void writeDesign(Element design, DesignContext designContext) { super.writeDesign(design, designContext); + + // Parameters, in alphabetic order + ArrayList<String> paramNames = new ArrayList<String>(); for (String param : getParameterNames()) { + paramNames.add(param); + } + + Collections.sort(paramNames); + for (String param : paramNames) { design.appendElement("parameter").attr("name", param) .attr("value", getParameter(param)); } diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index 43e82560df..77785c301b 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -3270,14 +3270,16 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, return getState().hidable; } - /* + /** * Writes the design attributes for this column into given element. * * @since 7.5.0 * - * @param design Element to write attributes into + * @param design + * Element to write attributes into * - * @param designContext the design context + * @param designContext + * the design context */ protected void writeDesign(Element design, DesignContext designContext) { Attributes attributes = design.attributes(); @@ -3367,20 +3369,27 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, /** * An abstract base class for server-side Grid renderers. * {@link com.vaadin.client.widget.grid.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 revision. + * currently extends the AbstractGridExtension superclass, 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 */ - public static abstract class AbstractRenderer<T> extends AbstractExtension - implements Renderer<T> { + public static abstract class AbstractRenderer<T> extends + AbstractGridExtension implements Renderer<T> { private final Class<T> presentationType; - protected AbstractRenderer(Class<T> presentationType) { + private final String nullRepresentation; + + protected AbstractRenderer(Class<T> presentationType, String nullRepresentation) { this.presentationType = presentationType; + this.nullRepresentation = nullRepresentation; + } + + protected AbstractRenderer(Class<T> presentationType) { + this(presentationType, null); } /** @@ -3410,7 +3419,19 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, @Override public JsonValue encode(T value) { - return encode(value, getPresentationType()); + 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; } /** @@ -3433,6 +3454,33 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, return JsonCodec.encode(value, null, type, getUI().getConnectorTracker()).getEncodedValue(); } + } + + /** + * An abstract base class for server-side Grid extensions. + * + * @since 7.5 + */ + public static abstract class AbstractGridExtension extends + AbstractExtension { + + /** + * Constructs a new Grid extension. + */ + public AbstractGridExtension() { + super(); + } + + /** + * Constructs a new Grid extension and extends given Grid. + * + * @param grid + * a grid instance + */ + public AbstractGridExtension(Grid grid) { + super(); + extend(grid); + } /** * Gets the item id for a row key. @@ -4416,6 +4464,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, * added for any property id in propertyIds that has no corresponding column * in this Grid. * + * @since 7.5.0 + * * @param propertyIds * properties in the desired column order */ @@ -5480,7 +5530,9 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, @Override public Iterator<Component> iterator() { - List<Component> componentList = new ArrayList<Component>(); + // This is a hash set to avoid adding header/footer components inside + // merged cells multiple times + LinkedHashSet<Component> componentList = new LinkedHashSet<Component>(); Header header = getHeader(); for (int i = 0; i < header.getRowCount(); ++i) { @@ -5797,6 +5849,13 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, column.getState().editorConnector = getEditorField(column .getPropertyId()); } + + // Must ensure that all fields, recursively, are sent to the client + // This is needed because the fields are hidden using isRendered + for (Field<?> f : getEditorFields()) { + f.markAsDirtyRecursive(); + } + } private void setEditorField(Object propertyId, Field<?> field) { @@ -6184,7 +6243,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, return datasourceExtension.isDetailsVisible(itemId); } - protected SelectionMode getDefaultSelectionMode() { + private static SelectionMode getDefaultSelectionMode() { return SelectionMode.SINGLE; } diff --git a/server/src/com/vaadin/ui/PasswordField.java b/server/src/com/vaadin/ui/PasswordField.java index 1894804775..ff3b1fea1f 100644 --- a/server/src/com/vaadin/ui/PasswordField.java +++ b/server/src/com/vaadin/ui/PasswordField.java @@ -113,4 +113,10 @@ public class PasswordField extends AbstractTextField { DesignAttributeHandler.writeAttribute("value", attr, getValue(), def.getValue(), String.class); } + + @Override + public void clear() { + setValue(""); + } + } diff --git a/server/src/com/vaadin/ui/PopupView.java b/server/src/com/vaadin/ui/PopupView.java index 12034cb56c..73c93b29f3 100644 --- a/server/src/com/vaadin/ui/PopupView.java +++ b/server/src/com/vaadin/ui/PopupView.java @@ -69,6 +69,8 @@ public class PopupView extends AbstractComponent implements HasComponents { /** * This is an internal constructor. Use * {@link PopupView#PopupView(String, Component)}Â instead. + * + * @since 7.5.0 */ @Deprecated public PopupView() { @@ -106,6 +108,8 @@ public class PopupView extends AbstractComponent implements HasComponents { /** * Creates a Content from given text representation and popup content. * + * @since 7.5.0 + * * @param minimizedValue * text representation when popup is hidden * @param popupContent diff --git a/server/src/com/vaadin/ui/ProgressBar.java b/server/src/com/vaadin/ui/ProgressBar.java index c288695ae1..89baac1e64 100644 --- a/server/src/com/vaadin/ui/ProgressBar.java +++ b/server/src/com/vaadin/ui/ProgressBar.java @@ -37,11 +37,13 @@ import com.vaadin.ui.declarative.DesignContext; public class ProgressBar extends AbstractField<Float> implements Property.Viewer, Property.ValueChangeListener { + private static final float DEFAULT_VALUE = 0f; + /** * Creates a new progress bar initially set to 0% progress. */ public ProgressBar() { - this(0); + this(DEFAULT_VALUE); } /** @@ -170,4 +172,15 @@ public class ProgressBar extends AbstractField<Float> implements DesignAttributeHandler.writeAttribute("value", design.attributes(), getValue(), defaultValue, Float.class); } + + @Override + public void clear() { + setValue(DEFAULT_VALUE); + } + + @Override + public boolean isEmpty() { + return super.isEmpty() || getValue() == DEFAULT_VALUE; + + } } diff --git a/server/src/com/vaadin/ui/RichTextArea.java b/server/src/com/vaadin/ui/RichTextArea.java index 763e42ad8b..7c23cce5cb 100644 --- a/server/src/com/vaadin/ui/RichTextArea.java +++ b/server/src/com/vaadin/ui/RichTextArea.java @@ -293,6 +293,11 @@ public class RichTextArea extends AbstractField<String> implements } @Override + public void clear() { + setValue(""); + } + + @Override public void readDesign(Element design, DesignContext designContext) { super.readDesign(design, designContext); setValue(design.html()); diff --git a/server/src/com/vaadin/ui/Slider.java b/server/src/com/vaadin/ui/Slider.java index 40a4047d53..2e00628eb0 100644 --- a/server/src/com/vaadin/ui/Slider.java +++ b/server/src/com/vaadin/ui/Slider.java @@ -104,9 +104,9 @@ public class Slider extends AbstractField<Double> { */ public Slider(double min, double max, int resolution) { this(); - setMin(min); - setMax(max); setResolution(resolution); + setMax(max); + setMin(min); } /** @@ -167,14 +167,15 @@ public class Slider extends AbstractField<Double> { * The new maximum slider value */ public void setMax(double max) { - getState().maxValue = max; + double roundedMax = getRoundedValue(max); + getState().maxValue = roundedMax; - if (getMin() > max) { - getState().minValue = max; + if (getMin() > roundedMax) { + getState().minValue = roundedMax; } - if (getValue() > max) { - setValue(max); + if (getValue() > roundedMax) { + setValue(roundedMax); } } @@ -195,14 +196,15 @@ public class Slider extends AbstractField<Double> { * The new minimum slider value */ public void setMin(double min) { - getState().minValue = min; + double roundedMin = getRoundedValue(min); + getState().minValue = roundedMin; - if (getMax() < min) { - getState().maxValue = min; + if (getMax() < roundedMin) { + getState().maxValue = roundedMin; } - if (getValue() < min) { - setValue(min); + if (getValue() < roundedMin) { + setValue(roundedMin); } } @@ -268,28 +270,28 @@ public class Slider extends AbstractField<Double> { */ @Override protected void setValue(Double value, boolean repaintIsNotNeeded) { - final double v = value.doubleValue(); - final int resolution = getResolution(); - double newValue; - - if (resolution > 0) { - // Round up to resolution - newValue = Math.floor(v * Math.pow(10, resolution)); - newValue = newValue / Math.pow(10, resolution); - if (getMin() > newValue || getMax() < newValue) { - throw new ValueOutOfBoundsException(newValue); - } - } else { - newValue = (int) v; - if (getMin() > newValue || getMax() < newValue) { - throw new ValueOutOfBoundsException(newValue); - } + double newValue = getRoundedValue(value); + + if (getMin() > newValue || getMax() < newValue) { + throw new ValueOutOfBoundsException(newValue); } getState().value = newValue; super.setValue(newValue, repaintIsNotNeeded); } + private double getRoundedValue(Double value) { + final double v = value.doubleValue(); + final int resolution = getResolution(); + + double ratio = Math.pow(10, resolution); + if(v >= 0) { + return Math.floor(v * ratio) / ratio; + } else { + return Math.ceil(v * ratio) / ratio; + } + } + @Override public void setValue(Double newFieldValue) { super.setValue(newFieldValue); diff --git a/server/src/com/vaadin/ui/TextArea.java b/server/src/com/vaadin/ui/TextArea.java index c8103f9c5b..b4dfb209e8 100644 --- a/server/src/com/vaadin/ui/TextArea.java +++ b/server/src/com/vaadin/ui/TextArea.java @@ -159,4 +159,10 @@ public class TextArea extends AbstractTextField { super.writeDesign(design, designContext); design.html(getValue()); } + + @Override + public void clear() { + setValue(""); + } + } diff --git a/server/src/com/vaadin/ui/Tree.java b/server/src/com/vaadin/ui/Tree.java index 48f4e54831..aac827e5b5 100644 --- a/server/src/com/vaadin/ui/Tree.java +++ b/server/src/com/vaadin/ui/Tree.java @@ -273,7 +273,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical, * @param sendChildTree * flag to indicate if client needs subtree or not (may be * cached) - * @return True iff the expand operation succeeded + * @return True if the expand operation succeeded */ private boolean expandItem(Object itemId, boolean sendChildTree) { diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 8dd600ddd0..b16d7e32d3 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -16,6 +16,8 @@ package com.vaadin.ui; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Collection; @@ -67,6 +69,7 @@ import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.shared.ui.ui.UIServerRpc; import com.vaadin.shared.ui.ui.UIState; import com.vaadin.ui.Component.Focusable; +import com.vaadin.ui.declarative.Design; import com.vaadin.util.ConnectorHelper; import com.vaadin.util.CurrentInstance; @@ -211,6 +214,32 @@ public abstract class UI extends AbstractSingleComponentContainer implements json.toString()); } + @Override + public void showServerDesign(Connector connector) { + if (!(connector instanceof Component)) { + getLogger().severe( + "Tried to output declarative design for " + connector + + ", which is not a component"); + return; + } + if (connector instanceof UI) { + // We want to see the content of the UI, so we can add it to + // another UI or component container + connector = ((UI) connector).getContent(); + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + Design.write((Component) connector, baos); + getLogger().info( + "Design for " + connector + + " requested from debug window:\n" + + baos.toString("UTF-8")); + } catch (IOException e) { + getLogger().log(Level.WARNING, + "Error producing design for " + connector, e); + } + + } }; /** diff --git a/server/src/com/vaadin/ui/Window.java b/server/src/com/vaadin/ui/Window.java index e7764ffd8d..61664fc95d 100644 --- a/server/src/com/vaadin/ui/Window.java +++ b/server/src/com/vaadin/ui/Window.java @@ -21,9 +21,6 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -133,7 +130,6 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, super(caption, content); registerRpc(rpc); setSizeUndefined(); - setCloseShortcut(ShortcutAction.KeyCode.ESCAPE); } /* ********************************************************************* */ @@ -820,48 +816,14 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, /* * Actions */ - private LinkedHashSet<CloseShortcut> closeShortcuts = new LinkedHashSet<CloseShortcut>(); - - protected Collection<CloseShortcut> getCloseShortcuts() { - return Collections.unmodifiableCollection(closeShortcuts); - } - - /** - * Adds a keyboard shortcut for closing the window when user presses the - * given {@link KeyCode} and (optional) {@link ModifierKey}s.<br/> - * Note that this shortcut only reacts while the window has focus, closing - * itself - if you want to close a window from a UI, use - * {@link UI#addAction(com.vaadin.event.Action)} of the UI instead. - * <p> - * If there is a prior CloseShortcut with the same keycode and modifiers, - * that gets removed before the new one is added. Prior CloseShortcuts with - * differing keycodes or modifiers are not affected. - * - * @param keyCode - * the keycode for invoking the shortcut - * @param modifiers - * the (optional) modifiers for invoking the shortcut, null for - * none - */ - public void addCloseShortcut(int keyCode, int... modifiers) { - // make sure there are no duplicates - removeCloseShortcut(keyCode, modifiers); - CloseShortcut closeShortcut = new CloseShortcut(this, keyCode, - modifiers); - closeShortcuts.add(closeShortcut); - addAction(closeShortcut); - } + protected CloseShortcut closeShortcut; /** - * Sets the keyboard shortcut for closing the window when user presses the - * given {@link KeyCode} and (optional) {@link ModifierKey}s.<br/> + * Makes is possible to close the window by pressing the given + * {@link KeyCode} and (optional) {@link ModifierKey}s.<br/> * Note that this shortcut only reacts while the window has focus, closing * itself - if you want to close a window from a UI, use * {@link UI#addAction(com.vaadin.event.Action)} of the UI instead. - * <p> - * If there are any prior CloseShortcuts when this method is called those - * get removed before the new one is added. <b>NOTE: this also removes the - * default shortcut that is added for accessibility purposes.</b> * * @param keyCode * the keycode for invoking the shortcut @@ -870,61 +832,22 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, * none */ public void setCloseShortcut(int keyCode, int... modifiers) { - removeCloseShortcuts(); - addCloseShortcut(keyCode, modifiers); - } - - /** - * Removes a keyboard shortcut previously set with - * {@link #setCloseShortcut(int, int...)} or - * {@link #addCloseShortcut(int, int...)}. - * - * @param keyCode - * the keycode for invoking the shortcut - * @param modifiers - * the (optional) modifiers for invoking the shortcut, null for - * none - */ - public void removeCloseShortcut(int keyCode, int... modifiers) { - for (CloseShortcut closeShortcut : closeShortcuts) { - if (closeShortcut.isTriggeredBy(keyCode, modifiers)) { - removeAction(closeShortcut); - closeShortcuts.remove(closeShortcut); - break; - } + if (closeShortcut != null) { + removeAction(closeShortcut); } + closeShortcut = new CloseShortcut(this, keyCode, modifiers); + addAction(closeShortcut); } /** - * @deprecated use {@link #resetCloseShortcuts()} instead, or - * {@link #removeCloseShortcuts()} if you also want to get rid - * of the default shortcut + * Removes the keyboard shortcut previously set with + * {@link #setCloseShortcut(int, int...)}. */ - @Deprecated public void removeCloseShortcut() { - resetCloseShortcuts(); - } - - /** - * Removes all the keyboard shortcuts previously set with - * {@link #setCloseShortcut(int, int...)} or - * {@link #addCloseShortcut(int, int...)} and re-adds the default shortcut - * {@link KeyCode.ESCAPE}. - */ - public void resetCloseShortcuts() { - setCloseShortcut(ShortcutAction.KeyCode.ESCAPE); - } - - /** - * Removes all the keyboard shortcuts previously set with - * {@link #setCloseShortcut(int, int...)} or - * {@link #addCloseShortcut(int, int...)}. - */ - public void removeCloseShortcuts() { - for (CloseShortcut closeShortcut : closeShortcuts) { + if (closeShortcut != null) { removeAction(closeShortcut); + closeShortcut = null; } - closeShortcuts.clear(); } /** @@ -1391,8 +1314,7 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, } private CloseShortcut getCloseShortcut() { - Iterator<CloseShortcut> i = getCloseShortcuts().iterator(); - return i.hasNext() ? i.next() : null; + return closeShortcut; } @Override diff --git a/server/src/com/vaadin/ui/declarative/DesignContext.java b/server/src/com/vaadin/ui/declarative/DesignContext.java index d6cb970ce8..0d68c22ea0 100644 --- a/server/src/com/vaadin/ui/declarative/DesignContext.java +++ b/server/src/com/vaadin/ui/declarative/DesignContext.java @@ -171,6 +171,8 @@ public class DesignContext implements Serializable { * component was mapped to some string s different from localId, the mapping * from s to component is removed. * + * @since 7.5.0 + * * @param component * The component whose local id is to be set. * @param localId @@ -186,7 +188,9 @@ public class DesignContext implements Serializable { } /** - * Returns the local id for a component + * Returns the local id for a component. + * + * @since 7.5.0 * * @param component * The component whose local id to get. diff --git a/server/src/com/vaadin/ui/declarative/FieldBinder.java b/server/src/com/vaadin/ui/declarative/FieldBinder.java index bd906682fa..577e9f5515 100644 --- a/server/src/com/vaadin/ui/declarative/FieldBinder.java +++ b/server/src/com/vaadin/ui/declarative/FieldBinder.java @@ -204,11 +204,14 @@ public class FieldBinder implements Serializable { } return true; } catch (IllegalAccessException e) { - throw new FieldBindingException("Field binding failed", e); + throw new FieldBindingException("Field binding failed for " + + identifier, e); } catch (IllegalArgumentException e) { - throw new FieldBindingException("Field binding failed", e); + throw new FieldBindingException("Field binding failed for " + + identifier, e); } catch (InvocationTargetException e) { - throw new FieldBindingException("Field binding failed", e); + throw new FieldBindingException("Field binding failed for " + + identifier, e); } } diff --git a/server/src/com/vaadin/ui/declarative/converters/DesignResourceConverter.java b/server/src/com/vaadin/ui/declarative/converters/DesignResourceConverter.java index ff73b61eb2..ffa51fedd1 100644 --- a/server/src/com/vaadin/ui/declarative/converters/DesignResourceConverter.java +++ b/server/src/com/vaadin/ui/declarative/converters/DesignResourceConverter.java @@ -28,8 +28,8 @@ import com.vaadin.server.FontAwesome; import com.vaadin.server.FontIcon; import com.vaadin.server.GenericFontIcon; import com.vaadin.server.Resource; +import com.vaadin.server.ResourceReference; import com.vaadin.server.ThemeResource; -import com.vaadin.shared.ApplicationConstants; import com.vaadin.ui.declarative.DesignAttributeHandler; /** @@ -109,8 +109,7 @@ public class DesignResourceConverter implements Converter<String, Resource> { @Override public String format(Resource value) throws Converter.ConversionException { - return ApplicationConstants.THEME_PROTOCOL_PREFIX - + ((ThemeResource) value).getResourceId(); + return new ResourceReference(value, null, null).getURL(); } }, FONTICON { @@ -118,8 +117,7 @@ public class DesignResourceConverter implements Converter<String, Resource> { public Resource parse(String value) { final String address = (value.split("://", 2))[1]; final String[] familyAndCode = address.split("/", 2); - final int codepoint = Integer.valueOf( - familyAndCode[1].substring(2), 16); + final int codepoint = Integer.valueOf(familyAndCode[1], 16); if (FontAwesome.FONT_FAMILY.equals(familyAndCode[0])) { try { @@ -141,9 +139,8 @@ public class DesignResourceConverter implements Converter<String, Resource> { public String format(Resource value) throws Converter.ConversionException { FontIcon icon = (FontIcon) value; - return ApplicationConstants.FONTICON_PROTOCOL_PREFIX - + icon.getFontFamily() + "/0x" - + Integer.toHexString(icon.getCodepoint()); + return new ResourceReference(icon, null, null).getURL(); + } }, @Deprecated diff --git a/server/src/com/vaadin/ui/renderers/AbstractJavaScriptRenderer.java b/server/src/com/vaadin/ui/renderers/AbstractJavaScriptRenderer.java index bed34cf6e3..104e07f02f 100644 --- a/server/src/com/vaadin/ui/renderers/AbstractJavaScriptRenderer.java +++ b/server/src/com/vaadin/ui/renderers/AbstractJavaScriptRenderer.java @@ -105,8 +105,12 @@ public abstract class AbstractJavaScriptRenderer<T> extends AbstractRenderer<T> private JavaScriptCallbackHelper callbackHelper = new JavaScriptCallbackHelper( this); + protected AbstractJavaScriptRenderer(Class<T> presentationType, String nullRepresentation) { + super(presentationType, nullRepresentation); + } + protected AbstractJavaScriptRenderer(Class<T> presentationType) { - super(presentationType); + super(presentationType, null); } @Override diff --git a/server/src/com/vaadin/ui/renderers/ButtonRenderer.java b/server/src/com/vaadin/ui/renderers/ButtonRenderer.java index 0b070d3f69..a747e45713 100644 --- a/server/src/com/vaadin/ui/renderers/ButtonRenderer.java +++ b/server/src/com/vaadin/ui/renderers/ButtonRenderer.java @@ -15,6 +15,8 @@ */ package com.vaadin.ui.renderers; +import elemental.json.JsonValue; + /** * A Renderer that displays a button with a textual caption. The value of the * corresponding property is used as the caption. Click listeners can be added @@ -27,9 +29,12 @@ public class ButtonRenderer extends ClickableRenderer<String> { /** * Creates a new button renderer. + * + * @param nullRepresentation + * the textual representation of {@code null} value */ - public ButtonRenderer() { - super(String.class); + public ButtonRenderer(String nullRepresentation) { + super(String.class, nullRepresentation); } /** @@ -37,9 +42,34 @@ public class ButtonRenderer extends ClickableRenderer<String> { * * @param listener * the click listener to register + * @param nullRepresentation + * the textual representation of {@code null} value */ - public ButtonRenderer(RendererClickListener listener) { - this(); + public ButtonRenderer(RendererClickListener listener, String nullRepresentation) { + this(nullRepresentation); addClickListener(listener); } + + /** + * Creates a new button renderer. + */ + public ButtonRenderer() { + this(""); + } + + /** + * Creates a new button renderer and adds the given click listener to it. + * + * @param listener + * the click listener to register + */ + public ButtonRenderer(RendererClickListener listener) { + this(listener, ""); + } + + @Override + public String getNullRepresentation() { + return super.getNullRepresentation(); + } + } diff --git a/server/src/com/vaadin/ui/renderers/ClickableRenderer.java b/server/src/com/vaadin/ui/renderers/ClickableRenderer.java index 38e9acef9c..01e939bb67 100644 --- a/server/src/com/vaadin/ui/renderers/ClickableRenderer.java +++ b/server/src/com/vaadin/ui/renderers/ClickableRenderer.java @@ -103,7 +103,11 @@ public class ClickableRenderer<T> extends AbstractRenderer<T> { } protected ClickableRenderer(Class<T> presentationType) { - super(presentationType); + this(presentationType, null); + } + + protected ClickableRenderer(Class<T> presentationType, String nullRepresentation) { + super(presentationType, nullRepresentation); registerRpc(new RendererClickRpc() { @Override public void click(String rowKey, String columnId, diff --git a/server/src/com/vaadin/ui/renderers/DateRenderer.java b/server/src/com/vaadin/ui/renderers/DateRenderer.java index 9dd4d19e87..092b3f405e 100644 --- a/server/src/com/vaadin/ui/renderers/DateRenderer.java +++ b/server/src/com/vaadin/ui/renderers/DateRenderer.java @@ -41,7 +41,7 @@ public class DateRenderer extends AbstractRenderer<Date> { * representation for the default locale. */ public DateRenderer() { - this(Locale.getDefault()); + this(Locale.getDefault(), ""); } /** @@ -56,7 +56,24 @@ public class DateRenderer extends AbstractRenderer<Date> { * if {@code locale} is {@code null} */ public DateRenderer(Locale locale) throws IllegalArgumentException { - this("%s", locale); + 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); } /** @@ -74,7 +91,27 @@ public class DateRenderer extends AbstractRenderer<Date> { * String Syntax</a> */ public DateRenderer(String formatString) throws IllegalArgumentException { - this(formatString, Locale.getDefault()); + 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); } /** @@ -95,7 +132,29 @@ public class DateRenderer extends AbstractRenderer<Date> { */ public DateRenderer(String formatString, Locale locale) throws IllegalArgumentException { - super(Date.class); + 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"); @@ -121,7 +180,20 @@ public class DateRenderer extends AbstractRenderer<Date> { * if {@code dateFormat} is {@code null} */ public DateRenderer(DateFormat dateFormat) throws IllegalArgumentException { - super(Date.class); + 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"); } @@ -132,9 +204,16 @@ public class DateRenderer extends AbstractRenderer<Date> { } @Override + public String getNullRepresentation() { + return super.getNullRepresentation(); + } + + @Override public JsonValue encode(Date value) { String dateString; - if (dateFormat != null) { + if (value == null) { + dateString = getNullRepresentation(); + } else if (dateFormat != null) { dateString = dateFormat.format(value); } else { dateString = String.format(locale, formatString, value); diff --git a/server/src/com/vaadin/ui/renderers/HtmlRenderer.java b/server/src/com/vaadin/ui/renderers/HtmlRenderer.java index 34774b3825..df89c60ad2 100644 --- a/server/src/com/vaadin/ui/renderers/HtmlRenderer.java +++ b/server/src/com/vaadin/ui/renderers/HtmlRenderer.java @@ -16,18 +16,33 @@ package com.vaadin.ui.renderers; import com.vaadin.ui.Grid.AbstractRenderer; +import elemental.json.JsonValue; /** * A renderer for presenting HTML content. - * - * @since 7.4 + * * @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() { - super(String.class); + this(""); + } + + @Override + public String getNullRepresentation() { + return super.getNullRepresentation(); } } diff --git a/server/src/com/vaadin/ui/renderers/ImageRenderer.java b/server/src/com/vaadin/ui/renderers/ImageRenderer.java index 4bb3671033..2fb872583e 100644 --- a/server/src/com/vaadin/ui/renderers/ImageRenderer.java +++ b/server/src/com/vaadin/ui/renderers/ImageRenderer.java @@ -39,7 +39,7 @@ public class ImageRenderer extends ClickableRenderer<Resource> { * Creates a new image renderer. */ public ImageRenderer() { - super(Resource.class); + super(Resource.class, null); } /** @@ -55,7 +55,7 @@ public class ImageRenderer extends ClickableRenderer<Resource> { @Override public JsonValue encode(Resource resource) { - if (!(resource instanceof ExternalResource || resource instanceof ThemeResource)) { + if (!(resource == null || resource instanceof ExternalResource || resource instanceof ThemeResource)) { throw new IllegalArgumentException( "ImageRenderer only supports ExternalResource and ThemeResource (" + resource.getClass().getSimpleName() + "given )"); diff --git a/server/src/com/vaadin/ui/renderers/NumberRenderer.java b/server/src/com/vaadin/ui/renderers/NumberRenderer.java index 5c30e55b17..1d4d7e0ec9 100644 --- a/server/src/com/vaadin/ui/renderers/NumberRenderer.java +++ b/server/src/com/vaadin/ui/renderers/NumberRenderer.java @@ -24,7 +24,7 @@ import elemental.json.JsonValue; /** * A renderer for presenting number values. - * + * * @since 7.4 * @author Vaadin Ltd */ @@ -35,7 +35,7 @@ public class NumberRenderer extends AbstractRenderer<Number> { /** * Creates a new number renderer. - * <p> + * <p/> * The renderer is configured to render with the number's natural string * representation in the default locale. */ @@ -45,18 +45,35 @@ public class NumberRenderer extends AbstractRenderer<Number> { /** * Creates a new number renderer. - * <p> + * <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) + 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); + super(Number.class, nullRepresentation); if (numberFormat == null) { throw new IllegalArgumentException("Number format may not be null"); @@ -69,10 +86,10 @@ public class NumberRenderer extends AbstractRenderer<Number> { /** * Creates a new number renderer. - * <p> + * <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 @@ -84,12 +101,29 @@ public class NumberRenderer extends AbstractRenderer<Number> { /** * Creates a new number renderer. - * <p> - * The renderer is configured to render with the given format string in the - * default locale. - * + * <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 @@ -97,15 +131,15 @@ public class NumberRenderer extends AbstractRenderer<Number> { * String Syntax</a> */ public NumberRenderer(String formatString) throws IllegalArgumentException { - this(formatString, Locale.getDefault()); + this(formatString, Locale.getDefault(), ""); } /** * Creates a new number renderer. - * <p> + * <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 @@ -116,8 +150,8 @@ public class NumberRenderer extends AbstractRenderer<Number> { * href="http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax">Format * String Syntax</a> */ - public NumberRenderer(String formatString, Locale locale) { - super(Number.class); + public NumberRenderer(String formatString, Locale locale, String nullRepresentation) { + super(Number.class, nullRepresentation); if (formatString == null) { throw new IllegalArgumentException("Format string may not be null"); @@ -135,7 +169,9 @@ public class NumberRenderer extends AbstractRenderer<Number> { @Override public JsonValue encode(Number value) { String stringValue; - if (formatString != null && locale != null) { + 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); @@ -160,4 +196,9 @@ public class NumberRenderer extends AbstractRenderer<Number> { return String.format("%s [%s]", getClass().getSimpleName(), fieldInfo); } + + @Override + public String getNullRepresentation() { + return super.getNullRepresentation(); + } } diff --git a/server/src/com/vaadin/ui/renderers/ProgressBarRenderer.java b/server/src/com/vaadin/ui/renderers/ProgressBarRenderer.java index a077cd8012..1566c47222 100644 --- a/server/src/com/vaadin/ui/renderers/ProgressBarRenderer.java +++ b/server/src/com/vaadin/ui/renderers/ProgressBarRenderer.java @@ -21,9 +21,9 @@ import elemental.json.JsonValue; /** * A renderer that represents a double values as a graphical progress bar. - * - * @since 7.4 + * * @author Vaadin Ltd + * @since 7.4 */ public class ProgressBarRenderer extends AbstractRenderer<Double> { @@ -31,13 +31,15 @@ public class ProgressBarRenderer extends AbstractRenderer<Double> { * Creates a new text renderer */ public ProgressBarRenderer() { - super(Double.class); + 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); } diff --git a/server/src/com/vaadin/ui/renderers/TextRenderer.java b/server/src/com/vaadin/ui/renderers/TextRenderer.java index 3723a45f70..0045024b2f 100644 --- a/server/src/com/vaadin/ui/renderers/TextRenderer.java +++ b/server/src/com/vaadin/ui/renderers/TextRenderer.java @@ -16,6 +16,7 @@ package com.vaadin.ui.renderers; import com.vaadin.ui.Grid.AbstractRenderer; +import elemental.json.JsonValue; /** * A renderer for presenting simple plain-text string values. @@ -29,6 +30,20 @@ public class TextRenderer extends AbstractRenderer<String> { * Creates a new text renderer */ public TextRenderer() { - super(String.class); + 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(); } } diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java index c70462012e..b2cc9a5d0c 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTableQueryTest.java @@ -29,9 +29,9 @@ import com.vaadin.data.Item; import com.vaadin.data.util.filter.Like; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants.DB; import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; -import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.OrderBy; import com.vaadin.data.util.sqlcontainer.query.TableQuery; +import com.vaadin.data.util.sqlcontainer.query.ValidatingSimpleJDBCConnectionPool; public class SQLContainerTableQueryTest { @@ -51,7 +51,7 @@ public class SQLContainerTableQueryTest { public void setUp() throws SQLException { try { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); } catch (SQLException e) { @@ -99,7 +99,7 @@ public class SQLContainerTableQueryTest { assertTrue(container.removeItem(container.lastItemId())); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = SQLException.class) public void itemWithNonExistingVersionColumnCannotBeRemoved() throws SQLException { query.setVersionColumn("version"); diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTest.java index 4c132eba30..a332d9d9ee 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLContainerTest.java @@ -26,11 +26,11 @@ import com.vaadin.data.util.filter.Compare.Equal; import com.vaadin.data.util.filter.Like; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants.DB; import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; -import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.FreeformQuery; import com.vaadin.data.util.sqlcontainer.query.FreeformQueryDelegate; import com.vaadin.data.util.sqlcontainer.query.FreeformStatementDelegate; import com.vaadin.data.util.sqlcontainer.query.OrderBy; +import com.vaadin.data.util.sqlcontainer.query.ValidatingSimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.generator.MSSQLGenerator; import com.vaadin.data.util.sqlcontainer.query.generator.OracleGenerator; import com.vaadin.data.util.sqlcontainer.query.generator.SQLGenerator; @@ -45,7 +45,7 @@ public class SQLContainerTest { public void setUp() throws SQLException { try { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); } catch (SQLException e) { diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/TicketTests.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/TicketTests.java index 110225e206..e180e3f3e7 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/TicketTests.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/TicketTests.java @@ -16,10 +16,11 @@ import com.vaadin.data.Container.Filter; import com.vaadin.data.Item; import com.vaadin.data.util.filter.Compare.Equal; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants.DB; -import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; +import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.FreeformQuery; import com.vaadin.data.util.sqlcontainer.query.FreeformStatementDelegate; import com.vaadin.data.util.sqlcontainer.query.TableQuery; +import com.vaadin.data.util.sqlcontainer.query.ValidatingSimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; import com.vaadin.data.util.sqlcontainer.query.generator.filter.QueryBuilder; import com.vaadin.ui.Table; @@ -27,11 +28,11 @@ import com.vaadin.ui.Window; public class TicketTests { - private SimpleJDBCConnectionPool connectionPool; + private JDBCConnectionPool connectionPool; @Before public void setUp() throws SQLException { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); DataGenerator.addPeopleToDatabase(connectionPool); diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPoolTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPoolTest.java index 99ad420229..b786f5b2de 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPoolTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPoolTest.java @@ -9,13 +9,14 @@ import org.junit.Before; import org.junit.Test; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants; +import com.vaadin.data.util.sqlcontainer.query.ValidatingSimpleJDBCConnectionPool; public class SimpleJDBCConnectionPoolTest { private JDBCConnectionPool connectionPool; @Before public void setUp() throws SQLException { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); } @@ -145,8 +146,11 @@ public class SimpleJDBCConnectionPoolTest { EasyMock.expectLastCall().atLeastOnce(); EasyMock.replay(c); // make sure the connection pool is initialized - connectionPool.reserveConnection(); - connectionPool.releaseConnection(c); + // Bypass validation + JDBCConnectionPool realPool = ((ValidatingSimpleJDBCConnectionPool) connectionPool) + .getRealPool(); + realPool.reserveConnection(); + realPool.releaseConnection(c); EasyMock.verify(c); } @@ -154,7 +158,13 @@ public class SimpleJDBCConnectionPoolTest { public void destroy_shouldCloseAllConnections() throws SQLException { Connection c1 = connectionPool.reserveConnection(); Connection c2 = connectionPool.reserveConnection(); - connectionPool.destroy(); + try { + connectionPool.destroy(); + } catch (RuntimeException e) { + // The test connection pool throws an exception when the pool was + // not empty but only after cleanup of the real pool has been done + } + Assert.assertTrue(c1.isClosed()); Assert.assertTrue(c2.isClosed()); } diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/generator/SQLGeneratorsTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/generator/SQLGeneratorsTest.java index 59e879a8e0..c2dbf0f12a 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/generator/SQLGeneratorsTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/generator/SQLGeneratorsTest.java @@ -18,9 +18,9 @@ import com.vaadin.data.util.sqlcontainer.RowItem; import com.vaadin.data.util.sqlcontainer.SQLContainer; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants; import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; -import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.OrderBy; import com.vaadin.data.util.sqlcontainer.query.TableQuery; +import com.vaadin.data.util.sqlcontainer.query.ValidatingSimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.generator.DefaultSQLGenerator; import com.vaadin.data.util.sqlcontainer.query.generator.MSSQLGenerator; import com.vaadin.data.util.sqlcontainer.query.generator.OracleGenerator; @@ -34,7 +34,7 @@ public class SQLGeneratorsTest { public void setUp() throws SQLException { try { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); } catch (SQLException e) { diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/query/FreeformQueryTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/FreeformQueryTest.java index 195911475e..e193b79df3 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/query/FreeformQueryTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/FreeformQueryTest.java @@ -23,7 +23,6 @@ import com.vaadin.data.util.sqlcontainer.SQLContainer; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants.DB; import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; -import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; public class FreeformQueryTest { @@ -34,7 +33,7 @@ public class FreeformQueryTest { public void setUp() throws SQLException { try { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); } catch (SQLException e) { @@ -148,7 +147,10 @@ public class FreeformQueryTest { connectionPool, "ID"); query.getCount(); query.getCount(); - Assert.assertNotNull(connectionPool.reserveConnection()); + Connection c = connectionPool.reserveConnection(); + Assert.assertNotNull(c); + // Cleanup to make test connection pool happy + connectionPool.releaseConnection(c); } @Test @@ -276,37 +278,38 @@ public class FreeformQueryTest { new Object[] { 1 }), null)); } - @Test(expected = UnsupportedOperationException.class) + @Test public void storeRow_noDelegate_shouldFail() throws SQLException { FreeformQuery query = new FreeformQuery("SELECT * FROM people", Arrays.asList("ID"), connectionPool); SQLContainer container = EasyMock.createNiceMock(SQLContainer.class); EasyMock.replay(container); query.beginTransaction(); - query.storeRow(new RowItem(container, new RowId(new Object[] { 1 }), - null)); - query.commit(); - EasyMock.verify(container); + try { + query.storeRow(new RowItem(container, + new RowId(new Object[] { 1 }), null)); + Assert.fail("storeRow should fail when there is no delegate"); + } catch (UnsupportedOperationException e) { + // Cleanup to make test connection pool happy + query.rollback(); + } } - @Test(expected = UnsupportedOperationException.class) + @Test public void removeRow_noDelegate_shouldFail() throws SQLException { FreeformQuery query = new FreeformQuery("SELECT * FROM people", Arrays.asList("ID"), connectionPool); SQLContainer container = EasyMock.createNiceMock(SQLContainer.class); EasyMock.replay(container); query.beginTransaction(); - query.removeRow(new RowItem(container, new RowId(new Object[] { 1 }), - null)); - query.commit(); - EasyMock.verify(container); - } - - @Test - public void beginTransaction_readOnly_shouldSucceed() throws SQLException { - FreeformQuery query = new FreeformQuery("SELECT * FROM people", - Arrays.asList("ID"), connectionPool); - query.beginTransaction(); + try { + query.removeRow(new RowItem(container, + new RowId(new Object[] { 1 }), null)); + Assert.fail("removeRow should fail when there is no delgate"); + } catch (UnsupportedOperationException e) { + // Cleanup to make test connection pool happy + query.rollback(); + } } @Test @@ -628,7 +631,7 @@ public class FreeformQueryTest { EasyMock.verify(delegate, container); } - @Test(expected = UnsupportedOperationException.class) + @Test public void storeRow_delegateDoesNotImplementStoreRow_shouldFail() throws SQLException { FreeformQuery query = new FreeformQuery("SELECT * FROM people", @@ -646,10 +649,13 @@ public class FreeformQueryTest { query.beginTransaction(); RowItem row = new RowItem(container, new RowId(new Object[] { 1 }), null); - query.storeRow(row); - query.commit(); - - EasyMock.verify(delegate, container); + try { + query.storeRow(row); + Assert.fail("storeRow should fail when delgate does not implement storeRow"); + } catch (UnsupportedOperationException e) { + // Cleanup to make test connection pool happy + query.rollback(); + } } @Test @@ -675,7 +681,7 @@ public class FreeformQueryTest { EasyMock.verify(delegate, container); } - @Test(expected = UnsupportedOperationException.class) + @Test public void removeRow_delegateDoesNotImplementRemoveRow_shouldFail() throws SQLException { FreeformQuery query = new FreeformQuery("SELECT * FROM people", @@ -693,10 +699,13 @@ public class FreeformQueryTest { query.beginTransaction(); RowItem row = new RowItem(container, new RowId(new Object[] { 1 }), null); - query.removeRow(row); - query.commit(); - - EasyMock.verify(delegate, container); + try { + query.removeRow(row); + Assert.fail("removeRow should fail when delegate does not implement removeRow"); + } catch (UnsupportedOperationException e) { + // Cleanup to make test connection pool happy + query.rollback(); + } } @Test @@ -710,16 +719,24 @@ public class FreeformQueryTest { query.setDelegate(delegate); query.beginTransaction(); + // Cleanup to make test connection pool happy + query.rollback(); } - @Test(expected = IllegalStateException.class) + @Test public void beginTransaction_transactionAlreadyActive_shouldFail() throws SQLException { FreeformQuery query = new FreeformQuery("SELECT * FROM people", Arrays.asList("ID"), connectionPool); query.beginTransaction(); - query.beginTransaction(); + try { + query.beginTransaction(); + Assert.fail("Should throw exception when starting a transaction while already in a transaction"); + } catch (IllegalStateException e) { + // Cleanup to make test connection pool happy + query.rollback(); + } } @Test(expected = SQLException.class) diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java index f009fc505e..1cb3d722c6 100644 --- a/server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java @@ -24,7 +24,6 @@ import com.vaadin.data.util.sqlcontainer.SQLContainer; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants; import com.vaadin.data.util.sqlcontainer.SQLTestsConstants.DB; import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; -import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.generator.DefaultSQLGenerator; public class TableQueryTest { @@ -33,16 +32,14 @@ public class TableQueryTest { @Before public void setUp() throws SQLException { - try { - connectionPool = new SimpleJDBCConnectionPool( + connectionPool = new ValidatingSimpleJDBCConnectionPool( SQLTestsConstants.dbDriver, SQLTestsConstants.dbURL, SQLTestsConstants.dbUser, SQLTestsConstants.dbPwd, 2, 2); } catch (SQLException e) { e.printStackTrace(); Assert.fail(e.getMessage()); } - DataGenerator.addPeopleToDatabase(connectionPool); } @@ -139,7 +136,9 @@ public class TableQueryTest { SQLTestsConstants.sqlGen); tQuery.getCount(); tQuery.getCount(); - Assert.assertNotNull(connectionPool.reserveConnection()); + Connection c = connectionPool.reserveConnection(); + Assert.assertNotNull(c); + connectionPool.releaseConnection(c); } /********************************************************************** @@ -193,20 +192,19 @@ public class TableQueryTest { * TableQuery transaction management tests **********************************************************************/ @Test - public void beginTransaction_readOnly_shouldSucceed() throws SQLException { - TableQuery tQuery = new TableQuery("people", connectionPool, - SQLTestsConstants.sqlGen); - tQuery.beginTransaction(); - } - - @Test(expected = IllegalStateException.class) public void beginTransaction_transactionAlreadyActive_shouldFail() throws SQLException { TableQuery tQuery = new TableQuery("people", connectionPool, SQLTestsConstants.sqlGen); tQuery.beginTransaction(); - tQuery.beginTransaction(); + try { + tQuery.beginTransaction(); + Assert.fail("Should throw exception when starting a transaction while already in a transaction"); + } catch (IllegalStateException e) { + // Cleanup to make test connection pool happy + tQuery.rollback(); + } } @Test @@ -284,8 +282,13 @@ public class TableQueryTest { .fail("null should throw an IllegalArgumentException from StatementHelper"); } catch (IllegalArgumentException e) { // We should now be able to reserve two connections - connectionPool.reserveConnection(); - connectionPool.reserveConnection(); + Connection c1 = connectionPool.reserveConnection(); + Connection c2 = connectionPool.reserveConnection(); + + // Cleanup to make test connection pool happy + connectionPool.releaseConnection(c1); + connectionPool.releaseConnection(c2); + } } @@ -693,6 +696,9 @@ public class TableQueryTest { // cleanup - might not be an in-memory DB statement.execute(SQLTestsConstants.dropSchema); } + + // Cleanup to make test connection pool happy + connectionPool.releaseConnection(conn); } @Test diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/query/ValidatingSimpleJDBCConnectionPool.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/ValidatingSimpleJDBCConnectionPool.java new file mode 100644 index 0000000000..464f3c8562 --- /dev/null +++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/ValidatingSimpleJDBCConnectionPool.java @@ -0,0 +1,89 @@ +/* + * Copyright 2000-2014 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.data.util.sqlcontainer.query; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Logger; + +import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; +import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; + +/** + * Connection pool for testing SQLContainer. Ensures that only reserved + * connections are released and that all connections are released before the + * pool is destroyed. + * + * @author Vaadin Ltd + */ +public class ValidatingSimpleJDBCConnectionPool implements JDBCConnectionPool { + + private JDBCConnectionPool realPool; + private Set<Connection> reserved = new HashSet<Connection>(); + private Set<Connection> alreadyReleased = new HashSet<Connection>(); + + public ValidatingSimpleJDBCConnectionPool(String driverName, + String connectionUri, String userName, String password, + int initialConnections, int maxConnections) throws SQLException { + realPool = new SimpleJDBCConnectionPool(driverName, connectionUri, + userName, password, initialConnections, maxConnections); + } + + @Deprecated + public JDBCConnectionPool getRealPool() { + return realPool; + } + + @Override + public Connection reserveConnection() throws SQLException { + Connection c = realPool.reserveConnection(); + reserved.add(c); + return c; + } + + @Override + public void releaseConnection(Connection conn) { + if (conn != null && !reserved.remove(conn)) { + if (alreadyReleased.contains(conn)) { + getLogger().severe( + "Tried to release connection (" + conn + + ") which has already been released"); + } else { + throw new RuntimeException("Tried to release connection (" + + conn + ") not reserved using reserveConnection"); + } + } + realPool.releaseConnection(conn); + alreadyReleased.add(conn); + + } + + @Override + public void destroy() { + realPool.destroy(); + if (!reserved.isEmpty()) { + throw new RuntimeException(reserved.size() + + " connections never released"); + } + } + + public static Logger getLogger() { + return Logger.getLogger(ValidatingSimpleJDBCConnectionPool.class + .getName()); + } +}
\ No newline at end of file diff --git a/server/tests/src/com/vaadin/server/AbstractClientConnectorTest.java b/server/tests/src/com/vaadin/server/AbstractClientConnectorTest.java new file mode 100644 index 0000000000..96ca82a0b3 --- /dev/null +++ b/server/tests/src/com/vaadin/server/AbstractClientConnectorTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2000-2014 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.server; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import com.vaadin.shared.MouseEventDetails; +import com.vaadin.shared.communication.FieldRpc.BlurServerRpc; +import com.vaadin.shared.ui.ClickRpc; + +/** + * We test that AbstractClientConnector has a suitable isThis method which is + * needed to correctly perform an equals check between a proxy and it's + * underlying instance. + * + * @author Vaadin Ltd + */ +public class AbstractClientConnectorTest { + + @Test + public void registerRPCMultiInterfaceTest() { + AbstractClientConnector mock = mock(AbstractClientConnector.class); + MultiServerRpcMock implementation = new MultiServerRpcMock(); + Mockito.doCallRealMethod().when(mock).registerRpc(implementation); + try { + mock.registerRpc(implementation); + Assert.fail("expected exception"); + } catch (Exception expected) { + Assert.assertEquals( + expected.getMessage(), + "Use registerRpc(T implementation, Class<T> rpcInterfaceType) if the Rpc implementation implements more than one interface"); + } + } + + @Test + public void registerRPCInterfaceTest() { + AbstractClientConnector mock = mock(AbstractClientConnector.class); + ServerRpcMock implementation = new ServerRpcMock(); + Mockito.doCallRealMethod().when(mock).registerRpc(implementation); + mock.registerRpc(implementation); + verify(mock, times(1)).registerRpc(implementation, ClickRpc.class); + } + + @Test + public void registerRPCInterfaceLastTest() { + AbstractClientConnector mock = mock(AbstractClientConnector.class); + ServerRpcLastMock implementation = new ServerRpcLastMock(); + Mockito.doCallRealMethod().when(mock).registerRpc(implementation); + mock.registerRpc(implementation); + verify(mock, times(1)).registerRpc(implementation, ClickRpc.class); + } + + private class ServerRpcLastMock implements Comparable<ServerRpcLastMock>, + ClickRpc { + private static final long serialVersionUID = -2822356895755286180L; + + @Override + public void click(MouseEventDetails mouseDetails) { + } + + @Override + public int compareTo(ServerRpcLastMock o) { + return 0; + } + + } + + private class ServerRpcMock implements ClickRpc { + private static final long serialVersionUID = 2822356895755286180L; + + @Override + public void click(MouseEventDetails mouseDetails) { + } + + } + + private class MultiServerRpcMock implements ClickRpc, BlurServerRpc { + + private static final long serialVersionUID = -7611999715560330373L; + + @Override + public void blur() { + + } + + @Override + public void click(MouseEventDetails mouseDetails) { + + } + + } + +} diff --git a/server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java b/server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java index dcabd6c637..00af20ea8c 100644 --- a/server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java +++ b/server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java @@ -275,8 +275,8 @@ public class DesignFormatterTest { String httpUrl = "http://example.com/icon.png"; String httpsUrl = "https://example.com/icon.png"; String themePath = "icons/icon.png"; - String fontAwesomeUrl = "fonticon://FontAwesome/0xf0f9"; - String someOtherFontUrl = "fonticon://SomeOther/0xF0F9"; + String fontAwesomeUrl = "fonticon://FontAwesome/f0f9"; + String someOtherFontUrl = "fonticon://SomeOther/F0F9"; String fileSystemPath = "c:\\app\\resources\\icon.png"; assertEquals(httpUrl, formatter.format(new ExternalResource(httpUrl))); @@ -315,8 +315,8 @@ public class DesignFormatterTest { String httpUrl = "http://example.com/icon.png"; String httpsUrl = "https://example.com/icon.png"; String themePath = "icons/icon.png"; - String fontAwesomeUrl = "fonticon://FontAwesome/0xf0f9"; - String someOtherFont = "fonticon://SomeOther/0xF0F9"; + String fontAwesomeUrl = "fonticon://FontAwesome/f0f9"; + String someOtherFont = "fonticon://SomeOther/F0F9"; String fontAwesomeUrlOld = "font://AMBULANCE"; String fileSystemPath = "c:\\app\\resources\\icon.png"; diff --git a/server/tests/src/com/vaadin/tests/server/component/FieldDefaultValues.java b/server/tests/src/com/vaadin/tests/server/component/FieldDefaultValues.java index 5c9993e6dd..16bbd7008f 100644 --- a/server/tests/src/com/vaadin/tests/server/component/FieldDefaultValues.java +++ b/server/tests/src/com/vaadin/tests/server/component/FieldDefaultValues.java @@ -23,11 +23,7 @@ import org.junit.Test; import com.vaadin.tests.VaadinClasses; import com.vaadin.ui.Field; -import com.vaadin.ui.PasswordField; -import com.vaadin.ui.ProgressBar; -import com.vaadin.ui.RichTextArea; import com.vaadin.ui.Slider; -import com.vaadin.ui.TextArea; public class FieldDefaultValues { @@ -36,13 +32,6 @@ public class FieldDefaultValues { for (Field<?> field : createFields()) { Object originalValue = field.getValue(); - // Some fields are not initialized to the "empty" value. #17089 - if (field instanceof PasswordField || field instanceof ProgressBar - || field instanceof RichTextArea - || field instanceof TextArea) { - originalValue = null; - } - field.clear(); Object clearedValue = field.getValue(); diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValidatorsTest.java b/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValidatorsTest.java index 61aafe317d..59831d92e1 100644 --- a/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValidatorsTest.java +++ b/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValidatorsTest.java @@ -1,16 +1,19 @@ package com.vaadin.tests.server.component.abstractfield; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import org.easymock.EasyMock; +import org.junit.Test; import com.vaadin.data.Validator; import com.vaadin.ui.AbstractField; -import com.vaadin.ui.Field; -public class AbsFieldValidatorsTest extends TestCase { +public class AbsFieldValidatorsTest { - Field<Object> field = new AbstractField<Object>() { + AbstractField<Object> field = new AbstractField<Object>() { @Override public Class getType() { return Object.class; @@ -20,6 +23,7 @@ public class AbsFieldValidatorsTest extends TestCase { Validator validator = EasyMock.createMock(Validator.class); Validator validator2 = EasyMock.createMock(Validator.class); + @Test public void testAddValidator() { assertNotNull(field.getValidators()); assertEquals(0, field.getValidators().size()); @@ -34,6 +38,7 @@ public class AbsFieldValidatorsTest extends TestCase { assertTrue(field.getValidators().contains(validator2)); } + @Test public void testRemoveValidator() { field.addValidator(validator); field.addValidator(validator2); @@ -51,6 +56,7 @@ public class AbsFieldValidatorsTest extends TestCase { assertFalse(field.getValidators().contains(validator2)); } + @Test public void testRemoveAllValidators() { field.addValidator(validator); field.addValidator(validator2); @@ -61,4 +67,51 @@ public class AbsFieldValidatorsTest extends TestCase { assertFalse(field.getValidators().contains(validator)); assertFalse(field.getValidators().contains(validator2)); } + + @Test + public void validatorShouldMakeImmediate() { + assertFalse("field should not be immediate by default", + field.isImmediate()); + field.addValidator(validator); + assertTrue("field should be immediate when it has a validator", + field.isImmediate()); + } + + @Test + public void nonImmediateFieldWithValidator() { + field.setImmediate(false); + field.addValidator(validator); + assertFalse("field should be non-immediate because explicitly set", + field.isImmediate()); + } + + @Test + public void removeValidatorMakesNonImmediate() { + field.addValidator(validator); + field.removeValidator(validator); + assertFalse( + "field should be non-immediate after validator was removed", + field.isImmediate()); + } + + @Test + public void requiredMakesImmediate() { + assertFalse("field should not be immediate by default", + field.isImmediate()); + field.setRequired(true); + assertTrue("field should be immediate when it is required", + field.isImmediate()); + } + + @Test + public void removeRequiredMakesNonImmediate() { + assertFalse("field should not be immediate by default", + field.isImmediate()); + field.setRequired(true); + field.setRequired(false); + assertFalse( + "field should not be immediate even though it was required", + field.isImmediate()); + } + } diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractsinglecomponentcontainer/RemoveFromParentLockingTest.java b/server/tests/src/com/vaadin/tests/server/component/abstractsinglecomponentcontainer/RemoveFromParentLockingTest.java index e277d4e075..2334542676 100644 --- a/server/tests/src/com/vaadin/tests/server/component/abstractsinglecomponentcontainer/RemoveFromParentLockingTest.java +++ b/server/tests/src/com/vaadin/tests/server/component/abstractsinglecomponentcontainer/RemoveFromParentLockingTest.java @@ -102,6 +102,8 @@ public class RemoveFromParentLockingTest { "Cannot remove from parent when the session is not locked." + " Furthermore, there is another locked session, indicating that the component might be about to be moved from one session to another.", e.getMessage()); + } finally { + VaadinSession.setCurrent(null); } } @@ -119,6 +121,8 @@ public class RemoveFromParentLockingTest { notLockedComponent.addComponent(lockedComponent); } catch (AssertionError e) { // All is fine, don't care about the exact wording in this case + } finally { + VaadinSession.setCurrent(null); } } diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridChildren.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridChildren.java new file mode 100644 index 0000000000..7af1cfef69 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/grid/GridChildren.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2014 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.tests.server.component.grid; + +import java.util.Iterator; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.ui.Component; +import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.FooterCell; +import com.vaadin.ui.Grid.HeaderCell; +import com.vaadin.ui.Label; + +public class GridChildren { + + @Test + public void componentsInMergedHeader() { + Grid grid = new Grid(); + grid.addColumn("foo"); + grid.addColumn("bar"); + grid.addColumn("baz"); + HeaderCell merged = grid.getDefaultHeaderRow() + .join("foo", "bar", "baz"); + Label label = new Label(); + merged.setComponent(label); + Iterator<Component> i = grid.iterator(); + Assert.assertEquals(label, i.next()); + Assert.assertFalse(i.hasNext()); + } + + @Test + public void componentsInMergedFooter() { + Grid grid = new Grid(); + grid.addColumn("foo"); + grid.addColumn("bar"); + grid.addColumn("baz"); + FooterCell merged = grid.addFooterRowAt(0).join("foo", "bar", "baz"); + Label label = new Label(); + merged.setComponent(label); + Iterator<Component> i = grid.iterator(); + Assert.assertEquals(label, i.next()); + Assert.assertFalse(i.hasNext()); + } +} diff --git a/server/tests/src/com/vaadin/tests/server/component/grid/GridExtensionTest.java b/server/tests/src/com/vaadin/tests/server/component/grid/GridExtensionTest.java new file mode 100644 index 0000000000..d9db217aa3 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/server/component/grid/GridExtensionTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2014 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.tests.server.component.grid; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.AbstractGridExtension; + +public class GridExtensionTest { + + public static class DummyGridExtension extends AbstractGridExtension { + + public DummyGridExtension(Grid grid) { + super(grid); + } + } + + @Test + public void testCreateExtension() { + Grid grid = new Grid(); + DummyGridExtension dummy = new DummyGridExtension(grid); + assertTrue("DummyGridExtension never made it to Grid", grid + .getExtensions().contains(dummy)); + } +} diff --git a/server/tests/src/com/vaadin/tests/server/component/slider/SliderTest.java b/server/tests/src/com/vaadin/tests/server/component/slider/SliderTest.java index d2e2654cbc..7f20f29648 100644 --- a/server/tests/src/com/vaadin/tests/server/component/slider/SliderTest.java +++ b/server/tests/src/com/vaadin/tests/server/component/slider/SliderTest.java @@ -76,4 +76,60 @@ public class SliderTest { assertThat(slider.getValue(), is(99.01234567891234567890123456789)); } + + @Test + public void doublesCanBeUsedAsLimits() { + Slider slider = new Slider(1.5, 2.5, 1); + + assertThat(slider.getMin(), is(1.5)); + assertThat(slider.getValue(), is(1.5)); + assertThat(slider.getMax(), is(2.5)); + } + + @Test + public void valuesGreaterThanIntMaxValueCanBeUsed() { + double minValue = (double)Integer.MAX_VALUE + 1; + + Slider s = new Slider(minValue, minValue + 1, 0); + + assertThat(s.getValue(), is(minValue)); + } + + @Test + public void negativeValuesCanBeUsed() { + Slider slider = new Slider(-0.7, 1.0, 0); + + slider.setValue(-0.4); + + assertThat(slider.getValue(), is(-0.0)); + } + + @Test + public void boundariesAreRounded() { + Slider slider = new Slider(1.5, 2.5, 0); + + slider.setValue(1.0); + + assertThat(slider.getValue(), is(1.0)); + assertThat(slider.getMin(), is(1.0)); + assertThat(slider.getMax(), is(2.0)); + } + + @Test + public void valueWithSmallerPrecisionCanBeUsed() { + Slider slider = new Slider(0, 100, 10); + + slider.setValue(1.2); + + assertThat(slider.getValue(), is(1.2)); + } + + @Test + public void valueWithLargerPrecisionCanBeUsed() { + Slider slider = new Slider(0, 100, 2); + + slider.setValue(1.2345); + + assertThat(slider.getValue(), is(1.23)); + } } diff --git a/server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java b/server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java index 8bcbc6a5a9..8a01464180 100644 --- a/server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java +++ b/server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java @@ -15,15 +15,6 @@ */ package com.vaadin.tests.server.renderer; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; - -import java.util.Locale; - -import org.junit.Before; -import org.junit.Test; - import com.vaadin.data.Item; import com.vaadin.data.RpcDataProviderExtension; import com.vaadin.data.util.IndexedContainer; @@ -34,9 +25,21 @@ import com.vaadin.tests.server.component.grid.TestGrid; import com.vaadin.tests.util.AlwaysLockedVaadinSession; import com.vaadin.ui.Grid; import com.vaadin.ui.Grid.Column; +import com.vaadin.ui.renderers.ButtonRenderer; +import com.vaadin.ui.renderers.DateRenderer; +import com.vaadin.ui.renderers.HtmlRenderer; +import com.vaadin.ui.renderers.NumberRenderer; import com.vaadin.ui.renderers.TextRenderer; - import elemental.json.JsonValue; +import org.junit.Before; +import org.junit.Test; + +import java.util.Date; +import java.util.Locale; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; public class RendererTest { @@ -64,14 +67,14 @@ public class RendererTest { @Override public TestBean convertToModel(String value, - Class<? extends TestBean> targetType, Locale locale) + Class<? extends TestBean> targetType, Locale locale) throws ConversionException { return null; } @Override public String convertToPresentation(TestBean value, - Class<? extends String> targetType, Locale locale) + Class<? extends String> targetType, Locale locale) throws ConversionException { if (value instanceof ExtendedBean) { return "ExtendedBean(" + value.i + ", " @@ -94,101 +97,151 @@ public class RendererTest { private Grid grid; - private Column foo; - private Column bar; - private Column baz; - private Column bah; + private Column intColumn; + private Column textColumn; + private Column beanColumn; + private Column htmlColumn; + private Column numberColumn; + private Column dateColumn; + private Column extendedBeanColumn; + private Column buttonColumn; @Before + @SuppressWarnings("unchecked") public void setUp() { VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null)); IndexedContainer c = new IndexedContainer(); - c.addContainerProperty("foo", Integer.class, 0); - c.addContainerProperty("bar", String.class, ""); - c.addContainerProperty("baz", TestBean.class, null); - c.addContainerProperty("bah", ExtendedBean.class, null); + c.addContainerProperty("int", Integer.class, 0); + c.addContainerProperty("text", String.class, ""); + c.addContainerProperty("html", String.class, ""); + c.addContainerProperty("number", Number.class, null); + c.addContainerProperty("date", Date.class, null); + c.addContainerProperty("bean", TestBean.class, null); + c.addContainerProperty("button", String.class, null); + c.addContainerProperty("extendedBean", ExtendedBean.class, null); Object id = c.addItem(); Item item = c.getItem(id); - item.getItemProperty("foo").setValue(123); - item.getItemProperty("bar").setValue("321"); - item.getItemProperty("baz").setValue(new TestBean()); - item.getItemProperty("bah").setValue(new ExtendedBean()); + item.getItemProperty("int").setValue(123); + item.getItemProperty("text").setValue("321"); + item.getItemProperty("html").setValue("<b>html</b>"); + item.getItemProperty("number").setValue(3.14); + item.getItemProperty("date").setValue(new Date(123456789)); + item.getItemProperty("bean").setValue(new TestBean()); + item.getItemProperty("extendedBean").setValue(new ExtendedBean()); grid = new TestGrid(c); - foo = grid.getColumn("foo"); - bar = grid.getColumn("bar"); - baz = grid.getColumn("baz"); - bah = grid.getColumn("bah"); + intColumn = grid.getColumn("int"); + textColumn = grid.getColumn("text"); + htmlColumn = grid.getColumn("html"); + numberColumn = grid.getColumn("number"); + dateColumn = grid.getColumn("date"); + beanColumn = grid.getColumn("bean"); + extendedBeanColumn = grid.getColumn("extendedBean"); + buttonColumn = grid.getColumn("button"); + } @Test public void testDefaultRendererAndConverter() throws Exception { - assertSame(TextRenderer.class, foo.getRenderer().getClass()); - assertSame(StringToIntegerConverter.class, foo.getConverter() + assertSame(TextRenderer.class, intColumn.getRenderer().getClass()); + assertSame(StringToIntegerConverter.class, intColumn.getConverter() .getClass()); - assertSame(TextRenderer.class, bar.getRenderer().getClass()); + assertSame(TextRenderer.class, textColumn.getRenderer().getClass()); // String->String; converter not needed - assertNull(bar.getConverter()); + assertNull(textColumn.getConverter()); - assertSame(TextRenderer.class, baz.getRenderer().getClass()); + assertSame(TextRenderer.class, beanColumn.getRenderer().getClass()); // MyBean->String; converter not found - assertNull(baz.getConverter()); + assertNull(beanColumn.getConverter()); } @Test public void testFindCompatibleConverter() throws Exception { - foo.setRenderer(renderer()); - assertSame(StringToIntegerConverter.class, foo.getConverter() + intColumn.setRenderer(renderer()); + assertSame(StringToIntegerConverter.class, intColumn.getConverter() .getClass()); - bar.setRenderer(renderer()); - assertNull(bar.getConverter()); + textColumn.setRenderer(renderer()); + assertNull(textColumn.getConverter()); } @Test(expected = IllegalArgumentException.class) public void testCannotFindConverter() { - baz.setRenderer(renderer()); + beanColumn.setRenderer(renderer()); } @Test public void testExplicitConverter() throws Exception { - baz.setRenderer(renderer(), converter()); - bah.setRenderer(renderer(), converter()); + beanColumn.setRenderer(renderer(), converter()); + extendedBeanColumn.setRenderer(renderer(), converter()); } @Test public void testEncoding() throws Exception { - assertEquals("42", render(foo, 42).asString()); - foo.setRenderer(renderer()); - assertEquals("renderer(42)", render(foo, 42).asString()); + assertEquals("42", render(intColumn, 42).asString()); + intColumn.setRenderer(renderer()); + assertEquals("renderer(42)", render(intColumn, 42).asString()); - assertEquals("2.72", render(bar, "2.72").asString()); - bar.setRenderer(new TestRenderer()); - assertEquals("renderer(2.72)", render(bar, "2.72").asString()); + assertEquals("2.72", render(textColumn, "2.72").asString()); + textColumn.setRenderer(new TestRenderer()); + assertEquals("renderer(2.72)", render(textColumn, "2.72").asString()); } @Test public void testEncodingWithoutConverter() throws Exception { - assertEquals("TestBean [42]", render(baz, new TestBean()).asString()); + assertEquals("TestBean [42]", render(beanColumn, new TestBean()) + .asString()); } @Test public void testBeanEncoding() throws Exception { - baz.setRenderer(renderer(), converter()); - bah.setRenderer(renderer(), converter()); + beanColumn.setRenderer(renderer(), converter()); + extendedBeanColumn.setRenderer(renderer(), converter()); - assertEquals("renderer(TestBean(42))", render(baz, new TestBean()) - .asString()); + assertEquals("renderer(TestBean(42))", + render(beanColumn, new TestBean()).asString()); assertEquals("renderer(ExtendedBean(42, 3.14))", - render(baz, new ExtendedBean()).asString()); + render(beanColumn, new ExtendedBean()).asString()); assertEquals("renderer(ExtendedBean(42, 3.14))", - render(bah, new ExtendedBean()).asString()); + render(extendedBeanColumn, new ExtendedBean()).asString()); + } + + @Test + public void testNullEncoding() { + + textColumn.setRenderer(new TextRenderer()); + htmlColumn.setRenderer(new HtmlRenderer()); + numberColumn.setRenderer(new NumberRenderer()); + dateColumn.setRenderer(new DateRenderer()); + buttonColumn.setRenderer(new ButtonRenderer()); + + assertEquals("", textColumn.getRenderer().encode(null).asString()); + assertEquals("", htmlColumn.getRenderer().encode(null).asString()); + assertEquals("", numberColumn.getRenderer().encode(null).asString()); + assertEquals("", dateColumn.getRenderer().encode(null).asString()); + assertEquals("", buttonColumn.getRenderer().encode(null).asString()); + } + @Test + + public void testNullEncodingWithDefault() { + + textColumn.setRenderer(new TextRenderer("default value")); + htmlColumn.setRenderer(new HtmlRenderer("default value")); + numberColumn.setRenderer(new NumberRenderer("%s", Locale.getDefault(), "default value")); + dateColumn.setRenderer(new DateRenderer("%s", "default value")); + buttonColumn.setRenderer(new ButtonRenderer("default value")); + + assertEquals("default value", textColumn.getRenderer().encode(null).asString()); + assertEquals("default value", htmlColumn.getRenderer().encode(null).asString()); + assertEquals("default value", numberColumn.getRenderer().encode(null).asString()); + assertEquals("default value", dateColumn.getRenderer().encode(null).asString()); + assertEquals("default value", buttonColumn.getRenderer().encode(null).asString()); } private TestConverter converter() { |