Change-Id: I8ea2b781fab42458bf55a751c1229e391365e965tags/7.2.0.beta1
@@ -46,8 +46,10 @@ import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; | |||
import com.google.gwt.user.rebind.SourceWriter; | |||
import com.vaadin.client.JsArrayObject; | |||
import com.vaadin.client.ServerConnector; | |||
import com.vaadin.client.annotations.OnStateChange; | |||
import com.vaadin.client.metadata.ConnectorBundleLoader; | |||
import com.vaadin.client.metadata.InvokationHandler; | |||
import com.vaadin.client.metadata.OnStateChangeMethod; | |||
import com.vaadin.client.metadata.ProxyHandler; | |||
import com.vaadin.client.metadata.TypeData; | |||
import com.vaadin.client.metadata.TypeDataStore; | |||
@@ -56,6 +58,7 @@ import com.vaadin.server.widgetsetutils.metadata.ClientRpcVisitor; | |||
import com.vaadin.server.widgetsetutils.metadata.ConnectorBundle; | |||
import com.vaadin.server.widgetsetutils.metadata.ConnectorInitVisitor; | |||
import com.vaadin.server.widgetsetutils.metadata.GeneratedSerializer; | |||
import com.vaadin.server.widgetsetutils.metadata.OnStateChangeVisitor; | |||
import com.vaadin.server.widgetsetutils.metadata.Property; | |||
import com.vaadin.server.widgetsetutils.metadata.ServerRpcVisitor; | |||
import com.vaadin.server.widgetsetutils.metadata.StateInitVisitor; | |||
@@ -463,6 +466,92 @@ public class ConnectorBundleLoaderFactory extends Generator { | |||
writePropertyTypes(logger, w, bundle); | |||
writeSerializers(logger, w, bundle); | |||
writeDelegateToWidget(logger, w, bundle); | |||
writeOnStateChangeHandlers(logger, w, bundle); | |||
} | |||
private void writeOnStateChangeHandlers(TreeLogger logger, | |||
SplittingSourceWriter w, ConnectorBundle bundle) | |||
throws UnableToCompleteException { | |||
Map<JClassType, Set<JMethod>> needsOnStateChangeHandler = bundle | |||
.getNeedsOnStateChangeHandler(); | |||
for (Entry<JClassType, Set<JMethod>> entry : needsOnStateChangeHandler | |||
.entrySet()) { | |||
JClassType connector = entry.getKey(); | |||
TreeLogger typeLogger = logger.branch( | |||
Type.DEBUG, | |||
"Generating @OnStateChange support for " | |||
+ connector.getName()); | |||
// Build map to speed up error checking | |||
HashMap<String, Property> stateProperties = new HashMap<String, Property>(); | |||
JClassType stateType = ConnectorBundle | |||
.findInheritedMethod(connector, "getState").getReturnType() | |||
.isClassOrInterface(); | |||
for (Property property : bundle.getProperties(stateType)) { | |||
stateProperties.put(property.getName(), property); | |||
} | |||
for (JMethod method : entry.getValue()) { | |||
TreeLogger methodLogger = typeLogger.branch(Type.DEBUG, | |||
"Processing method " + method.getName()); | |||
if (method.isPublic() || method.isProtected()) { | |||
methodLogger | |||
.log(Type.ERROR, | |||
"@OnStateChange is only supported for methods with private or default visibility."); | |||
throw new UnableToCompleteException(); | |||
} | |||
OnStateChange onStateChange = method | |||
.getAnnotation(OnStateChange.class); | |||
String[] properties = onStateChange.value(); | |||
if (properties.length == 0) { | |||
methodLogger.log(Type.ERROR, | |||
"There are no properties to listen to"); | |||
throw new UnableToCompleteException(); | |||
} | |||
// Verify that all properties do exist | |||
for (String propertyName : properties) { | |||
if (!stateProperties.containsKey(propertyName)) { | |||
methodLogger.log(Type.ERROR, | |||
"State class has no property named " | |||
+ propertyName); | |||
throw new UnableToCompleteException(); | |||
} | |||
} | |||
if (method.getParameters().length != 0) { | |||
methodLogger.log(Type.ERROR, | |||
"Method should accept zero parameters"); | |||
throw new UnableToCompleteException(); | |||
} | |||
// new OnStateChangeMethod(Class declaringClass, String | |||
// methodName, String[], properties) | |||
w.print("store.addOnStateChangeMethod(%s, new %s(", | |||
getClassLiteralString(connector), | |||
OnStateChangeMethod.class.getName()); | |||
if (!connector.equals(method.getEnclosingType())) { | |||
w.print("%s, ", | |||
getClassLiteralString(method.getEnclosingType())); | |||
} | |||
w.print("\"%s\", ", method.getName()); | |||
w.print("new String[] {"); | |||
for (String propertyName : properties) { | |||
w.print("\"%s\", ", propertyName); | |||
} | |||
w.print("}"); | |||
w.println("));"); | |||
w.splitIfNeeded(); | |||
} | |||
} | |||
} | |||
private void writeSuperClasses(SplittingSourceWriter w, | |||
@@ -1109,7 +1198,7 @@ public class ConnectorBundleLoaderFactory extends Generator { | |||
List<TypeVisitor> visitors = Arrays.<TypeVisitor> asList( | |||
new ConnectorInitVisitor(), new StateInitVisitor(), | |||
new WidgetInitVisitor(), new ClientRpcVisitor(), | |||
new ServerRpcVisitor()); | |||
new ServerRpcVisitor(), new OnStateChangeVisitor()); | |||
for (TypeVisitor typeVisitor : visitors) { | |||
typeVisitor.init(oracle); | |||
} |
@@ -69,6 +69,7 @@ public class ConnectorBundle { | |||
private final Map<JClassType, Set<JMethod>> needsInvoker = new HashMap<JClassType, Set<JMethod>>(); | |||
private final Map<JClassType, Set<JMethod>> needsParamTypes = new HashMap<JClassType, Set<JMethod>>(); | |||
private final Map<JClassType, Set<JMethod>> needsDelayedInfo = new HashMap<JClassType, Set<JMethod>>(); | |||
private final Map<JClassType, Set<JMethod>> needsOnStateChange = new HashMap<JClassType, Set<JMethod>>(); | |||
private final Set<Property> needsProperty = new HashSet<Property>(); | |||
private final Set<Property> needsDelegateToWidget = new HashSet<Property>(); | |||
@@ -199,7 +200,7 @@ public class ConnectorBundle { | |||
JType type = iterator.next(); | |||
iterator.remove(); | |||
if (hasSserializeSupport(type)) { | |||
if (hasSerializeSupport(type)) { | |||
continue; | |||
} | |||
@@ -516,7 +517,7 @@ public class ConnectorBundle { | |||
} | |||
public void setNeedsSerialize(JType type) { | |||
if (!hasSserializeSupport(type)) { | |||
if (!hasSerializeSupport(type)) { | |||
needsSerializeSupport.add(type); | |||
} | |||
} | |||
@@ -557,12 +558,12 @@ public class ConnectorBundle { | |||
return false; | |||
} | |||
private boolean hasSserializeSupport(JType type) { | |||
private boolean hasSerializeSupport(JType type) { | |||
if (hasSerializeSupport.contains(type)) { | |||
return true; | |||
} else { | |||
return previousBundle != null | |||
&& previousBundle.hasSserializeSupport(type); | |||
&& previousBundle.hasSerializeSupport(type); | |||
} | |||
} | |||
@@ -585,4 +586,45 @@ public class ConnectorBundle { | |||
return Collections.unmodifiableSet(needsDelegateToWidget); | |||
} | |||
public void setNeedsOnStateChangeHandler(JClassType type, JMethod method) { | |||
if (!isNeedsOnStateChangeHandler(type, method)) { | |||
addMapping(needsOnStateChange, type, method); | |||
} | |||
} | |||
private boolean isNeedsOnStateChangeHandler(JClassType type, JMethod method) { | |||
if (hasMapping(needsOnStateChange, type, method)) { | |||
return true; | |||
} else { | |||
return previousBundle != null | |||
&& previousBundle.isNeedsOnStateChangeHandler(type, method); | |||
} | |||
} | |||
public Map<JClassType, Set<JMethod>> getNeedsOnStateChangeHandler() { | |||
return Collections.unmodifiableMap(needsOnStateChange); | |||
} | |||
public static JMethod findInheritedMethod(JClassType type, | |||
String methodName, JType... params) { | |||
JClassType currentType = type; | |||
while (currentType != null) { | |||
JMethod method = currentType.findMethod(methodName, params); | |||
if (method != null) { | |||
return method; | |||
} | |||
currentType = currentType.getSuperclass(); | |||
} | |||
JClassType[] interfaces = type.getImplementedInterfaces(); | |||
for (JClassType iface : interfaces) { | |||
JMethod method = iface.findMethod(methodName, params); | |||
if (method != null) { | |||
return method; | |||
} | |||
} | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,54 @@ | |||
/* | |||
* Copyright 2000-2013 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.widgetsetutils.metadata; | |||
import com.google.gwt.core.ext.TreeLogger; | |||
import com.google.gwt.core.ext.UnableToCompleteException; | |||
import com.google.gwt.core.ext.typeinfo.JClassType; | |||
import com.google.gwt.core.ext.typeinfo.JMethod; | |||
import com.vaadin.client.annotations.OnStateChange; | |||
import com.vaadin.shared.ui.Connect; | |||
/** | |||
* Visits Connector classes and check for methods with @OnStateChange | |||
* annotations. | |||
* | |||
* @since 7.2 | |||
* @author Vaadin Ltd | |||
*/ | |||
public class OnStateChangeVisitor extends TypeVisitor { | |||
@Override | |||
public void visitConnector(TreeLogger logger, JClassType type, | |||
ConnectorBundle bundle) throws UnableToCompleteException { | |||
Connect connectAnnotation = type.getAnnotation(Connect.class); | |||
if (connectAnnotation != null) { | |||
// Find all the annotated methods in all the superclasses | |||
JClassType connector = type; | |||
while (connector != null) { | |||
for (JMethod method : connector.getMethods()) { | |||
if (method.getAnnotation(OnStateChange.class) != null) { | |||
bundle.setNeedsInvoker(connector, method); | |||
bundle.setNeedsOnStateChangeHandler(type, method); | |||
} | |||
} | |||
connector = connector.getSuperclass(); | |||
} | |||
} | |||
} | |||
} |
@@ -24,7 +24,8 @@ public class StateInitVisitor extends TypeVisitor { | |||
@Override | |||
public void visitConnector(TreeLogger logger, JClassType type, | |||
ConnectorBundle bundle) { | |||
JMethod getState = findInheritedMethod(type, "getState"); | |||
JMethod getState = ConnectorBundle | |||
.findInheritedMethod(type, "getState"); | |||
bundle.setNeedsReturnType(type, getState); | |||
bundle.setNeedsSerialize(getState.getReturnType()); |
@@ -18,8 +18,6 @@ package com.vaadin.server.widgetsetutils.metadata; | |||
import com.google.gwt.core.ext.TreeLogger; | |||
import com.google.gwt.core.ext.UnableToCompleteException; | |||
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.NotFoundException; | |||
import com.google.gwt.core.ext.typeinfo.TypeOracle; | |||
@@ -43,27 +41,4 @@ public abstract class TypeVisitor { | |||
// Default does nothing | |||
} | |||
protected JMethod findInheritedMethod(JClassType type, String methodName, | |||
JType... params) { | |||
JClassType currentType = type; | |||
while (currentType != null) { | |||
JMethod method = currentType.findMethod(methodName, params); | |||
if (method != null) { | |||
return method; | |||
} | |||
currentType = currentType.getSuperclass(); | |||
} | |||
JClassType[] interfaces = type.getImplementedInterfaces(); | |||
for (JClassType iface : interfaces) { | |||
JMethod method = iface.findMethod(methodName, params); | |||
if (method != null) { | |||
return method; | |||
} | |||
} | |||
return null; | |||
} | |||
} |
@@ -32,10 +32,11 @@ public class WidgetInitVisitor extends TypeVisitor { | |||
ConnectorBundle bundle) throws UnableToCompleteException { | |||
if (ConnectorBundle.isConnectedComponentConnector(type)) { | |||
// The class in which createWidget is implemented | |||
JClassType createWidgetClass = findInheritedMethod(type, | |||
"createWidget").getEnclosingType(); | |||
JClassType createWidgetClass = ConnectorBundle.findInheritedMethod( | |||
type, "createWidget").getEnclosingType(); | |||
JMethod getWidget = findInheritedMethod(type, "getWidget"); | |||
JMethod getWidget = ConnectorBundle.findInheritedMethod(type, | |||
"getWidget"); | |||
JClassType widgetType = getWidget.getReturnType().isClass(); | |||
// Needs GWT constructor if createWidget is not overridden | |||
@@ -48,7 +49,8 @@ public class WidgetInitVisitor extends TypeVisitor { | |||
} | |||
// Check state properties for @DelegateToWidget | |||
JMethod getState = findInheritedMethod(type, "getState"); | |||
JMethod getState = ConnectorBundle.findInheritedMethod(type, | |||
"getState"); | |||
JClassType stateType = getState.getReturnType().isClass(); | |||
Collection<Property> properties = bundle.getProperties(stateType); | |||
@@ -63,8 +65,9 @@ public class WidgetInitVisitor extends TypeVisitor { | |||
String methodName = DelegateToWidget.Helper | |||
.getDelegateTarget(property.getName(), | |||
delegateToWidget.value()); | |||
JMethod delegatedSetter = findInheritedMethod(widgetType, | |||
methodName, property.getPropertyType()); | |||
JMethod delegatedSetter = ConnectorBundle | |||
.findInheritedMethod(widgetType, methodName, | |||
property.getPropertyType()); | |||
if (delegatedSetter == null) { | |||
logger.log( | |||
Type.ERROR, |
@@ -0,0 +1,50 @@ | |||
/* | |||
* Copyright 2000-2013 Vaadin Ltd. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||
* use this file except in compliance with the License. You may obtain a copy of | |||
* the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||
* License for the specific language governing permissions and limitations under | |||
* the License. | |||
*/ | |||
package com.vaadin.client.annotations; | |||
import java.lang.annotation.Documented; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
import com.vaadin.client.communication.StateChangeEvent; | |||
/** | |||
* Marks a method in Connector classes that should be used to handle changes to | |||
* specific properties in the connector's shared state. | |||
* <p> | |||
* The annotated method will by called whenever at least one of the named state | |||
* properties have changed. If multiple listened properties are changed by the | |||
* same {@link StateChangeEvent}, the method will only be called once. | |||
* <p> | |||
* If there is no state variable with the provided name, the widgetset | |||
* compilation will fail. | |||
* | |||
* @since 7.2 | |||
* @author Vaadin Ltd | |||
*/ | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@Target(ElementType.METHOD) | |||
@Documented | |||
public @interface OnStateChange { | |||
/** | |||
* Defines a list of property names to listen for. | |||
* | |||
* @return an array of property names, should contain at least one item | |||
*/ | |||
public String[] value(); | |||
} |
@@ -0,0 +1,111 @@ | |||
/* | |||
* Copyright 2000-2013 Vaadin Ltd. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||
* use this file except in compliance with the License. You may obtain a copy of | |||
* the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||
* License for the specific language governing permissions and limitations under | |||
* the License. | |||
*/ | |||
package com.vaadin.client.metadata; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import com.vaadin.client.ServerConnector; | |||
import com.vaadin.client.annotations.OnStateChange; | |||
import com.vaadin.client.communication.StateChangeEvent; | |||
/** | |||
* Encapsulates the data that the widgetset compiler generates for supporting a | |||
* connector method annotated with {@link OnStateChange} | |||
* | |||
* @since 7.2 | |||
* @author Vaadin Ltd | |||
*/ | |||
public class OnStateChangeMethod { | |||
private final String methodName; | |||
private final List<String> properties; | |||
private final Class<?> declaringClass; | |||
/** | |||
* Creates a new instance based on a method name, a list of parameters names | |||
* and a list of properties to listen for. | |||
* | |||
* @param methodName | |||
* the name of the method to call | |||
* @param properties | |||
* an array of state property names to listen to | |||
*/ | |||
public OnStateChangeMethod(String methodName, String[] properties) { | |||
this(null, methodName, properties); | |||
} | |||
/** | |||
* Creates a new instance based on declaring class, a method name, a list of | |||
* parameters names and a list of properties to listen for. | |||
* <p> | |||
* If the declaring class is <code>null</code>, the method is found based on | |||
* the type of the connector that fired the state change event. | |||
* | |||
* @param declaringClass | |||
* the class in which the target method is declared, or | |||
* <code>null</code> to use the class of the connector firing the | |||
* event | |||
* @param methodName | |||
* the name of the method to call | |||
* @param properties | |||
* an array of state property names to listen to | |||
*/ | |||
public OnStateChangeMethod(Class<?> declaringClass, String methodName, | |||
String[] properties) { | |||
this.methodName = methodName; | |||
this.properties = Collections.unmodifiableList(Arrays | |||
.asList(properties)); | |||
this.declaringClass = declaringClass; | |||
} | |||
/** | |||
* Invokes the listener method for a state change. | |||
* | |||
* @param stateChangeEvent | |||
* the state change event | |||
*/ | |||
public void invoke(StateChangeEvent stateChangeEvent) { | |||
ServerConnector connector = (ServerConnector) stateChangeEvent | |||
.getSource(); | |||
Class<?> declaringClass = this.declaringClass; | |||
if (declaringClass == null) { | |||
declaringClass = connector.getClass(); | |||
} | |||
Type declaringType = TypeDataStore.getType(declaringClass); | |||
try { | |||
declaringType.getMethod(methodName).invoke(connector); | |||
} catch (NoDataException e) { | |||
throw new RuntimeException("Couldn't invoke @OnStateChange method " | |||
+ declaringType.getSignature() + "." + methodName, e); | |||
} | |||
} | |||
/** | |||
* Gets the list of state property names to listen for. | |||
* | |||
* @return the list of state property names to listen for | |||
*/ | |||
public List<String> getProperties() { | |||
return properties; | |||
} | |||
} |
@@ -23,6 +23,7 @@ import com.google.gwt.core.client.JsArrayString; | |||
import com.vaadin.client.FastStringMap; | |||
import com.vaadin.client.FastStringSet; | |||
import com.vaadin.client.JsArrayObject; | |||
import com.vaadin.client.annotations.OnStateChange; | |||
import com.vaadin.client.communication.JSONSerializer; | |||
public class TypeDataStore { | |||
@@ -37,6 +38,12 @@ public class TypeDataStore { | |||
private final FastStringMap<JsArrayString> delegateToWidgetProperties = FastStringMap | |||
.create(); | |||
/** | |||
* Maps connector class -> state property name -> hander method data | |||
*/ | |||
private final FastStringMap<FastStringMap<JsArrayObject<OnStateChangeMethod>>> onStateChangeMethods = FastStringMap | |||
.create(); | |||
private final FastStringSet delayedMethods = FastStringSet.create(); | |||
private final FastStringSet lastOnlyMethods = FastStringSet.create(); | |||
@@ -368,4 +375,47 @@ public class TypeDataStore { | |||
return typeData[beanName] !== undefined ; | |||
}-*/; | |||
/** | |||
* Gets data for all methods annotated with {@link OnStateChange} in the | |||
* given connector type. | |||
* | |||
* @since 7.2 | |||
* @param type | |||
* the connector type | |||
* @return a map of state property names to handler method data | |||
*/ | |||
public static FastStringMap<JsArrayObject<OnStateChangeMethod>> getOnStateChangeMethods( | |||
Class<?> type) { | |||
return get().onStateChangeMethods.get(getType(type).getSignature()); | |||
} | |||
/** | |||
* Adds data about a method annotated with {@link OnStateChange} for the | |||
* given connector type. | |||
* | |||
* @since 7.2 | |||
* @param clazz | |||
* the connector type | |||
* @param method | |||
* the state change method data | |||
*/ | |||
public void addOnStateChangeMethod(Class<?> clazz, | |||
OnStateChangeMethod method) { | |||
FastStringMap<JsArrayObject<OnStateChangeMethod>> handlers = getOnStateChangeMethods(clazz); | |||
if (handlers == null) { | |||
handlers = FastStringMap.create(); | |||
onStateChangeMethods.put(getType(clazz).getSignature(), handlers); | |||
} | |||
for (String property : method.getProperties()) { | |||
JsArrayObject<OnStateChangeMethod> propertyHandlers = handlers | |||
.get(property); | |||
if (propertyHandlers == null) { | |||
propertyHandlers = JsArrayObject.createArray().cast(); | |||
handlers.put(property, propertyHandlers); | |||
} | |||
propertyHandlers.add(method); | |||
} | |||
} | |||
} |
@@ -18,6 +18,7 @@ package com.vaadin.client.ui; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Set; | |||
@@ -27,6 +28,7 @@ import com.google.gwt.event.shared.HandlerManager; | |||
import com.google.web.bindery.event.shared.HandlerRegistration; | |||
import com.vaadin.client.ApplicationConnection; | |||
import com.vaadin.client.FastStringMap; | |||
import com.vaadin.client.JsArrayObject; | |||
import com.vaadin.client.Profiler; | |||
import com.vaadin.client.ServerConnector; | |||
import com.vaadin.client.Util; | |||
@@ -35,8 +37,10 @@ import com.vaadin.client.communication.RpcProxy; | |||
import com.vaadin.client.communication.StateChangeEvent; | |||
import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler; | |||
import com.vaadin.client.metadata.NoDataException; | |||
import com.vaadin.client.metadata.OnStateChangeMethod; | |||
import com.vaadin.client.metadata.Type; | |||
import com.vaadin.client.metadata.TypeData; | |||
import com.vaadin.client.metadata.TypeDataStore; | |||
import com.vaadin.shared.communication.ClientRpc; | |||
import com.vaadin.shared.communication.ServerRpc; | |||
import com.vaadin.shared.communication.SharedState; | |||
@@ -290,6 +294,37 @@ public abstract class AbstractConnector implements ServerConnector, | |||
} | |||
updateEnabledState(isEnabled()); | |||
FastStringMap<JsArrayObject<OnStateChangeMethod>> handlers = TypeDataStore | |||
.getOnStateChangeMethods(getClass()); | |||
if (handlers != null) { | |||
Profiler.enter("AbstractConnector.onStateChanged @OnStateChange"); | |||
HashSet<OnStateChangeMethod> invokedMethods = new HashSet<OnStateChangeMethod>(); | |||
JsArrayString propertyNames = handlers.getKeys(); | |||
for (int i = 0; i < propertyNames.length(); i++) { | |||
String propertyName = propertyNames.get(i); | |||
if (stateChangeEvent.hasPropertyChanged(propertyName)) { | |||
JsArrayObject<OnStateChangeMethod> propertyMethods = handlers | |||
.get(propertyName); | |||
for (int j = 0; j < propertyMethods.size(); j++) { | |||
OnStateChangeMethod method = propertyMethods.get(j); | |||
if (invokedMethods.add(method)) { | |||
method.invoke(stateChangeEvent); | |||
} | |||
} | |||
} | |||
} | |||
Profiler.leave("AbstractConnector.onStateChanged @OnStateChange"); | |||
} | |||
Profiler.leave("AbstractConnector.onStateChanged"); | |||
} | |||
@@ -26,8 +26,8 @@ import com.google.gwt.event.shared.HandlerRegistration; | |||
import com.google.gwt.user.client.DOM; | |||
import com.vaadin.client.EventHelper; | |||
import com.vaadin.client.MouseEventDetailsBuilder; | |||
import com.vaadin.client.annotations.OnStateChange; | |||
import com.vaadin.client.communication.StateChangeEvent; | |||
import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler; | |||
import com.vaadin.client.ui.AbstractComponentConnector; | |||
import com.vaadin.client.ui.Icon; | |||
import com.vaadin.client.ui.VButton; | |||
@@ -56,44 +56,38 @@ public class ButtonConnector extends AbstractComponentConnector implements | |||
super.init(); | |||
getWidget().addClickHandler(this); | |||
getWidget().client = getConnection(); | |||
addStateChangeHandler("errorMessage", new StateChangeHandler() { | |||
@Override | |||
public void onStateChanged(StateChangeEvent stateChangeEvent) { | |||
if (null != getState().errorMessage) { | |||
if (getWidget().errorIndicatorElement == null) { | |||
getWidget().errorIndicatorElement = DOM.createSpan(); | |||
getWidget().errorIndicatorElement | |||
.setClassName("v-errorindicator"); | |||
} | |||
getWidget().wrapper.insertBefore( | |||
getWidget().errorIndicatorElement, | |||
getWidget().captionElement); | |||
} else if (getWidget().errorIndicatorElement != null) { | |||
getWidget().wrapper | |||
.removeChild(getWidget().errorIndicatorElement); | |||
getWidget().errorIndicatorElement = null; | |||
} | |||
} | |||
}); | |||
addStateChangeHandler("resources", new StateChangeHandler() { | |||
@Override | |||
public void onStateChanged(StateChangeEvent stateChangeEvent) { | |||
if (getWidget().icon != null) { | |||
getWidget().wrapper.removeChild(getWidget().icon | |||
.getElement()); | |||
getWidget().icon = null; | |||
} | |||
Icon icon = getIcon(); | |||
if (icon != null) { | |||
getWidget().icon = icon; | |||
icon.setAlternateText(getState().iconAltText); | |||
getWidget().wrapper.insertBefore(icon.getElement(), | |||
getWidget().captionElement); | |||
} | |||
} | |||
@OnStateChange("errorMessage") | |||
void setErrorMessage() { | |||
if (null != getState().errorMessage) { | |||
if (getWidget().errorIndicatorElement == null) { | |||
getWidget().errorIndicatorElement = DOM.createSpan(); | |||
getWidget().errorIndicatorElement | |||
.setClassName("v-errorindicator"); | |||
} | |||
}); | |||
getWidget().wrapper.insertBefore(getWidget().errorIndicatorElement, | |||
getWidget().captionElement); | |||
} else if (getWidget().errorIndicatorElement != null) { | |||
getWidget().wrapper.removeChild(getWidget().errorIndicatorElement); | |||
getWidget().errorIndicatorElement = null; | |||
} | |||
} | |||
@OnStateChange("resources") | |||
void onResourceChange() { | |||
if (getWidget().icon != null) { | |||
getWidget().wrapper.removeChild(getWidget().icon.getElement()); | |||
getWidget().icon = null; | |||
} | |||
Icon icon = getIcon(); | |||
if (icon != null) { | |||
getWidget().icon = icon; | |||
icon.setAlternateText(getState().iconAltText); | |||
getWidget().wrapper.insertBefore(icon.getElement(), | |||
getWidget().captionElement); | |||
} | |||
} | |||
@Override | |||
@@ -103,22 +97,27 @@ public class ButtonConnector extends AbstractComponentConnector implements | |||
focusHandlerRegistration); | |||
blurHandlerRegistration = EventHelper.updateBlurHandler(this, | |||
blurHandlerRegistration); | |||
} | |||
if (stateChangeEvent.hasPropertyChanged("caption") | |||
|| stateChangeEvent.hasPropertyChanged("htmlContentAllowed")) { | |||
// Set text | |||
if (getState().htmlContentAllowed) { | |||
getWidget().setHtml(getState().caption); | |||
} else { | |||
getWidget().setText(getState().caption); | |||
} | |||
@OnStateChange({ "caption", "htmlContentAllowed" }) | |||
void setCaption() { | |||
String caption = getState().caption; | |||
if (getState().htmlContentAllowed) { | |||
getWidget().setHtml(caption); | |||
} else { | |||
getWidget().setText(caption); | |||
} | |||
} | |||
if (getWidget().icon != null | |||
&& stateChangeEvent.hasPropertyChanged("iconAltText")) { | |||
@OnStateChange("iconAltText") | |||
void setIconAltText() { | |||
if (getWidget().icon != null) { | |||
getWidget().icon.setAlternateText(getState().iconAltText); | |||
} | |||
} | |||
@OnStateChange("clickShortcutKeyCode") | |||
void setClickShortcut() { | |||
getWidget().clickShortcut = getState().clickShortcutKeyCode; | |||
} | |||