Revision: 9824
Author: gwt.mirror...@gmail.com
Date: Tue Mar 8 09:11:26 2011
Log: property fall back value evaluation scheme - enable fall back bindings.
Review at http://gwt-code-reviews.appspot.com/1369807
http://code.google.com/p/google-web-toolkit/source/detail?r=9824
Added:
/trunk/user/src/com/google/gwt/user/rebind/UserAgentPropertyGeneratorPredicate.java
Modified:
/trunk/dev/core/src/com/google/gwt/core/ext/DefaultSelectionProperty.java
/trunk/dev/core/src/com/google/gwt/core/ext/SelectionProperty.java
/trunk/dev/core/src/com/google/gwt/dev/cfg/BindingProperty.java
/trunk/dev/core/src/com/google/gwt/dev/cfg/ConditionWhenPropertyIs.java
/trunk/dev/core/src/com/google/gwt/dev/cfg/DeferredBindingQuery.java
/trunk/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
/trunk/dev/core/src/com/google/gwt/dev/cfg/Rule.java
/trunk/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java
/trunk/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java
/trunk/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
/trunk/dev/core/src/com/google/gwt/dev/util/xml/HandlerArgs.java
/trunk/dev/core/src/com/google/gwt/dev/util/xml/HandlerParam.java
/trunk/dev/core/test/com/google/gwt/dev/js/JsCoerceIntShiftTest.java
/trunk/user/src/com/google/gwt/user/UserAgent.gwt.xml
/trunk/user/src/com/google/gwt/user/rebind/UserAgentGenerator.java
/trunk/user/src/com/google/gwt/user/rebind/UserAgentPropertyGenerator.java
=======================================
--- /dev/null
+++
/trunk/user/src/com/google/gwt/user/rebind/UserAgentPropertyGeneratorPredicate.java
Tue Mar 8 09:11:26 2011
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * 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.google.gwt.user.rebind;
+
+/**
+ * Represents a predicate expressed in Javascript
+ * returns the given user agent if predicate evaluates
+ * to true.
+ */
+public class UserAgentPropertyGeneratorPredicate {
+
+ private final StringSourceWriter predicateWriter = new
StringSourceWriter();
+ private String userAgent;
+ private String returnValue;
+
+ public UserAgentPropertyGeneratorPredicate(String userAgent) {
+ assert userAgent != null;
+ assert userAgent.length() > 0;
+ this.userAgent = userAgent;
+ }
+
+ public UserAgentPropertyGeneratorPredicate getPredicateBlock() {
+ return this;
+ }
+
+ public String getReturnValue() {
+ return returnValue;
+ }
+
+ public String getUserAgent() {
+ return userAgent;
+ }
+
+ public UserAgentPropertyGeneratorPredicate indent() {
+ predicateWriter.indent();
+ return this;
+ }
+
+ public UserAgentPropertyGeneratorPredicate outdent() {
+ predicateWriter.outdent();
+ return this;
+ }
+
+ public UserAgentPropertyGeneratorPredicate println(String s) {
+ predicateWriter.println(s);
+ return this;
+ }
+
+ public UserAgentPropertyGeneratorPredicate returns(String s) {
+ returnValue = s;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return predicateWriter.toString();
+ }
+}
=======================================
---
/trunk/dev/core/src/com/google/gwt/core/ext/DefaultSelectionProperty.java
Mon Nov 16 13:28:11 2009
+++
/trunk/dev/core/src/com/google/gwt/core/ext/DefaultSelectionProperty.java
Tue Mar 8 09:11:26 2011
@@ -15,6 +15,9 @@
*/
package com.google.gwt.core.ext;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.SortedSet;
/**
@@ -27,6 +30,7 @@
private final String fallbackValue;
private final String name;
private final SortedSet<String> possibleValues;
+ private final Map<String, ? extends List<? extends Set<String>>>
fallbackValueMap;
/**
* Construct a selection property.
@@ -40,6 +44,23 @@
*/
public DefaultSelectionProperty(String currentValue, String
fallbackValue,
String name, SortedSet<String> possibleValues) {
+ this(currentValue, fallbackValue, name, possibleValues, null);
+ }
+
+ /**
+ * Construct a selection property.
+ *
+ * @param currentValue current value of this property, must not be null
+ * @param fallbackValue the fallback value to use, must not be null
+ * @param name the name of this property, must not be null
+ * @param possibleValues the set of possible values, must not be null and
+ * will be returned to callers, so a copy should be passed into this
+ * ctor if the caller will use this set later
+ * @param map the map propertyValue to fallback values
+ */
+ public DefaultSelectionProperty(String currentValue, String
fallbackValue,
+ String name, SortedSet<String> possibleValues,
+ Map<String, ? extends List<? extends Set<String>>> fallbackValueMap)
{
assert currentValue != null;
assert fallbackValue != null;
assert name != null;
@@ -48,6 +69,7 @@
this.fallbackValue = fallbackValue;
this.name = name;
this.possibleValues = possibleValues;
+ this.fallbackValueMap = fallbackValueMap;
}
@Override
@@ -75,6 +97,10 @@
public String getFallbackValue() {
return fallbackValue;
}
+
+ public List<? extends Set<String>> getFallbackValues(String value) {
+ return (null != fallbackValueMap) ? fallbackValueMap.get(value) : null;
+ }
public String getName() {
return name;
=======================================
--- /trunk/dev/core/src/com/google/gwt/core/ext/SelectionProperty.java Tue
Jun 30 14:56:38 2009
+++ /trunk/dev/core/src/com/google/gwt/core/ext/SelectionProperty.java Tue
Mar 8 09:11:26 2011
@@ -16,6 +16,8 @@
package com.google.gwt.core.ext;
+import java.util.List;
+import java.util.Set;
import java.util.SortedSet;
/**
@@ -46,6 +48,14 @@
*/
String getFallbackValue();
+ /**
+ * Returns the list of fall back values for a given value.
+ * @param value the property value
+ * @return the fall back list of values by increasing order
+ * of preference.
+ */
+ List<? extends Set<String>> getFallbackValues(String value);
+
/**
* Returns the possible values for the property in sorted order.
*
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/cfg/BindingProperty.java Mon Dec
20 11:48:24 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/cfg/BindingProperty.java Tue
Mar 8 09:11:26 2011
@@ -28,11 +28,13 @@
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
+import java.util.Map.Entry;
import java.util.regex.Pattern;
/**
@@ -51,6 +53,8 @@
private PropertyProvider provider;
private Class<? extends PropertyProviderGenerator> providerGenerator;
private String fallback;
+ private HashMap<String,LinkedList<LinkedHashSet<String>>>
fallbackValueMap;
+ private HashMap<String,LinkedList<String>> fallbackValues = new
HashMap<String,LinkedList<String>>();
private final ConditionAll rootCondition = new ConditionAll();
{
@@ -93,6 +97,20 @@
}
set.add(newValue);
}
+
+ /**
+ * Adds fall back value to given property name.
+ * @param value the property value.
+ * @param fallbackValue the fall back value for given property value.
+ */
+ public void addFallbackValue(String value, String fallbackValue) {
+ LinkedList<String> values = fallbackValues.get(fallbackValue);
+ if (values == null) {
+ values = new LinkedList<String>();
+ fallbackValues.put(fallbackValue, values);
+ }
+ values.addFirst(value);
+ }
/**
* Returns the set of allowed values in sorted order when a certain
condition
@@ -145,6 +163,43 @@
return fallback;
}
+ /**
+ * Returns the map of values to fall back values. the list of fall
+ * back values is in decreasing order of preference.
+ * @return map of property value to fall back values.
+ */
+ public Map<String,? extends List<? extends Set<String>>>
getFallbackValuesMap() {
+ if (fallbackValueMap == null) {
+ HashMap<String,LinkedList<LinkedHashSet<String>>> valuesMap = new
HashMap<String,LinkedList<LinkedHashSet<String>>>();
+ // compute closure of fall back values preserving order
+ for (Entry<String, LinkedList<String>> e :
fallbackValues.entrySet()) {
+ String from = e.getKey();
+ LinkedList<LinkedHashSet<String>> alternates = new
LinkedList<LinkedHashSet<String>>();
+ valuesMap.put(from, alternates);
+ LinkedList<String> childList = fallbackValues.get(from);
+ LinkedHashSet<String> children = new LinkedHashSet<String>();
+ children.addAll(childList);
+ while (children != null && children.size() > 0)
+ {
+ alternates.add(children);
+ LinkedHashSet<String> newChildren = new LinkedHashSet<String>();
+ for (String child : children) {
+ childList = fallbackValues.get(child);
+ if (null == childList) {
+ continue;
+ }
+ for (String val : childList) {
+ newChildren.add(val);
+ }
+ }
+ children = newChildren;
+ }
+ }
+ fallbackValueMap = valuesMap;
+ }
+ return fallbackValueMap;
+ }
+
public PropertyProvider getProvider() {
return provider;
}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/cfg/ConditionWhenPropertyIs.java
Wed Aug 11 09:22:23 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/cfg/ConditionWhenPropertyIs.java
Tue Mar 8 09:11:26 2011
@@ -23,6 +23,7 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.util.collect.Sets;
+import java.util.List;
import java.util.Set;
/**
@@ -69,6 +70,31 @@
if (testValue.equals(value)) {
return true;
} else {
+ // no exact match was found, see if any fall back
+ // value would satisfy the condition
+ try {
+ SelectionProperty prop =
propertyOracle.getSelectionProperty(logger,
+ propName);
+ List<? extends Set<String>> fallbackValues =
prop.getFallbackValues(value);
+ if (fallbackValues != null && fallbackValues.size() > 0) {
+ logger.log(TreeLogger.DEBUG, "Property value '" + value + "'" +
+ " is the fallback of '" + fallbackValues.toString() + "'",
null);
+ int cost = -1;
+ for (Set<String> values : fallbackValues) {
+ for (String fallbackValue : values) {
+ if (testValue.equals(fallbackValue)) {
+ query.setFallbackEvaluationCost(cost);
+ return false;
+ }
+ }
+ cost--;
+ }
+ }
+ }
+ catch (BadPropertyValueException e) {
+ // do nothing - currently, only selection
+ // properties support fall back values
+ }
return false;
}
} catch (BadPropertyValueException e) {
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/cfg/DeferredBindingQuery.java
Thu Mar 4 12:16:00 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/cfg/DeferredBindingQuery.java
Tue Mar 8 09:11:26 2011
@@ -26,6 +26,7 @@
* against such a query.
*/
public class DeferredBindingQuery {
+ private int fallbackEvalCost = Integer.MAX_VALUE;
private final Set<String> linkerNames;
private final PropertyOracle propertyOracle;
private final String testType;
@@ -54,6 +55,10 @@
this.testType = testType;
}
+ public int getFallbackEvaluationCost() {
+ return fallbackEvalCost;
+ }
+
public Set<String> getLinkerNames() {
return linkerNames;
}
@@ -69,4 +74,8 @@
public TypeOracle getTypeOracle() {
return typeOracle;
}
-}
+
+ public void setFallbackEvaluationCost(int cost) {
+ fallbackEvalCost = cost;
+ }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java Mon Dec
20 11:48:24 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java Tue
Mar 8 09:11:26 2011
@@ -98,6 +98,9 @@
@SuppressWarnings("unused") // referenced reflectively
protected final String __extend_property_2_values = null;
+ @SuppressWarnings("unused") // referenced reflectively ($ means
optional)
+ protected final String __extend_property_3_fallback_value$ = null;
+
@SuppressWarnings("unused") // referenced reflectively
protected final String __generate_with_1_class = null;
@@ -441,11 +444,25 @@
@SuppressWarnings("unused") // called reflectively
protected Schema __extend_property_begin(BindingProperty property,
- PropertyValue[] values) {
+ PropertyValue[] values, PropertyFallbackValue fallbackValue)
+ throws UnableToCompleteException {
for (int i = 0; i < values.length; i++) {
property.addDefinedValue(property.getRootCondition(),
values[i].token);
}
+ // validate fallback-property value if present
+ if (fallbackValue != null) {
+ if (!property.isDefinedValue(fallbackValue.token)) {
+ logger.log(TreeLogger.ERROR, "The property " + property.name
+ + " fallback-value was not defined");
+ throw new UnableToCompleteException();
+ }
+ // add fallback map to the property
+ for (int i = 0; i < values.length; i++) {
+ property.addFallbackValue(values[i].token, fallbackValue.token);
+ }
+ }
+
// No children.
return null;
}
@@ -1184,6 +1201,14 @@
}
}
+ private static class PropertyFallbackValue {
+ public final String token;
+
+ public PropertyFallbackValue(String token) {
+ this.token = token;
+ }
+ }
+
/**
* Converts a comma-separated string into an array of property value
tokens.
*/
@@ -1235,6 +1260,24 @@
}
}
+ /**
+ * Converts a string into a property fallback value, validating it in
the process.
+ */
+ private final class PropertyFallbackValueAttrCvt extends
AttributeConverter {
+ @Override
+ public Object convertToArg(Schema schema, int line, String elem,
+ String attr, String value) throws UnableToCompleteException {
+ String token = value.trim();
+ if (Util.isValidJavaIdent(token)) {
+ return new PropertyFallbackValue(token);
+ } else {
+ Messages.PROPERTY_VALUE_INVALID.log(logger, token, null);
+ throw new UnableToCompleteException();
+ }
+ }
+ }
+
+
/**
* Converts a comma-separated string into an array of property value
tokens.
*/
@@ -1351,6 +1394,7 @@
private final PropertyNameAttrCvt propNameAttrCvt = new
PropertyNameAttrCvt();
private final PropertyValueArrayAttrCvt propValueArrayAttrCvt = new
PropertyValueArrayAttrCvt();
private final PropertyValueAttrCvt propValueAttrCvt = new
PropertyValueAttrCvt();
+ private final PropertyFallbackValueAttrCvt propFallbackValueAttrCvt =
new PropertyFallbackValueAttrCvt();
private final PropertyValueGlobArrayAttrCvt propValueGlobArrayAttrCvt =
new PropertyValueGlobArrayAttrCvt();
private final PropertyValueGlobAttrCvt propValueGlobAttrCvt = new
PropertyValueGlobAttrCvt();
@@ -1371,6 +1415,7 @@
registerAttributeConverter(ConfigurationProperty.class,
configurationPropAttrCvt);
registerAttributeConverter(PropertyValue.class, propValueAttrCvt);
+ registerAttributeConverter(PropertyFallbackValue.class,
propFallbackValueAttrCvt);
registerAttributeConverter(PropertyValue[].class,
propValueArrayAttrCvt);
registerAttributeConverter(PropertyValueGlob.class,
propValueGlobAttrCvt);
registerAttributeConverter(PropertyValueGlob[].class,
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/cfg/Rule.java Mon Dec 20
10:49:11 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/cfg/Rule.java Tue Mar 8
09:11:26 2011
@@ -24,19 +24,35 @@
* Abstract base class for various kinds of deferred binding rules.
*/
public abstract class Rule {
-
+
+ private int fallbackEvalCost = Integer.MAX_VALUE;
private final ConditionAll rootCondition = new ConditionAll();
+ /**
+ * Returns the cost of evaluation fallback binding values.
+ * when isApplicable() is true, this value is meaningless
+ * when isApplicable() is false, [1,Integer.MAX_VALUE-1] means
+ * a relative scale of cost, where cost c is better than cost c+k
+ * Integer.MAX_VALUE implies no match.
+ * @return cost of evaluating fallback values.
+ */
+ public int getFallbackEvaluationCost() {
+ return fallbackEvalCost;
+ }
+
public ConditionAll getRootCondition() {
return rootCondition;
}
-
+
public boolean isApplicable(TreeLogger logger,
StandardGeneratorContext context, String typeName)
throws UnableToCompleteException {
- return rootCondition.isTrue(logger, new DeferredBindingQuery(
+ DeferredBindingQuery query = new DeferredBindingQuery(
context.getPropertyOracle(), context.getActiveLinkerNames(),
- context.getTypeOracle(), typeName));
+ context.getTypeOracle(), typeName);
+ boolean result = rootCondition.isTrue(logger, query);
+ fallbackEvalCost = query.getFallbackEvaluationCost();
+ return result;
}
public abstract RebindResult realize(TreeLogger logger,
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java
Thu Mar 25 12:00:47 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java
Tue Mar 8 09:11:26 2011
@@ -22,6 +22,9 @@
import com.google.gwt.core.ext.TreeLogger;
import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.TreeSet;
/**
@@ -152,7 +155,7 @@
possibleValues.add(v);
}
return new DefaultSelectionProperty(value, prop.getFallback(),
name,
- possibleValues);
+ possibleValues, (Map<String, List<Set<String>>>)
prop.getFallbackValuesMap());
}
}
=======================================
---
/trunk/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java
Thu Dec 16 11:33:51 2010
+++
/trunk/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java
Tue Mar 8 09:11:26 2011
@@ -135,7 +135,8 @@
for (String v : cprop.getDefinedValues()) {
possibleValues.add(v);
}
- return new DefaultSelectionProperty(value, fallback, name,
possibleValues);
+ return new DefaultSelectionProperty(value, fallback, name,
possibleValues,
+ cprop.getFallbackValuesMap());
} else {
throw new BadPropertyValueException(propertyName);
}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
Wed Feb 9 07:49:06 2011
+++ /trunk/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
Tue Mar 8 09:11:26 2011
@@ -116,6 +116,8 @@
"No rules are defined, so no substitution can occur", null);
return null;
}
+
+ Rule minCostRuleSoFar = null;
for (Iterator<Rule> iter = rules.iterator(); iter.hasNext();) {
Rule rule = iter.next();
@@ -132,7 +134,7 @@
if (!usedRules.contains(rule)) {
usedRules.add(rule);
Messages.TRACE_RULE_MATCHED.log(logger, null);
-
+
return rule;
} else {
// We are skipping this rule because it has already been used
@@ -141,11 +143,35 @@
}
} else {
Messages.TRACE_RULE_DID_NOT_MATCH.log(logger, null);
+
+ // keep track of fallback partial matches
+ if (minCostRuleSoFar == null) {
+ minCostRuleSoFar = rule;
+ }
+ assert rule.getFallbackEvaluationCost() != 0;
+ // if we found a better match, keep that as the best candidate
so far
+ if (rule.getFallbackEvaluationCost() <=
minCostRuleSoFar.getFallbackEvaluationCost()) {
+ logger.log(TreeLogger.DEBUG, "Found better fallback match
for " + rule);
+ minCostRuleSoFar = rule;
+ }
}
}
+ // if we reach this point, it means we did not find an exact match
+ // and we may have a partial match based on fall back values
+ assert minCostRuleSoFar != null;
+ if (minCostRuleSoFar.getFallbackEvaluationCost() <
Integer.MAX_VALUE) {
+ logger.log(TreeLogger.WARN, "Could not find an exact match rule.
Using 'closest' rule " +
+ minCostRuleSoFar + " based on fall back values. You may need
to implement a specific " +
+ "binding in case the fall back behavior does not replace the
missing binding");
+ if (!usedRules.contains(minCostRuleSoFar)) {
+ usedRules.add(minCostRuleSoFar);
+ logger.log(TreeLogger.DEBUG, "No exact match was found, using
closest match rule " + minCostRuleSoFar);
+ return minCostRuleSoFar;
+ }
+ }
+
// No matching rule for this type.
- //
return null;
}
@@ -161,14 +187,14 @@
if (!genCtx.isGeneratorResultCachingEnabled()) {
return resultTypeName;
}
-
+
RebindStatus status = newResult.getResultStatus();
switch (status) {
case USE_EXISTING:
// in this case, no newly generated or cached types are needed
break;
-
+
case USE_ALL_NEW_WITH_NO_CACHING:
/*
* in this case, new artifacts have been generated, but no need
to
@@ -176,7 +202,7 @@
* advantage of caching).
*/
break;
-
+
case USE_ALL_NEW:
// use all new results, add a new cache entry
cachedResult = new
CachedRebindResult(newResult.getReturnedTypeName(),
@@ -184,18 +210,18 @@
System.currentTimeMillis(), newResult.getClientDataMap());
rebindCachePut(rule, typeName, cachedResult);
break;
-
+
case USE_ALL_CACHED:
// use all cached results
assert (cachedResult != null);
-
+
genCtx.commitArtifactsFromCache(logger);
genCtx.addGeneratedUnitsFromCache();
-
+
// use cached type name
resultTypeName = cachedResult.getReturnedTypeName();
break;
-
+
case USE_PARTIAL_CACHED:
/*
* Add cached generated units marked for reuse to the context.
@@ -203,7 +229,7 @@
* as GeneratedUnits.
*/
genCtx.addGeneratedUnitsMarkedForReuseFromCache();
-
+
/*
* Create a new cache entry using the composite set of new and
* reused cached results currently in genCtx.
@@ -267,14 +293,14 @@
public void setRebindCache(RebindCache cache) {
this.rebindCache = cache;
}
-
+
private CachedRebindResult rebindCacheGet(Rule rule, String typeName) {
if (rebindCache != null) {
return rebindCache.get(rule, typeName);
}
return null;
}
-
+
private void rebindCachePut(Rule rule, String typeName,
CachedRebindResult result) {
if (rebindCache != null) {
rebindCache.put(rule, typeName, result);
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/util/xml/HandlerArgs.java Wed
Dec 27 13:19:22 2006
+++ /trunk/dev/core/src/com/google/gwt/dev/util/xml/HandlerArgs.java Tue
Mar 8 09:11:26 2011
@@ -63,6 +63,8 @@
AttributeConverter converter =
schema.getAttributeConverter(handlerParams[i].getParamType());
return converter.convertToArg(schema, lineNumber, elemName,
attrNames[i],
value);
+ } else if (handlerParams[i].isOptional()) {
+ return null;
} else {
return new NullPointerException("Argument " + i + " was null");
}
@@ -77,7 +79,7 @@
}
public boolean isArgSet(int i) {
- if (argValues[i] != null) {
+ if (argValues[i] != null || handlerParams[i].isOptional()) {
return true;
} else {
return false;
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/util/xml/HandlerParam.java Fri
Mar 19 08:12:41 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/util/xml/HandlerParam.java Tue
Mar 8 09:11:26 2011
@@ -81,11 +81,17 @@
private final Class<?> paramType;
private final Field metaField;
+
+ private final boolean isOptional;
private final String normalizedAttrName;
private HandlerParam(Class<?> paramType, Field metaField,
String normalizedAttrName) {
+ this.isOptional = normalizedAttrName.endsWith("$");
+ if (isOptional) {
+ normalizedAttrName = normalizedAttrName.substring(0,
normalizedAttrName.length() - 1);
+ }
this.paramType = paramType;
this.metaField = metaField;
this.normalizedAttrName = normalizedAttrName;
@@ -116,4 +122,8 @@
public Class<?> getParamType() {
return paramType;
}
-}
+
+ public boolean isOptional() {
+ return isOptional;
+ }
+}
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/js/JsCoerceIntShiftTest.java
Tue Jun 22 11:13:30 2010
+++ /trunk/dev/core/test/com/google/gwt/dev/js/JsCoerceIntShiftTest.java
Tue Mar 8 09:11:26 2011
@@ -52,7 +52,8 @@
} else {
SortedSet<String> valueSet = new TreeSet<String>();
valueSet.add(value);
- return new DefaultSelectionProperty(value, value, value, valueSet);
+ return new DefaultSelectionProperty(value, value, value, valueSet,
+ null /* fallbackValueMap */);
}
}
=======================================
--- /trunk/user/src/com/google/gwt/user/UserAgent.gwt.xml Tue Feb 8
16:15:58 2011
+++ /trunk/user/src/com/google/gwt/user/UserAgent.gwt.xml Tue Mar 8
09:11:26 2011
@@ -19,8 +19,11 @@
<module>
<!-- Browser-sensitive code should use the 'user.agent' property -->
- <define-property name="user.agent"
values="ie6,ie8,gecko1_8,safari,opera"/>
-
+ <define-property name="user.agent" values="ie6" />
+ <extend-property name="user.agent" values="ie8" />
+ <extend-property name="user.agent" values="gecko1_8" />
+ <extend-property name="user.agent" values="safari" />
+ <extend-property name="user.agent" values="opera" />
<property-provider name="user.agent"
generator="com.google.gwt.user.rebind.UserAgentPropertyGenerator"/>
<!-- Set to false to avoid runtime warnings for mismatched runtime and
-->
=======================================
--- /trunk/user/src/com/google/gwt/user/rebind/UserAgentGenerator.java Tue
Feb 8 16:15:58 2011
+++ /trunk/user/src/com/google/gwt/user/rebind/UserAgentGenerator.java Tue
Mar 8 09:11:26 2011
@@ -80,10 +80,11 @@
}
String userAgentValue;
+ SelectionProperty selectionProperty;
try {
- SelectionProperty property =
propertyOracle.getSelectionProperty(logger,
+ selectionProperty = propertyOracle.getSelectionProperty(logger,
PROPERTY_USER_AGENT);
- userAgentValue = property.getCurrentValue();
+ userAgentValue = selectionProperty.getCurrentValue();
} catch (BadPropertyValueException e) {
logger.log(TreeLogger.ERROR, "Unable to find value for '"
+ PROPERTY_USER_AGENT + "'", e);
@@ -113,7 +114,8 @@
sw.println();
sw.println("public native String getRuntimeValue() /*-{");
sw.indent();
- UserAgentPropertyGenerator.writeUserAgentPropertyJavaScript(sw);
+ UserAgentPropertyGenerator.writeUserAgentPropertyJavaScript(sw,
+ selectionProperty.getPossibleValues());
sw.outdent();
sw.println("}-*/;");
sw.println();
=======================================
---
/trunk/user/src/com/google/gwt/user/rebind/UserAgentPropertyGenerator.java
Tue Feb 8 16:15:58 2011
+++
/trunk/user/src/com/google/gwt/user/rebind/UserAgentPropertyGenerator.java
Tue Mar 8 09:11:26 2011
@@ -39,6 +39,51 @@
private static final List<String> VALID_VALUES = Arrays.asList(new
String[]{
"ie6", "ie8", "gecko1_8", "safari", "opera"});
+ /**
+ * List of predicates to identify user agent.
+ * The order of evaluation is from top to bottom, i.e., the first
matching
+ * predicate will have the associated ua token returned.
+ * ua is defined in an outer scope and is therefore visible in
+ * the predicate javascript fragment.
+ */
+ private static UserAgentPropertyGeneratorPredicate[] predicates =
+ new UserAgentPropertyGeneratorPredicate[] {
+
+ // opera
+ new UserAgentPropertyGeneratorPredicate("opera")
+ .getPredicateBlock()
+ .println("return (ua.indexOf('opera') != -1);")
+ .returns("'opera'"),
+
+ // webkit family
+ new UserAgentPropertyGeneratorPredicate("safari")
+ .getPredicateBlock()
+ .println("return (ua.indexOf('webkit') != -1);")
+ .returns("'safari'"),
+
+ // IE8
+ new UserAgentPropertyGeneratorPredicate("ie8")
+ .getPredicateBlock()
+ .println("return (ua.indexOf('msie') != -1 && ($doc.documentMode
= 8));")
+ .returns("'ie8'"),
+
+ // IE6
+ new UserAgentPropertyGeneratorPredicate("ie6")
+ .getPredicateBlock()
+ .println("var result = /msie ([0-9]+)\\.([0-9]+)/.exec(ua);")
+ .println("if (result && result.length == 3)")
+ .indent()
+ .println("return (makeVersion(result) >= 6000);")
+ .outdent()
+ .returns("'ie6'"),
+
+ // gecko family
+ new UserAgentPropertyGeneratorPredicate("gecko1_8")
+ .getPredicateBlock()
+ .println("return (ua.indexOf('gecko') != -1);")
+ .returns("'gecko1_8'"),
+ };
+
/**
* Writes out the JavaScript function body for determining the value of
the
* <code>user.agent</code> selection property. This method is used to
create
@@ -47,48 +92,29 @@
* <code>user.agent</code> values listed here should be kept in sync with
* {@link #VALID_VALUES} and <code>UserAgent.gwt.xml</code>.
*/
- static void writeUserAgentPropertyJavaScript(SourceWriter body) {
+ static void writeUserAgentPropertyJavaScript(SourceWriter body,
+ SortedSet<String> possibleValues) {
+
+ // write preamble
body.println("var ua = navigator.userAgent.toLowerCase();");
body.println("var makeVersion = function(result) {");
body.indent();
body.println("return (parseInt(result[1]) * 1000) +
parseInt(result[2]);");
body.outdent();
body.println("};");
- body.println("if (ua.indexOf('opera') != -1) {");
- body.indent();
- body.println("return 'opera';");
- body.outdent();
- body.println("} else if (ua.indexOf('webkit') != -1) {");
- body.indent();
- body.println("return 'safari';");
- body.outdent();
- body.println("} else if (ua.indexOf('msie') != -1) {");
- body.indent();
- body.println("if ($doc.documentMode >= 8) {");
- body.indent();
- body.println("return 'ie8';");
- body.outdent();
- body.println("} else {");
- body.indent();
- body.println("var result = /msie ([0-9]+)\\.([0-9]+)/.exec(ua);");
- body.println("if (result && result.length == 3) {");
- body.indent();
- body.println("var v = makeVersion(result);");
- body.println("if (v >= 6000) {");
- body.indent();
- body.println("return 'ie6';");
- body.outdent();
- body.println("}");
- body.outdent();
- body.println("}");
- body.outdent();
- body.println("}");
- body.outdent();
- body.println("} else if (ua.indexOf('gecko') != -1) {");
- body.indent();
- body.println("return 'gecko1_8';");
- body.outdent();
- body.println("}");
+
+ // write only selected user agents
+ for (int i = 0; i < predicates.length; i++) {
+ if (possibleValues.contains(predicates[i].getUserAgent())) {
+ body.println("if ((function() { ");
+ body.indent();
+ body.print(predicates[i].toString());
+ body.outdent();
+ body.println("})()) return " + predicates[i].getReturnValue()
+ ";");
+ }
+ }
+
+ // default return
body.println("return 'unknown';");
}
@@ -105,11 +131,14 @@
+ "\" value=\"false\"/> to suppress this warning message.");
}
}
-
+ // make sure that the # of ua in VALID_VALUES
+ // is the same of predicates. maybe should iterate
+ // to make sure each one has a match.
+ assert predicates.length == VALID_VALUES.size();
StringSourceWriter body = new StringSourceWriter();
body.println("{");
body.indent();
- writeUserAgentPropertyJavaScript(body);
+ writeUserAgentPropertyJavaScript(body, possibleValues);
body.outdent();
body.println("}");
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors