From 77f399a27e1d06b7a9fa7bd699ce1176ba0b40ef Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 9 Mar 2012 11:47:09 +0200 Subject: [PATCH] #8510 Support using Resources through URLReference/ResourceReference in shared state and RPC calls --- .../gwt/client/ApplicationConnection.java | 8 ++-- .../terminal/gwt/client/ComponentState.java | 10 ++++ .../vaadin/terminal/gwt/client/VCaption.java | 16 +++---- .../client/communication/JSONSerializer.java | 9 ++-- .../gwt/client/communication/JsonDecoder.java | 28 ++++++----- .../gwt/client/communication/JsonEncoder.java | 11 +++-- .../communication/ResourceReference.java | 47 +++++++++++++++++++ .../client/communication/URLReference.java | 26 ++++++++++ .../URLReference_Serializer.java | 29 ++++++++++++ .../client/ui/AbstractComponentConnector.java | 1 - .../gwt/client/ui/ButtonConnector.java | 4 +- .../gwt/client/ui/CheckBoxConnector.java | 4 +- .../terminal/gwt/client/ui/FormConnector.java | 4 +- .../terminal/gwt/client/ui/LinkConnector.java | 4 +- .../gwt/client/ui/NativeButtonConnector.java | 7 ++- .../gwt/client/ui/PanelConnector.java | 6 ++- .../gwt/client/ui/TabsheetBaseConnector.java | 1 + .../terminal/gwt/client/ui/TreeConnector.java | 4 +- .../terminal/gwt/client/ui/VAccordion.java | 3 +- .../terminal/gwt/client/ui/VFormLayout.java | 5 +- .../terminal/gwt/client/ui/VMenuBar.java | 2 +- .../terminal/gwt/client/ui/VNotification.java | 2 +- .../vaadin/terminal/gwt/client/ui/VPanel.java | 6 +-- .../terminal/gwt/client/ui/VTabsheet.java | 3 +- .../gwt/client/ui/WindowConnector.java | 9 ++-- .../vaadin/terminal/gwt/server/JsonCodec.java | 15 +++++- .../widgetsetutils/SerializerGenerator.java | 21 +++++---- .../SerializerMapGenerator.java | 34 ++++++++++++-- src/com/vaadin/ui/AbstractComponent.java | 24 +++------- src/com/vaadin/ui/TabSheet.java | 3 +- 30 files changed, 251 insertions(+), 95 deletions(-) create mode 100644 src/com/vaadin/terminal/gwt/client/communication/ResourceReference.java create mode 100644 src/com/vaadin/terminal/gwt/client/communication/URLReference.java create mode 100644 src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index 8ac2f1f7b1..c889a65ce5 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -1197,7 +1197,8 @@ public class ApplicationConnection { states.getJavaScriptObject(connectorId)); Object state = JsonDecoder.convertValue( - stateDataAndType, connectorMap); + stateDataAndType, connectorMap, + ApplicationConnection.this); paintable.setState((SharedState) state); } @@ -1317,7 +1318,7 @@ public class ApplicationConnection { Object[] parameters = new Object[parametersJson.size()]; for (int j = 0; j < parametersJson.size(); ++j) { parameters[j] = JsonDecoder.convertValue( - (JSONArray) parametersJson.get(j), getConnectorMap()); + (JSONArray) parametersJson.get(j), getConnectorMap(), this); } return new MethodInvocation(connectorId, interfaceName, methodName, parameters); @@ -1438,7 +1439,8 @@ public class ApplicationConnection { for (int i = 0; i < invocation.getParameters().length; ++i) { // TODO non-static encoder? type registration? paramJson.set(i, JsonEncoder.encode( - invocation.getParameters()[i], getConnectorMap())); + invocation.getParameters()[i], getConnectorMap(), + this)); } invocationJson.set(3, paramJson); reqJson.set(reqJson.size(), invocationJson); diff --git a/src/com/vaadin/terminal/gwt/client/ComponentState.java b/src/com/vaadin/terminal/gwt/client/ComponentState.java index e42afd6d03..9a72f7cd80 100644 --- a/src/com/vaadin/terminal/gwt/client/ComponentState.java +++ b/src/com/vaadin/terminal/gwt/client/ComponentState.java @@ -5,6 +5,7 @@ package com.vaadin.terminal.gwt.client; import com.vaadin.terminal.gwt.client.communication.SharedState; +import com.vaadin.terminal.gwt.client.communication.URLReference; import com.vaadin.ui.Component; /** @@ -26,6 +27,7 @@ public class ComponentState extends SharedState { // string! private String caption = null; private boolean visible = true; + private URLReference icon = null; /** * Returns the component height as set by the server. @@ -288,4 +290,12 @@ public class ComponentState extends SharedState { this.visible = visible; } + public URLReference getIcon() { + return icon; + } + + public void setIcon(URLReference icon) { + this.icon = icon; + } + } diff --git a/src/com/vaadin/terminal/gwt/client/VCaption.java b/src/com/vaadin/terminal/gwt/client/VCaption.java index b7d66612a9..e639da9502 100644 --- a/src/com/vaadin/terminal/gwt/client/VCaption.java +++ b/src/com/vaadin/terminal/gwt/client/VCaption.java @@ -118,8 +118,7 @@ public class VCaption extends HTML { } setStyleName(style); - boolean hasIcon = uidl - .hasAttribute(AbstractComponentConnector.ATTRIBUTE_ICON); + boolean hasIcon = owner.getState().getIcon() != null; boolean showRequired = uidl .getBooleanAttribute(AbstractComponentConnector.ATTRIBUTE_REQUIRED); boolean showError = uidl @@ -138,8 +137,7 @@ public class VCaption extends HTML { // Icon forces the caption to be above the component placedAfterComponent = false; - icon.setUri(uidl - .getStringAttribute(AbstractComponentConnector.ATTRIBUTE_ICON)); + icon.setUri(owner.getState().getIcon().getURL()); } else if (icon != null) { // Remove existing @@ -257,7 +255,7 @@ public class VCaption extends HTML { @Deprecated public boolean updateCaptionWithoutOwner(UIDL uidl, String caption, - boolean disabled, boolean hasDescription) { + boolean disabled, boolean hasDescription, String iconURL) { // TODO temporary method, needed because some tabsheet and accordion // internal captions do not have an owner or shared state. Simplified to // only support those cases @@ -281,8 +279,7 @@ public class VCaption extends HTML { removeStyleDependentName("hasdescription"); } } - boolean hasIcon = uidl - .hasAttribute(AbstractComponentConnector.ATTRIBUTE_ICON); + boolean hasIcon = iconURL != null; boolean showError = uidl .hasAttribute(AbstractComponentConnector.ATTRIBUTE_ERROR) && !uidl.getBooleanAttribute(AbstractComponentConnector.ATTRIBUTE_HIDEERRORS); @@ -299,8 +296,7 @@ public class VCaption extends HTML { // Icon forces the caption to be above the component placedAfterComponent = false; - icon.setUri(uidl - .getStringAttribute(AbstractComponentConnector.ATTRIBUTE_ICON)); + icon.setUri(iconURL); } else if (icon != null) { // Remove existing @@ -412,7 +408,7 @@ public class VCaption extends HTML { if (uidl.hasAttribute(AbstractComponentConnector.ATTRIBUTE_ERROR)) { return true; } - if (uidl.hasAttribute(AbstractComponentConnector.ATTRIBUTE_ICON)) { + if (state.getIcon() != null) { return true; } if (uidl.hasAttribute(AbstractComponentConnector.ATTRIBUTE_REQUIRED)) { diff --git a/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java b/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java index ee03323618..c626d31d0a 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java @@ -5,6 +5,7 @@ package com.vaadin.terminal.gwt.client.communication; import com.google.gwt.json.client.JSONObject; +import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.ConnectorMap; import com.vaadin.terminal.gwt.server.JsonCodec; @@ -21,7 +22,7 @@ import com.vaadin.terminal.gwt.server.JsonCodec; * * @since 7.0 */ -public interface JSONSerializer { +public interface JSONSerializer { /** * Creates and deserializes an object received from the server. Must be @@ -37,7 +38,8 @@ public interface JSONSerializer { * references to paintables * @return A deserialized object */ - Object deserialize(JSONObject jsonValue, ConnectorMap idMapper); + T deserialize(JSONObject jsonValue, ConnectorMap idMapper, + ApplicationConnection connection); /** * Serialize the given object into JSON. Must be compatible with @@ -52,6 +54,7 @@ public interface JSONSerializer { * references to paintables * @return A JSON serialized version of the object */ - JSONObject serialize(Object value, ConnectorMap idMapper); + JSONObject serialize(T value, ConnectorMap idMapper, + ApplicationConnection connection); } diff --git a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java index 444faa6276..2250bbbb8d 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java @@ -14,6 +14,7 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONString; +import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.Connector; import com.vaadin.terminal.gwt.client.ConnectorMap; @@ -39,23 +40,26 @@ public class JsonDecoder { * JSON array with two elements * @param idMapper * mapper between connector ID and {@link Connector} objects + * @param connection + * reference to the current ApplicationConnection * @return converted value (does not contain JSON types) */ - public static Object convertValue(JSONArray jsonArray, ConnectorMap idMapper) { + public static Object convertValue(JSONArray jsonArray, + ConnectorMap idMapper, ApplicationConnection connection) { String type = ((JSONString) jsonArray.get(0)).stringValue(); - return convertValue(type, jsonArray.get(1), idMapper); + return convertValue(type, jsonArray.get(1), idMapper, connection); } private static Object convertValue(String variableType, Object value, - ConnectorMap idMapper) { + ConnectorMap idMapper, ApplicationConnection connection) { Object val = null; // TODO type checks etc. if (JsonEncoder.VTYPE_UNDEFINED.equals(variableType)) { val = null; } else if (JsonEncoder.VTYPE_ARRAY.equals(variableType)) { - val = convertArray((JSONArray) value, idMapper); + val = convertArray((JSONArray) value, idMapper, connection); } else if (JsonEncoder.VTYPE_MAP.equals(variableType)) { - val = convertMap((JSONObject) value, idMapper); + val = convertMap((JSONObject) value, idMapper, connection); } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(variableType)) { val = convertStringArray((JSONArray) value); } else if (JsonEncoder.VTYPE_STRING.equals(variableType)) { @@ -83,8 +87,8 @@ public class JsonDecoder { JSONSerializer serializer = serializerMap .getSerializer(variableType); // TODO handle case with no serializer found - Object object = serializer - .deserialize((JSONObject) value, idMapper); + Object object = serializer.deserialize((JSONObject) value, + idMapper, connection); return object; } @@ -92,12 +96,14 @@ public class JsonDecoder { } private static Map convertMap(JSONObject jsonMap, - ConnectorMap idMapper) { + ConnectorMap idMapper, ApplicationConnection connection) { HashMap map = new HashMap(); Iterator it = jsonMap.keySet().iterator(); while (it.hasNext()) { String key = it.next(); - map.put(key, convertValue((JSONArray) jsonMap.get(key), idMapper)); + map.put(key, + convertValue((JSONArray) jsonMap.get(key), idMapper, + connection)); } return map; } @@ -112,12 +118,12 @@ public class JsonDecoder { } private static Object[] convertArray(JSONArray jsonArray, - ConnectorMap idMapper) { + ConnectorMap idMapper, ApplicationConnection connection) { List tokens = new ArrayList(); for (int i = 0; i < jsonArray.size(); ++i) { // each entry always has two elements: type and value JSONArray entryArray = (JSONArray) jsonArray.get(i); - tokens.add(convertValue(entryArray, idMapper)); + tokens.add(convertValue(entryArray, idMapper, connection)); } return tokens.toArray(new Object[tokens.size()]); } diff --git a/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java b/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java index faa701f2db..c7d49875d7 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java @@ -12,6 +12,7 @@ import com.google.gwt.json.client.JSONNull; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONString; import com.google.gwt.json.client.JSONValue; +import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.Connector; import com.vaadin.terminal.gwt.client.ConnectorMap; @@ -52,9 +53,11 @@ public class JsonEncoder { * value to convert * @param connectorMap * mapper from connectors to connector IDs + * @param connection * @return JSON representation of the value */ - public static JSONValue encode(Object value, ConnectorMap connectorMap) { + public static JSONValue encode(Object value, ConnectorMap connectorMap, + ApplicationConnection connection) { if (null == value) { // TODO as undefined type? return combineTypeAndValue(VTYPE_UNDEFINED, JSONNull.getInstance()); @@ -76,7 +79,7 @@ public class JsonEncoder { JSONArray jsonArray = new JSONArray(); for (int i = 0; i < array.length; ++i) { // TODO handle object graph loops? - jsonArray.set(i, encode(array[i], connectorMap)); + jsonArray.set(i, encode(array[i], connectorMap, connection)); } return combineTypeAndValue(VTYPE_ARRAY, jsonArray); } else if (value instanceof Map) { @@ -85,7 +88,7 @@ public class JsonEncoder { for (String mapKey : map.keySet()) { // TODO handle object graph loops? Object mapValue = map.get(mapKey); - jsonMap.put(mapKey, encode(mapValue, connectorMap)); + jsonMap.put(mapKey, encode(mapValue, connectorMap, connection)); } return combineTypeAndValue(VTYPE_MAP, jsonMap); } else if (value instanceof Connector) { @@ -105,7 +108,7 @@ public class JsonEncoder { // TODO handle case with no serializer found return combineTypeAndValue(type, - serializer.serialize(value, connectorMap)); + serializer.serialize(value, connectorMap, connection)); } } } diff --git a/src/com/vaadin/terminal/gwt/client/communication/ResourceReference.java b/src/com/vaadin/terminal/gwt/client/communication/ResourceReference.java new file mode 100644 index 0000000000..1bfde31eca --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/ResourceReference.java @@ -0,0 +1,47 @@ +package com.vaadin.terminal.gwt.client.communication; + +import com.vaadin.Application; +import com.vaadin.terminal.ApplicationResource; +import com.vaadin.terminal.ExternalResource; +import com.vaadin.terminal.Resource; +import com.vaadin.terminal.ThemeResource; + +public class ResourceReference extends URLReference { + + private Resource resource; + + public ResourceReference(Resource resource) { + this.resource = resource; + } + + public Resource getResource() { + return resource; + } + + @Override + public String getURL() { + if (resource instanceof ExternalResource) { + return ((ExternalResource) resource).getURL(); + } else if (resource instanceof ApplicationResource) { + final ApplicationResource r = (ApplicationResource) resource; + final Application a = r.getApplication(); + if (a == null) { + throw new RuntimeException( + "An ApplicationResource (" + + r.getClass().getName() + + " must be attached to an application when it is sent to the client."); + } + final String uri = a.getRelativeLocation(r); + return uri; + } else if (resource instanceof ThemeResource) { + final String uri = "theme://" + + ((ThemeResource) resource).getResourceId(); + return uri; + } else { + throw new RuntimeException(getClass().getSimpleName() + + " does not support resources of type: " + + resource.getClass().getName()); + } + + } +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/URLReference.java b/src/com/vaadin/terminal/gwt/client/communication/URLReference.java new file mode 100644 index 0000000000..eb880944c2 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/URLReference.java @@ -0,0 +1,26 @@ +package com.vaadin.terminal.gwt.client.communication; + +public class URLReference { + + private String URL; + + /** + * Returns the URL that this object refers to. + *

+ * Note that the URL can use special protocols like theme:// + * + * @return The URL for this reference or null if unknown. + */ + public String getURL() { + return URL; + } + + /** + * Sets the URL that this object refers to + * + * @param URL + */ + public void setURL(String URL) { + this.URL = URL; + } +} \ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java b/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java new file mode 100644 index 0000000000..24053d2c15 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java @@ -0,0 +1,29 @@ +package com.vaadin.terminal.gwt.client.communication; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONObject; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ConnectorMap; + +public class URLReference_Serializer implements JSONSerializer { + + public URLReference deserialize(JSONObject jsonValue, + ConnectorMap idMapper, ApplicationConnection connection) { + URLReference reference = GWT.create(URLReference.class); + JSONArray jsonURL = (JSONArray) jsonValue.get("URL"); + String URL = (String) JsonDecoder.convertValue(jsonURL, idMapper, + connection); + reference.setURL(connection.translateVaadinUri(URL)); + return reference; + } + + public JSONObject serialize(URLReference value, ConnectorMap idMapper, + ApplicationConnection connection) { + JSONObject json = new JSONObject(); + json.put("URL", + JsonEncoder.encode(value.getURL(), idMapper, connection)); + return json; + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java index f2d4f082d1..24baa22940 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java @@ -33,7 +33,6 @@ public abstract class AbstractComponentConnector extends AbstractConnector // constants, which may refer to these. // Not all references to the string literals have been converted to use // these! - public static final String ATTRIBUTE_ICON = "icon"; public static final String ATTRIBUTE_REQUIRED = "required"; public static final String ATTRIBUTE_ERROR = "error"; public static final String ATTRIBUTE_HIDEERRORS = "hideErrors"; diff --git a/src/com/vaadin/terminal/gwt/client/ui/ButtonConnector.java b/src/com/vaadin/terminal/gwt/client/ui/ButtonConnector.java index c9e69235b1..903047171a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/ButtonConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/ButtonConnector.java @@ -88,13 +88,13 @@ public class ButtonConnector extends AbstractComponentConnector { getWidget().errorIndicatorElement = null; } - if (uidl.hasAttribute(ATTRIBUTE_ICON)) { + if (getState().getIcon() != null) { if (getWidget().icon == null) { getWidget().icon = new Icon(client); getWidget().wrapper.insertBefore(getWidget().icon.getElement(), getWidget().captionElement); } - getWidget().icon.setUri(uidl.getStringAttribute(ATTRIBUTE_ICON)); + getWidget().icon.setUri(getState().getIcon().getURL()); } else { if (getWidget().icon != null) { getWidget().wrapper.removeChild(getWidget().icon.getElement()); diff --git a/src/com/vaadin/terminal/gwt/client/ui/CheckBoxConnector.java b/src/com/vaadin/terminal/gwt/client/ui/CheckBoxConnector.java index f198fdc00f..e59777ef31 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/CheckBoxConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/CheckBoxConnector.java @@ -59,7 +59,7 @@ public class CheckBoxConnector extends AbstractComponentConnector { getWidget().setEnabled(false); } - if (uidl.hasAttribute(ATTRIBUTE_ICON)) { + if (getState().getIcon() != null) { if (getWidget().icon == null) { getWidget().icon = new Icon(client); DOM.insertChild(getWidget().getElement(), @@ -67,7 +67,7 @@ public class CheckBoxConnector extends AbstractComponentConnector { getWidget().icon.sinkEvents(VTooltip.TOOLTIP_EVENTS); getWidget().icon.sinkEvents(Event.ONCLICK); } - getWidget().icon.setUri(uidl.getStringAttribute(ATTRIBUTE_ICON)); + getWidget().icon.setUri(getState().getIcon().getURL()); } else if (getWidget().icon != null) { // detach icon DOM.removeChild(getWidget().getElement(), diff --git a/src/com/vaadin/terminal/gwt/client/ui/FormConnector.java b/src/com/vaadin/terminal/gwt/client/ui/FormConnector.java index 2e34781228..9ff7a38ccf 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/FormConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/FormConnector.java @@ -43,12 +43,12 @@ public class FormConnector extends AbstractComponentContainerConnector } else { getWidget().caption.setInnerText(""); } - if (uidl.hasAttribute(ATTRIBUTE_ICON)) { + if (getState().getIcon() != null) { if (getWidget().icon == null) { getWidget().icon = new Icon(client); getWidget().legend.insertFirst(getWidget().icon.getElement()); } - getWidget().icon.setUri(uidl.getStringAttribute(ATTRIBUTE_ICON)); + getWidget().icon.setUri(getState().getIcon().getURL()); legendEmpty = false; } else { if (getWidget().icon != null) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/LinkConnector.java b/src/com/vaadin/terminal/gwt/client/ui/LinkConnector.java index a8c10650c1..7d6e7e04ce 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/LinkConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/LinkConnector.java @@ -74,13 +74,13 @@ public class LinkConnector extends AbstractComponentConnector { "none"); } - if (uidl.hasAttribute(ATTRIBUTE_ICON)) { + if (getState().getIcon() != null) { if (getWidget().icon == null) { getWidget().icon = new Icon(client); getWidget().anchor.insertBefore(getWidget().icon.getElement(), getWidget().captionElement); } - getWidget().icon.setUri(uidl.getStringAttribute(ATTRIBUTE_ICON)); + getWidget().icon.setUri(getState().getIcon().getURL()); } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/NativeButtonConnector.java b/src/com/vaadin/terminal/gwt/client/ui/NativeButtonConnector.java index 20737fc70b..135fb4f676 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/NativeButtonConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/NativeButtonConnector.java @@ -18,8 +18,7 @@ public class NativeButtonConnector extends AbstractComponentConnector { public void init() { super.init(); - ButtonServerRpc rpcProxy = GWT - .create(ButtonServerRpc.class); + ButtonServerRpc rpcProxy = GWT.create(ButtonServerRpc.class); getWidget().buttonRpcProxy = initRPC(rpcProxy); } @@ -68,14 +67,14 @@ public class NativeButtonConnector extends AbstractComponentConnector { getWidget().errorIndicatorElement = null; } - if (uidl.hasAttribute(ATTRIBUTE_ICON)) { + if (getState().getIcon() != null) { if (getWidget().icon == null) { getWidget().icon = new Icon(client); getWidget().getElement().insertBefore( getWidget().icon.getElement(), getWidget().captionElement); } - getWidget().icon.setUri(uidl.getStringAttribute(ATTRIBUTE_ICON)); + getWidget().icon.setUri(getState().getIcon().getURL()); } else { if (getWidget().icon != null) { getWidget().getElement().removeChild( diff --git a/src/com/vaadin/terminal/gwt/client/ui/PanelConnector.java b/src/com/vaadin/terminal/gwt/client/ui/PanelConnector.java index d5ed3fcaf3..c54b9fbf60 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/PanelConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/PanelConnector.java @@ -105,7 +105,11 @@ public class PanelConnector extends AbstractComponentContainerConnector getWidget().client = client; getWidget().id = uidl.getId(); - getWidget().setIconUri(uidl, client); + if (getState().getIcon() != null) { + getWidget().setIconUri(getState().getIcon().getURL(), client); + } else { + getWidget().setIconUri(null, client); + } getWidget().handleError(uidl); diff --git a/src/com/vaadin/terminal/gwt/client/ui/TabsheetBaseConnector.java b/src/com/vaadin/terminal/gwt/client/ui/TabsheetBaseConnector.java index 8a52d5bb49..1840ac159e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/TabsheetBaseConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/TabsheetBaseConnector.java @@ -18,6 +18,7 @@ public abstract class TabsheetBaseConnector extends public static final String ATTRIBUTE_TAB_DISABLED = "disabled"; public static final String ATTRIBUTE_TAB_DESCRIPTION = "description"; public static final String ATTRIBUTE_TAB_CAPTION = "caption"; + public static final String ATTRIBUTE_TAB_ICON = "icon"; @Override public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/TreeConnector.java b/src/com/vaadin/terminal/gwt/client/ui/TreeConnector.java index 118b01fe03..b6e6095ef2 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/TreeConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/TreeConnector.java @@ -16,10 +16,10 @@ public class TreeConnector extends AbstractComponentConnector { public static final String ATTRIBUTE_NODE_STYLE = "style"; public static final String ATTRIBUTE_NODE_CAPTION = "caption"; - public static final String ATTRIBUTE_NODE_ICON = AbstractComponentConnector.ATTRIBUTE_ICON; + public static final String ATTRIBUTE_NODE_ICON = "icon"; public static final String ATTRIBUTE_ACTION_CAPTION = "caption"; - public static final String ATTRIBUTE_ACTION_ICON = AbstractComponentConnector.ATTRIBUTE_ICON; + public static final String ATTRIBUTE_ACTION_ICON = ATTRIBUTE_NODE_ICON; @Override public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAccordion.java b/src/com/vaadin/terminal/gwt/client/ui/VAccordion.java index e0c1510ae9..95db322730 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VAccordion.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VAccordion.java @@ -443,7 +443,8 @@ public class VAccordion extends VTabsheetBase { uidl, uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_CAPTION), uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DISABLED), - uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION)); + uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION), + uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ICON)); } public int getWidgetWidth() { diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java index b322be6601..cf9f35dc8d 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java @@ -267,14 +267,13 @@ public class VFormLayout extends SimplePanel { boolean isEmpty = true; - if (uidl.hasAttribute(AbstractComponentConnector.ATTRIBUTE_ICON)) { + if (state.getIcon() != null) { if (icon == null) { icon = new Icon(client); DOM.insertChild(getElement(), icon.getElement(), 0); } - icon.setUri(uidl - .getStringAttribute(AbstractComponentConnector.ATTRIBUTE_ICON)); + icon.setUri(state.getIcon().getURL()); isEmpty = false; } else { if (icon != null) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java b/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java index e1682b72d3..2276320cbb 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java @@ -65,7 +65,7 @@ public class VMenuBar extends SimpleFocusablePanel implements public static final String ATTRIBUTE_CHECKED = "checked"; public static final String ATTRIBUTE_ITEM_DESCRIPTION = "description"; - public static final String ATTRIBUTE_ITEM_ICON = AbstractComponentConnector.ATTRIBUTE_ICON; + public static final String ATTRIBUTE_ITEM_ICON = "icon"; public static final String ATTRIBUTE_ITEM_DISABLED = "disabled"; public static final String ATTRIBUTE_ITEM_STYLE = "style"; diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNotification.java b/src/com/vaadin/terminal/gwt/client/ui/VNotification.java index 2cbd562d43..cf62bb2de8 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VNotification.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VNotification.java @@ -59,7 +59,7 @@ public class VNotification extends VOverlay { public static final String ATTRIBUTE_NOTIFICATION_STYLE = "style"; public static final String ATTRIBUTE_NOTIFICATION_CAPTION = "caption"; public static final String ATTRIBUTE_NOTIFICATION_MESSAGE = "message"; - public static final String ATTRIBUTE_NOTIFICATION_ICON = AbstractComponentConnector.ATTRIBUTE_ICON; + public static final String ATTRIBUTE_NOTIFICATION_ICON = "icon"; public static final String ATTRIBUTE_NOTIFICATION_POSITION = "position"; public static final String ATTRIBUTE_NOTIFICATION_DELAY = "delay"; diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VPanel.java index 768a9596ae..7dcfa24d89 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VPanel.java @@ -133,11 +133,7 @@ public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner, } } - void setIconUri(UIDL uidl, ApplicationConnection client) { - final String iconUri = uidl - .hasAttribute(AbstractComponentConnector.ATTRIBUTE_ICON) ? uidl - .getStringAttribute(AbstractComponentConnector.ATTRIBUTE_ICON) - : null; + void setIconUri(String iconUri, ApplicationConnection client) { if (iconUri == null) { if (icon != null) { DOM.removeChild(captionNode, icon.getElement()); diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java index 5b14bede1d..7b166ee25f 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java @@ -266,7 +266,8 @@ public class VTabsheet extends VTabsheetBase implements Focusable, uidl, uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_CAPTION), uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DISABLED), - uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION)); + uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION), + uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ICON)); setClosable(uidl.hasAttribute("closable")); diff --git a/src/com/vaadin/terminal/gwt/client/ui/WindowConnector.java b/src/com/vaadin/terminal/gwt/client/ui/WindowConnector.java index 5bae9cd99a..5a00950a48 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/WindowConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/WindowConnector.java @@ -86,10 +86,11 @@ public class WindowConnector extends AbstractComponentContainerConnector // Caption must be set before required header size is measured. If // the caption attribute is missing the caption should be cleared. - getWidget() - .setCaption( - getState().getCaption(), - uidl.getStringAttribute(AbstractComponentConnector.ATTRIBUTE_ICON)); + String iconURL = null; + if (getState().getIcon() != null) { + iconURL = getState().getIcon().getURL(); + } + getWidget().setCaption(getState().getCaption(), iconURL); } getWidget().visibilityChangesDisabled = true; diff --git a/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/src/com/vaadin/terminal/gwt/server/JsonCodec.java index 350a70d9d4..0a617470a5 100644 --- a/src/com/vaadin/terminal/gwt/server/JsonCodec.java +++ b/src/com/vaadin/terminal/gwt/server/JsonCodec.java @@ -153,6 +153,12 @@ public class JsonCodec implements Serializable { */ public static JSONArray encode(Object value, PaintableIdMapper idMapper) throws JSONException { + return encode(value, null, idMapper); + } + + public static JSONArray encode(Object value, Class valueType, + PaintableIdMapper idMapper) throws JSONException { + if (null == value) { // TODO as undefined type? return combineTypeAndValue(JsonEncoder.VTYPE_UNDEFINED, @@ -188,7 +194,11 @@ public class JsonCodec implements Serializable { } else { // Any object that we do not know how to encode we encode by looping // through fields - return combineTypeAndValue(value.getClass().getCanonicalName(), + if (valueType == null) { + valueType = value.getClass(); + } + + return combineTypeAndValue(valueType.getCanonicalName(), encodeObject(value, idMapper)); } } @@ -201,12 +211,13 @@ public class JsonCodec implements Serializable { for (PropertyDescriptor pd : Introspector.getBeanInfo( value.getClass()).getPropertyDescriptors()) { String fieldName = pd.getName(); + Class fieldType = pd.getPropertyType(); if (pd.getReadMethod() == null || pd.getWriteMethod() == null) { continue; } Method getterMethod = pd.getReadMethod(); Object fieldValue = getterMethod.invoke(value, null); - jsonMap.put(fieldName, encode(fieldValue, idMapper)); + jsonMap.put(fieldName, encode(fieldValue, fieldType, idMapper)); } } catch (Exception e) { // TODO: Should exceptions be handled in a different way? diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java index f992b3ff2c..f80b7a3f27 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java @@ -24,11 +24,12 @@ import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; +import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.communication.JSONSerializer; import com.vaadin.terminal.gwt.client.communication.JsonDecoder; import com.vaadin.terminal.gwt.client.communication.JsonEncoder; import com.vaadin.terminal.gwt.client.communication.SerializerMap; -import com.vaadin.terminal.gwt.client.communication.JSONSerializer; /** * GWT generator for creating serializer classes for custom classes sent from @@ -113,10 +114,12 @@ public class SerializerGenerator extends Generator { // Serializer - // public JSONValue serialize(Object value, ConnectorMap idMapper) { + // public JSONValue serialize(Object value, ConnectorMap idMapper, + // ApplicationConnection connection) { sourceWriter.println("public " + JSONObject.class.getName() + " serialize(" + Object.class.getName() + " value, " - + ConnectorMap.class.getName() + " idMapper) {"); + + ConnectorMap.class.getName() + " idMapper, " + + ApplicationConnection.class.getName() + " connection) {"); sourceWriter.indent(); // MouseEventDetails castedValue = (MouseEventDetails) value; sourceWriter.println(beanQualifiedSourceName + " castedValue = (" @@ -136,10 +139,11 @@ public class SerializerGenerator extends Generator { + ". Serialization will likely fail"); } // json.put("button", - // JsonEncoder.encode(castedValue.getButton(), idMapper)); + // JsonEncoder.encode(castedValue.getButton(), idMapper, + // connection)); sourceWriter.println("json.put(\"" + fieldName + "\", " + JsonEncoder.class.getName() + ".encode(castedValue." - + getterName + "(), idMapper));"); + + getterName + "(), idMapper, connection));"); } // return json; sourceWriter.println("return json;"); @@ -149,7 +153,8 @@ public class SerializerGenerator extends Generator { // Deserializer sourceWriter.println("public " + beanQualifiedSourceName + " deserialize(" + JSONObject.class.getName() + " jsonValue, " - + ConnectorMap.class.getName() + " idMapper) {"); + + ConnectorMap.class.getName() + " idMapper, " + + ApplicationConnection.class.getName() + " connection) {"); sourceWriter.indent(); // VButtonState state = GWT.create(VButtonState.class); @@ -170,7 +175,7 @@ public class SerializerGenerator extends Generator { + " = (JSONArray) jsonValue.get(\"" + fieldName + "\");"); // state.setHeight((String) - // JsonDecoder.convertValue(jsonFieldValue,idMapper)); + // JsonDecoder.convertValue(jsonFieldValue,idMapper, connection)); String fieldType; JPrimitiveType primitiveType = setterParameterType.isPrimitive(); @@ -183,7 +188,7 @@ public class SerializerGenerator extends Generator { sourceWriter.println("state." + setterName + "((" + fieldType + ") JsonDecoder.convertValue(" + jsonFieldName - + ", idMapper));"); + + ", idMapper, connection));"); } // return state; diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java index 8282547eb0..c2a54030f7 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java @@ -19,13 +19,16 @@ import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.JMethod; import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.json.client.JSONObject; import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ConnectorMap; import com.vaadin.terminal.gwt.client.communication.ClientRpc; +import com.vaadin.terminal.gwt.client.communication.JSONSerializer; import com.vaadin.terminal.gwt.client.communication.SerializerMap; import com.vaadin.terminal.gwt.client.communication.ServerRpc; import com.vaadin.terminal.gwt.client.communication.SharedState; -import com.vaadin.terminal.gwt.client.communication.JSONSerializer; /** * GWT generator that creates a {@link SerializerMap} implementation (mapper @@ -47,13 +50,17 @@ public class SerializerMapGenerator extends Generator { TypeOracle typeOracle = context.getTypeOracle(); Set typesNeedingSerializers = findTypesNeedingSerializers( typeOracle, logger); - + Set typesWithExistingSerializers = findTypesWithExistingSerializers( + typeOracle, logger); + Set serializerMappings = new HashSet(); + serializerMappings.addAll(typesNeedingSerializers); + serializerMappings.addAll(typesWithExistingSerializers); // get classType and save instance variables JClassType classType = typeOracle.getType(typeName); packageName = classType.getPackage().getName(); className = classType.getSimpleSourceName() + "Impl"; // Generate class source code for SerializerMapImpl - generateSerializerMap(typesNeedingSerializers, logger, context); + generateSerializerMap(serializerMappings, logger, context); SerializerGenerator sg = new SerializerGenerator(); for (JClassType type : typesNeedingSerializers) { @@ -67,6 +74,27 @@ public class SerializerMapGenerator extends Generator { return packageName + "." + className; } + private Set findTypesWithExistingSerializers( + TypeOracle typeOracle, TreeLogger logger) { + JClassType serializerInterface = typeOracle + .findType(JSONSerializer.class.getName()); + Set types = new HashSet(); + for (JClassType serializer : serializerInterface.getSubtypes()) { + JType[] deserializeParamTypes = new JType[] { + typeOracle.findType(JSONObject.class.getName()), + typeOracle.findType(ConnectorMap.class.getName()), + typeOracle.findType(ApplicationConnection.class.getName()) }; + JMethod deserializeMethod = serializer.findMethod("deserialize", + deserializeParamTypes); + if (deserializeMethod == null) { + continue; + } + + types.add(deserializeMethod.getReturnType().isClass()); + } + return types; + } + /** * Generate source code for SerializerMapImpl * diff --git a/src/com/vaadin/ui/AbstractComponent.java b/src/com/vaadin/ui/AbstractComponent.java index 92e064a33f..06a15fabf8 100644 --- a/src/com/vaadin/ui/AbstractComponent.java +++ b/src/com/vaadin/ui/AbstractComponent.java @@ -35,7 +35,7 @@ import com.vaadin.terminal.Resource; import com.vaadin.terminal.Terminal; import com.vaadin.terminal.gwt.client.ComponentState; import com.vaadin.terminal.gwt.client.communication.ClientRpc; -import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; +import com.vaadin.terminal.gwt.client.communication.ResourceReference; import com.vaadin.terminal.gwt.server.ClientMethodInvocation; import com.vaadin.terminal.gwt.server.ComponentSizeValidator; import com.vaadin.terminal.gwt.server.RpcManager; @@ -70,11 +70,6 @@ public abstract class AbstractComponent implements Component, MethodEventSource */ private Object applicationData; - /** - * Icon to be shown together with caption. - */ - private Resource icon; - /** * The container this component resides in. */ @@ -341,7 +336,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource * use the default documentation from implemented interface. */ public Resource getIcon() { - return icon; + return ((ResourceReference) getState().getIcon()).getResource(); } /** @@ -353,7 +348,11 @@ public abstract class AbstractComponent implements Component, MethodEventSource * the icon to be shown with the component's caption. */ public void setIcon(Resource icon) { - this.icon = icon; + if (icon == null) { + getState().setIcon(null); + } else { + getState().setIcon(new ResourceReference(icon)); + } requestRepaint(); } @@ -736,15 +735,6 @@ public abstract class AbstractComponent implements Component, MethodEventSource // Only paint content of visible components. if (isVisible()) { - // width and height are only in shared state - - // TODO probably can remove also icon once all the VCaption - // related code has been updated - if (getIcon() != null) { - target.addAttribute( - AbstractComponentConnector.ATTRIBUTE_ICON, - getIcon()); - } if (eventIdentifiers != null) { target.addAttribute("eventListeners", diff --git a/src/com/vaadin/ui/TabSheet.java b/src/com/vaadin/ui/TabSheet.java index 01f808099a..89c363e554 100644 --- a/src/com/vaadin/ui/TabSheet.java +++ b/src/com/vaadin/ui/TabSheet.java @@ -25,7 +25,6 @@ import com.vaadin.terminal.KeyMapper; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; import com.vaadin.terminal.gwt.client.ui.TabsheetBaseConnector; import com.vaadin.terminal.gwt.client.ui.TabsheetConnector; import com.vaadin.terminal.gwt.client.ui.VTabsheet; @@ -408,7 +407,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, // VCaption.updateCaption(uidl) final Resource icon = tab.getIcon(); if (icon != null) { - target.addAttribute(AbstractComponentConnector.ATTRIBUTE_ICON, + target.addAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ICON, icon); } final String caption = tab.getCaption(); -- 2.39.5