Adding the 2.1.1-rc1 tag
git-svn-id: https://google-web-toolkit.googlecode.com/svn/tags/2.1.1-rc1@9368 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/eclipse/samples/Validation/.checkstyle b/eclipse/samples/Validation/.checkstyle
deleted file mode 100644
index 0f1cbd9..0000000
--- a/eclipse/samples/Validation/.checkstyle
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<fileset-config file-format-version="1.2.0" simple-config="true">
- <fileset name="all" enabled="true" check-config-name="GWT Checks" local="false">
- <file-match-pattern match-pattern="." include-pattern="true"/>
- </fileset>
- <filter name="NonSrcDirs" enabled="true"/>
-</fileset-config>
diff --git a/eclipse/samples/Validation/.classpath b/eclipse/samples/Validation/.classpath
deleted file mode 100644
index b67ec19..0000000
--- a/eclipse/samples/Validation/.classpath
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="core/src"/>
- <classpathentry kind="src" output="war" path="core/war"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry combineaccessrules="false" kind="src" path="/gwt-user"/>
- <classpathentry kind="var" path="GWT_TOOLS/lib/javax/validation/validation-api-1.0.0.GA-sources.jar"/>
- <classpathentry kind="var" path="GWT_TOOLS/lib/javax/validation/validation-api-1.0.0.GA.jar" sourcepath="/GWT_TOOLS/lib/javax/validation/validation-api-1.0.0.GA-sources.jar"/>
- <classpathentry kind="output" path="war/WEB-INF/classes"/>
-</classpath>
diff --git a/eclipse/samples/Validation/.project b/eclipse/samples/Validation/.project
deleted file mode 100644
index 93a5b2f..0000000
--- a/eclipse/samples/Validation/.project
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>Validation</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>com.atlassw.tools.eclipse.checkstyle.CheckstyleBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.jdt.core.javanature</nature>
- <nature>com.atlassw.tools.eclipse.checkstyle.CheckstyleNature</nature>
- </natures>
- <linkedResources>
- <link>
- <name>core</name>
- <type>2</type>
- <locationURI>GWT_ROOT/samples/validation</locationURI>
- </link>
- </linkedResources>
-</projectDescription>
diff --git a/eclipse/samples/Validation/Validation-gwtc.launch b/eclipse/samples/Validation/Validation-gwtc.launch
deleted file mode 100644
index c48be56..0000000
--- a/eclipse/samples/Validation/Validation-gwtc.launch
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
-<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER" javaProject="Validation" path="1" type="4"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/Validation/core/src" path="3" type="2"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/src" path="3" type="2"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/super" path="3" type="2"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-dev/core/super" path="3" type="2"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="Validation"/> </runtimeClasspathEntry> "/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.Compiler"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="com.google.gwt.sample.validation.Validation"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Validation"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xmx256M -Dgwt.devjar=${gwt_devjar}"/>
-</launchConfiguration>
diff --git a/eclipse/samples/Validation/Validation.launch b/eclipse/samples/Validation/Validation.launch
deleted file mode 100644
index 45c184b..0000000
--- a/eclipse/samples/Validation/Validation.launch
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
-<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
-<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER" javaProject="Validation" path="1" type="4"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/Validation/core/src" path="3" type="2"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/src" path="3" type="2"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/super" path="3" type="2"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/gwt-dev/core/super" path="3" type="2"/> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="Validation"/> </runtimeClasspathEntry> "/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.HostedMode"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-startupUrl Validation.html com.google.gwt.sample.validation.Validation"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Validation"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xmx256M -Dgwt.devjar=${gwt_devjar}"/>
-</launchConfiguration>
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/console/Console.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/console/Console.java
deleted file mode 100644
index 0db3125..0000000
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/console/Console.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2010 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.sample.dynatablerf.console;
-
-import com.google.gwt.event.shared.SimpleEventBus;
-import com.google.gwt.requestfactory.server.testing.RequestFactoryMagic;
-import com.google.gwt.requestfactory.shared.Receiver;
-import com.google.gwt.sample.dynatablerf.shared.AddressProxy;
-import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory;
-import com.google.gwt.sample.dynatablerf.shared.PersonProxy;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * A proof-of-concept to demonstrate how RequestFactory can be used from
- * non-client code.
- */
-public class Console {
- public static void main(String[] args) {
- String url = "http://localhost:8888/gwtRequest";
- if (args.length == 1) {
- url = args[0];
- }
- try {
- new Console(new URI(url)).exec();
- System.exit(0);
- } catch (URISyntaxException e) {
- System.err.println("Could not parse argument");
- }
- System.exit(1);
- }
-
- private final DynaTableRequestFactory rf;
-
- private Console(URI uri) {
- /*
- * Instantiation of the RequestFactory interface uses the
- * RequestFactoryMagic class instead of GWT.create().
- */
- this.rf = RequestFactoryMagic.create(DynaTableRequestFactory.class);
- // Initialization follows the same pattern as client code
- rf.initialize(new SimpleEventBus(), new HttpClientTransport(uri));
- }
-
- /**
- * Making a request from non-GWT code is similar. The implementation of the
- * demonstration HttpClientTransport issues the requests synchronously. A
- * different transport system might use asynchronous callbacks.
- */
- private void exec() {
- rf.schoolCalendarRequest().getPeople(0, 100,
- Arrays.asList(true, true, true, true, true, true, true)).with("address").fire(
- new Receiver<List<PersonProxy>>() {
- @Override
- public void onSuccess(List<PersonProxy> response) {
- // Print each record to the console
- for (PersonProxy person : response) {
- AddressProxy address = person.getAddress();
- String addressBlob = address.getStreet() + " "
- + address.getCity() + " " + address.getState() + " "
- + address.getZip();
- System.out.printf("%-40s%40s\n%80s\n\n", person.getName(),
- person.getDescription(), addressBlob);
- }
- }
- });
- }
-}
diff --git a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/console/HttpClientTransport.java b/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/console/HttpClientTransport.java
deleted file mode 100644
index 8b5b0c5..0000000
--- a/samples/dynatablerf/src/com/google/gwt/sample/dynatablerf/console/HttpClientTransport.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2010 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.sample.dynatablerf.console;
-
-import com.google.gwt.dev.util.Util;
-import com.google.gwt.requestfactory.shared.RequestTransport;
-
-import org.apache.http.HttpResponse;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.DefaultHttpClient;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-
-/**
- * This is a simple implementation of {@link RequestTransport} that uses
- * HttpClient. It is not suitable for production use, but demonstrates the
- * minimum functionality necessary to implement a custom RequestTransport.
- */
-class HttpClientTransport implements RequestTransport {
- private final URI uri;
-
- public HttpClientTransport(URI uri) {
- this.uri = uri;
- }
-
- public void send(String payload, TransportReceiver receiver) {
- HttpClient client = new DefaultHttpClient();
- HttpPost post = new HttpPost();
- post.setHeader("Content-Type", "application/json;charset=UTF-8");
- post.setURI(uri);
- Throwable ex;
- try {
- post.setEntity(new StringEntity(payload, "UTF-8"));
- HttpResponse response = client.execute(post);
- if (200 == response.getStatusLine().getStatusCode()) {
- String contents = Util.readStreamAsString(response.getEntity().getContent());
- receiver.onTransportSuccess(contents);
- } else {
- receiver.onTransportFailure(response.getStatusLine().getReasonPhrase());
- }
- return;
- } catch (UnsupportedEncodingException e) {
- ex = e;
- } catch (ClientProtocolException e) {
- ex = e;
- } catch (IOException e) {
- ex = e;
- }
- receiver.onTransportFailure(ex.getMessage());
- }
-}
\ No newline at end of file
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.java
index 455e0cf..d4c02c7 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportDetails.java
@@ -23,6 +23,7 @@
import com.google.gwt.cell.client.NumberCell;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.cell.client.ValueUpdater;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
@@ -46,7 +47,6 @@
import com.google.gwt.requestfactory.ui.client.EntityProxyKeyProvider;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
-import com.google.gwt.safehtml.client.SafeHtmlTemplates.Template;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
@@ -183,15 +183,16 @@
}
@Override
- public boolean isEditing(Element parent, String value, Object key) {
- return super.isEditing(parent, value, key) || denialPopup.isShowing();
+ public boolean isEditing(Context context, Element parent, String value) {
+ return super.isEditing(context, parent, value) || denialPopup.isShowing();
}
@Override
- public void onBrowserEvent(Element parent, String value, Object key,
+ public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
- super.onBrowserEvent(parent, value, key, event, valueUpdater);
+ super.onBrowserEvent(context, parent, value, event, valueUpdater);
+ Object key = context.getKey();
String type = event.getType();
ApprovalViewData viewData = getViewData(key);
if ("change".equals(type)) {
@@ -235,8 +236,9 @@
}
@Override
- public void render(String value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, String value, SafeHtmlBuilder sb) {
// Get the view data.
+ Object key = context.getKey();
ApprovalViewData viewData = getViewData(key);
if (viewData != null && viewData.getPendingApproval().equals(value)) {
clearViewData(key);
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.java
index bb40add..2df0dbf 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseReportList.java
@@ -163,7 +163,7 @@
private static final String replaceString = "<span style='color:red;font-weight:bold;'>$1</span>";
@Override
- public void render(String value, Object viewData, SafeHtmlBuilder sb) {
+ public void render(Context context, String value, SafeHtmlBuilder sb) {
if (value != null) {
if (searchRegExp != null) {
// The search regex has already been html-escaped
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseTree.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseTree.java
index 49d29be..db78b4d 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseTree.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/ExpenseTree.java
@@ -19,13 +19,13 @@
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.IconCellDecorator;
import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.requestfactory.shared.EntityProxyId;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.requestfactory.ui.client.EntityProxyKeyProvider;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
-import com.google.gwt.safehtml.client.SafeHtmlTemplates.Template;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.sample.expenses.client.style.Styles;
@@ -85,7 +85,7 @@
}
@Override
- public void render(EmployeeProxy value, Object viewData,
+ public void render(Context context, EmployeeProxy value,
SafeHtmlBuilder sb) {
if (value != null) {
StringBuilder classesBuilder = new StringBuilder(usernameStyle);
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileExpenseList.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileExpenseList.java
index df44ef9..db184f7 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileExpenseList.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileExpenseList.java
@@ -81,7 +81,7 @@
}
@Override
- public void render(ExpenseProxy value, Object viewData, SafeHtmlBuilder sb) {
+ public void render(Context context, ExpenseProxy value, SafeHtmlBuilder sb) {
String approval = value.getApproval();
SafeHtml approvalIcon;
if (approvedText.equals(approval)) {
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileReportList.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileReportList.java
index 4ef274c..80466d8 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileReportList.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/MobileReportList.java
@@ -76,8 +76,7 @@
reportList = new CellList<ReportProxy>(new AbstractCell<ReportProxy>() {
@Override
- public void render(
- ReportProxy value, Object viewData, SafeHtmlBuilder sb) {
+ public void render(Context context, ReportProxy value, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<div class='item'>");
sb.appendEscaped(value.getPurpose());
sb.appendHtmlConstant("</div>");
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/SortableHeader.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/SortableHeader.java
index 5df24a5..3ab78bf 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/SortableHeader.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/client/SortableHeader.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.sample.expenses.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.cell.client.ClickableTextCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
@@ -89,7 +90,7 @@
}
@Override
- public void render(SafeHtmlBuilder sb) {
+ public void render(Context context, SafeHtmlBuilder sb) {
if (sorted) {
sb.append(template.sorted(IMAGE_WIDTH, reverseSort ? DOWN_ARROW : UP_ARROW, text));
} else {
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/server/domain/Report.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/server/domain/Report.java
index 2975080..96954de 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/server/domain/Report.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/server/domain/Report.java
@@ -17,11 +17,6 @@
import com.google.appengine.api.datastore.Cursor;
-import net.sf.jsr107cache.Cache;
-import net.sf.jsr107cache.CacheException;
-import net.sf.jsr107cache.CacheFactory;
-import net.sf.jsr107cache.CacheManager;
-
import org.datanucleus.store.appengine.query.JPACursorHelper;
import java.util.Collections;
@@ -29,6 +24,10 @@
import java.util.List;
import java.util.logging.Logger;
+import javax.cache.Cache;
+import javax.cache.CacheException;
+import javax.cache.CacheFactory;
+import javax.cache.CacheManager;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
diff --git a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/server/domain/ReportBack.java b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/server/domain/ReportBack.java
index 88f90c7..791c63d 100644
--- a/samples/expenses/src/main/java/com/google/gwt/sample/expenses/server/domain/ReportBack.java
+++ b/samples/expenses/src/main/java/com/google/gwt/sample/expenses/server/domain/ReportBack.java
@@ -17,11 +17,6 @@
import com.google.appengine.api.datastore.Cursor;
-import net.sf.jsr107cache.Cache;
-import net.sf.jsr107cache.CacheException;
-import net.sf.jsr107cache.CacheFactory;
-import net.sf.jsr107cache.CacheManager;
-
import org.datanucleus.store.appengine.query.JPACursorHelper;
import java.util.Collections;
@@ -29,6 +24,10 @@
import java.util.List;
import java.util.logging.Logger;
+import javax.cache.Cache;
+import javax.cache.CacheException;
+import javax.cache.CacheFactory;
+import javax.cache.CacheManager;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/MainMenuTreeViewModel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/MainMenuTreeViewModel.java
index 3c47105..f5f16fc 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/MainMenuTreeViewModel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/MainMenuTreeViewModel.java
@@ -109,7 +109,7 @@
*/
private static class CategoryCell extends AbstractCell<Category> {
@Override
- public void render(Category value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Category value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.getName());
}
@@ -121,7 +121,8 @@
*/
private static class ContentWidgetCell extends AbstractCell<ContentWidget> {
@Override
- public void render(ContentWidget value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, ContentWidget value,
+ SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.getName());
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/ContactTreeViewModel.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/ContactTreeViewModel.java
index 3a2248d..b18ff11 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/ContactTreeViewModel.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/ContactTreeViewModel.java
@@ -69,7 +69,7 @@
}
@Override
- public void render(Category value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Category value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendHtmlConstant(imageHtml).appendEscaped(" ");
sb.appendEscaped(value.getDisplayName());
@@ -126,7 +126,7 @@
private static class LetterCountCell extends AbstractCell<LetterCount> {
@Override
- public void render(LetterCount value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, LetterCount value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.firstLetter + " (" + value.count + ")");
}
@@ -193,9 +193,9 @@
});
contactCell = new CompositeCell<ContactInfo>(hasCells) {
@Override
- public void render(ContactInfo value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, ContactInfo value, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<table><tbody><tr>");
- super.render(value, key, sb);
+ super.render(context, value, sb);
sb.appendHtmlConstant("</tr></tbody></table>");
}
@@ -206,11 +206,11 @@
}
@Override
- protected <X> void render(ContactInfo value, Object key,
+ protected <X> void render(Context context, ContactInfo value,
SafeHtmlBuilder sb, HasCell<ContactInfo, X> hasCell) {
Cell<X> cell = hasCell.getCell();
sb.appendHtmlConstant("<td>");
- cell.render(hasCell.getValue(value), key, sb);
+ cell.render(context, hasCell.getValue(value), sb);
sb.appendHtmlConstant("</td>");
}
};
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellList.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellList.java
index 956e31d..4e55af7 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellList.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellList.java
@@ -90,7 +90,7 @@
}
@Override
- public void render(ContactInfo value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, ContactInfo value, SafeHtmlBuilder sb) {
// Value can be null, so do a null check..
if (value == null) {
return;
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellValidation.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellValidation.java
index 97c9be7..bd4c872 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellValidation.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellValidation.java
@@ -85,9 +85,9 @@
}
@Override
- public void onBrowserEvent(Element parent, String value, Object key,
+ public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
- super.onBrowserEvent(parent, value, key, event, valueUpdater);
+ super.onBrowserEvent(context, parent, value, event, valueUpdater);
// Ignore events that don't target the input.
Element target = event.getEventTarget().cast();
@@ -95,6 +95,7 @@
return;
}
+ Object key = context.getKey();
ValidationData viewData = getViewData(key);
String eventType = event.getType();
if ("change".equals(eventType)) {
@@ -120,8 +121,9 @@
}
@Override
- public void render(String value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, String value, SafeHtmlBuilder sb) {
// Get the view data.
+ Object key = context.getKey();
ValidationData viewData = getViewData(key);
if (viewData != null && viewData.getValue().equals(value)) {
// Clear the view data if the value is the same as the current value.
@@ -148,13 +150,13 @@
}
@Override
- protected void onEnterKeyDown(Element parent, String value, Object key,
+ protected void onEnterKeyDown(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
Element target = event.getEventTarget().cast();
if (getInputElement(parent).isOrHasChild(target)) {
- finishEditing(parent, value, key, valueUpdater);
+ finishEditing(parent, value, context.getKey(), valueUpdater);
} else {
- super.onEnterKeyDown(parent, value, key, event, valueUpdater);
+ super.onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
}
diff --git a/samples/validation/build.xml b/samples/validation/build.xml
deleted file mode 100755
index 844f146..0000000
--- a/samples/validation/build.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<project name="validation" default="build" basedir=".">
- <property name="sample.root" value="validation" />
- <property name="sample.module" value="Validation" />
- <property name="sample.path" value="src" />
- <import file="../common.ant.xml" />
-
- <!-- these are after the common.ant.xml so they have gwt.tools etc. -->
- <path id="sample.extraclasspath">
- <pathelement location="${gwt.tools.lib}/apache/log4j/log4j-1.2.16.jar" />
- <pathelement location="${gwt.tools.lib}/javax/validation/validation-api-1.0.0.GA.jar" />
- <pathelement location="${gwt.tools.lib}/javax/validation/validation-api-1.0.0.GA-sources.jar" />
- <pathelement location="${gwt.tools.lib}/hibernate/validator/hibernate-validator-4.1.0.Final.jar" />
- <pathelement location="${gwt.tools.lib}/hibernate/validator/hibernate-validator-4.1.0.Final-sources.jar" />
- <pathelement location="${gwt.tools.lib}/slf4j/slf4j-api/slf4j-api-1.6.1.jar" />
- <pathelement location="${gwt.tools.lib}/slf4j/slf4j-log4j12/slf4j-log4j12-1.6.1.jar" />
- <!-- Needed for JDK 1.5-->
- <pathelement location="${gwt.tools.lib}/javax/activation/activation-1.1.jar" />
- <pathelement location="${gwt.tools.lib}/javax/xml/bind/jaxb-api-2.1.jar" />
- <pathelement location="${gwt.tools.lib}/sun/jaxb/jaxb-impl-2.1.3.jar" />
- <pathelement location="${gwt.tools.lib}/javax/xml/stream/stax-api-1.0-2.jar" />
- </path>
- <fileset id="sample.server.libs" dir="${gwt.tools.lib}">
- <include name="javax/validation/validation-api-1.0.0.GA-sources.jar" />
- <include name="hibernate/validator/hibernate-validator-4.1.0.Final.jar" />
- <include name="hibernate/validator/hibernate-validator-4.1.0.Final-sources.jar" />
- <include name="apache/log4j/log4j-1.2.16.jar" />
- <include name="slf4j/slf4j-api/slf4j-api-1.6.1.jar" />
- <include name="slf4j/slf4j-log4j12/slf4j-log4j12-1.6.1.jar" />
- </fileset>
-</project>
diff --git a/tools/api-checker/config/gwt20_21userApi.conf b/tools/api-checker/config/gwt20_21userApi.conf
index 697b3cc..54313db 100644
--- a/tools/api-checker/config/gwt20_21userApi.conf
+++ b/tools/api-checker/config/gwt20_21userApi.conf
@@ -66,6 +66,7 @@
:**/server/**\
:**/tools/**\
:user/src/com/google/gwt/regexp/shared/**\
+:user/src/com/google/gwt/autobean/shared/ValueCodexHelper.java\
:user/src/com/google/gwt/autobean/shared/impl/StringQuoter.java\
:user/src/com/google/gwt/core/client/impl/WeakMapping.java\
:user/src/com/google/gwt/junit/*.java\
diff --git a/tools/api-checker/config/gwt21_22userApi.conf b/tools/api-checker/config/gwt21_22userApi.conf
index 405ee8d..3e4f820 100644
--- a/tools/api-checker/config/gwt21_22userApi.conf
+++ b/tools/api-checker/config/gwt21_22userApi.conf
@@ -73,6 +73,7 @@
:**/server/**\
:**/tools/**\
:user/src/com/google/gwt/regexp/shared/**\
+:user/src/com/google/gwt/autobean/shared/ValueCodexHelper.java\
:user/src/com/google/gwt/autobean/shared/impl/StringQuoter.java\
:user/src/com/google/gwt/core/client/impl/WeakMapping.java\
:user/src/com/google/gwt/junit/*.java\
@@ -143,3 +144,124 @@
com.google.gwt.user.cellview.client.Column::cell MISSING
com.google.gwt.user.cellview.client.Column::fieldUpdater MISSING
+# Passing a Context to Cell methods instead of passing a bunch of different args.
+com.google.gwt.cell.client.AbstractCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.AbstractCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.AbstractCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.AbstractCell::render(Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.AbstractCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.AbstractCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.AbstractEditableCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.AbstractInputCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.AbstractInputCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.AbstractInputCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.AbstractInputCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.AbstractSafeHtmlCell::render(Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.AbstractSafeHtmlCell::render(Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ActionCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ActionCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ActionCell::render(Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ButtonCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ButtonCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ButtonCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ButtonCell::render(Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ButtonCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ButtonCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ButtonCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.CheckboxCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/Boolean;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.CheckboxCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Boolean;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.CheckboxCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/Boolean;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.CheckboxCell::render(Ljava/lang/Boolean;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.CheckboxCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/Boolean;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.CheckboxCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/Boolean;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::render(Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ClickableTextCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.CompositeCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.CompositeCell::render(Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.CompositeCell::render(Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;Lcom/google/gwt/cell/client/HasCell;) MISSING
+com.google.gwt.cell.client.CompositeCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.CompositeCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.DateCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.DateCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.DateCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.DateCell::render(Ljava/util/Date;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.DateCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.DateCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.DatePickerCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.DatePickerCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.DatePickerCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.DatePickerCell::render(Ljava/util/Date;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.DatePickerCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.DatePickerCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/util/Date;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.EditTextCell::edit(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.EditTextCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.EditTextCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.EditTextCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.EditTextCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.EditTextCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.EditTextCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.IconCellDecorator::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.IconCellDecorator::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.IconCellDecorator::render(Ljava/lang/Object;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.IconCellDecorator::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.IconCellDecorator::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ImageCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ImageCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ImageCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageLoadingCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageLoadingCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ImageLoadingCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ImageLoadingCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ImageLoadingCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageLoadingCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageResourceCell::isEditing(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/resources/client/ImageResource;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageResourceCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/resources/client/ImageResource;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ImageResourceCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/resources/client/ImageResource;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.ImageResourceCell::render(Lcom/google/gwt/resources/client/ImageResource;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.ImageResourceCell::resetFocus(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/resources/client/ImageResource;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.ImageResourceCell::setValue(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/resources/client/ImageResource;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.NumberCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/Number;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.NumberCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/Number;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.NumberCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/Number;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.NumberCell::render(Ljava/lang/Number;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.NumberCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/Number;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.NumberCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/Number;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.SafeHtmlCell::isEditing(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.SafeHtmlCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.SafeHtmlCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.SafeHtmlCell::render(Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.SafeHtmlCell::resetFocus(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.SafeHtmlCell::setValue(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.SelectionCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.SelectionCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.SelectionCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.SelectionCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.SelectionCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.SelectionCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.TextCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.TextCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.TextCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.TextCell::render(Lcom/google/gwt/safehtml/shared/SafeHtml;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.TextCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.TextCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.TextCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.TextInputCell::isEditing(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.TextInputCell::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.TextInputCell::onEnterKeyDown(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/cell/client/ValueUpdater;) MISSING
+com.google.gwt.cell.client.TextInputCell::render(Ljava/lang/String;Ljava/lang/Object;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.cell.client.TextInputCell::resetFocus(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.cell.client.TextInputCell::setValue(Lcom/google/gwt/dom/client/Element;Ljava/lang/String;Ljava/lang/Object;) MISSING
+com.google.gwt.user.cellview.client.CellList::fireEventToCell(Lcom/google/gwt/user/client/Event;Lcom/google/gwt/dom/client/Element;Ljava/lang/Object;) MISSING
+com.google.gwt.user.cellview.client.Column::render(Ljava/lang/Object;Lcom/google/gwt/view/client/ProvidesKey;Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+com.google.gwt.user.cellview.client.Column::onBrowserEvent(Lcom/google/gwt/dom/client/Element;ILjava/lang/Object;Lcom/google/gwt/dom/client/NativeEvent;Lcom/google/gwt/view/client/ProvidesKey;) MISSING
+com.google.gwt.user.cellview.client.Header::onBrowserEvent(Lcom/google/gwt/dom/client/Element;Lcom/google/gwt/dom/client/NativeEvent;) MISSING
+com.google.gwt.user.cellview.client.Header::render(Lcom/google/gwt/safehtml/shared/SafeHtmlBuilder;) MISSING
+
diff --git a/user/javadoc/com/google/gwt/examples/cell/CellExample.java b/user/javadoc/com/google/gwt/examples/cell/CellExample.java
index 2c8317c..524889d 100644
--- a/user/javadoc/com/google/gwt/examples/cell/CellExample.java
+++ b/user/javadoc/com/google/gwt/examples/cell/CellExample.java
@@ -39,7 +39,7 @@
private static class ColorCell extends AbstractCell<String> {
@Override
- public void render(String value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, String value, SafeHtmlBuilder sb) {
/*
* Always do a null check on the value. Cell widgets can pass null to
* cells if the underlying data contains a null, or if the data arrives
diff --git a/user/javadoc/com/google/gwt/examples/cell/EditableCellExample.java b/user/javadoc/com/google/gwt/examples/cell/EditableCellExample.java
index 024a01b..73aacf2 100644
--- a/user/javadoc/com/google/gwt/examples/cell/EditableCellExample.java
+++ b/user/javadoc/com/google/gwt/examples/cell/EditableCellExample.java
@@ -67,7 +67,7 @@
}
@Override
- public void onBrowserEvent(Element parent, Contact value, Object key,
+ public void onBrowserEvent(Context context, Element parent, Contact value,
NativeEvent event, ValueUpdater<Contact> valueUpdater) {
// Check that the value is not null.
if (value == null) {
@@ -75,7 +75,7 @@
}
// Call the super handler, which handlers the enter key.
- super.onBrowserEvent(parent, value, key, event, valueUpdater);
+ super.onBrowserEvent(context, parent, value, event, valueUpdater);
// Handle click events.
if ("change".equals(event.getType())) {
@@ -85,7 +85,7 @@
}
@Override
- public void render(Contact value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Contact value, SafeHtmlBuilder sb) {
/*
* Always do a null check on the value. Cell widgets can pass null to
* cells if the underlying data contains a null, or if the data arrives
@@ -123,8 +123,8 @@
* navigation in the widget. Our cell will toggle the checkbox on Enter.
*/
@Override
- protected void onEnterKeyDown(Element parent, Contact value, Object key,
- NativeEvent event, ValueUpdater<Contact> valueUpdater) {
+ protected void onEnterKeyDown(Context context, Element parent,
+ Contact value, NativeEvent event, ValueUpdater<Contact> valueUpdater) {
// Toggle the checkbox.
InputElement input = getInputElement(parent);
input.setChecked(!input.isChecked());
diff --git a/user/javadoc/com/google/gwt/examples/cell/InteractionCellExample.java b/user/javadoc/com/google/gwt/examples/cell/InteractionCellExample.java
index ceaa7a3..70c7001 100644
--- a/user/javadoc/com/google/gwt/examples/cell/InteractionCellExample.java
+++ b/user/javadoc/com/google/gwt/examples/cell/InteractionCellExample.java
@@ -78,7 +78,7 @@
}
@Override
- public void onBrowserEvent(Element parent, Contact value, Object key,
+ public void onBrowserEvent(Context context, Element parent, Contact value,
NativeEvent event, ValueUpdater<Contact> valueUpdater) {
// Check that the value is not null.
if (value == null) {
@@ -86,16 +86,16 @@
}
// Call the super handler, which handlers the enter key.
- super.onBrowserEvent(parent, value, key, event, valueUpdater);
+ super.onBrowserEvent(context, parent, value, event, valueUpdater);
// On click, perform the same action that we perform on enter.
if ("click".equals(event.getType())) {
- this.onEnterKeyDown(parent, value, key, event, valueUpdater);
+ this.onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
@Override
- public void render(Contact value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Contact value, SafeHtmlBuilder sb) {
/*
* Always do a null check on the value. Cell widgets can pass null to
* cells if the underlying data contains a null, or if the data arrives
@@ -128,8 +128,8 @@
* navigation in the widget.
*/
@Override
- protected void onEnterKeyDown(Element parent, Contact value, Object key,
- NativeEvent event, ValueUpdater<Contact> valueUpdater) {
+ protected void onEnterKeyDown(Context context, Element parent,
+ Contact value, NativeEvent event, ValueUpdater<Contact> valueUpdater) {
Window.alert("You clicked " + value.name);
}
}
diff --git a/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample2.java b/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample2.java
index 013db42..5aa5173 100644
--- a/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample2.java
+++ b/user/javadoc/com/google/gwt/examples/cellview/CellBrowserExample2.java
@@ -209,7 +209,7 @@
// Create a cell to display a composer.
Cell<Composer> cell = new AbstractCell<Composer>() {
@Override
- public void render(Composer value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Composer value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.getName());
}
@@ -225,7 +225,7 @@
((Composer) value).getPlaylists());
Cell<Playlist> cell = new AbstractCell<Playlist>() {
@Override
- public void render(Playlist value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Playlist value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.getName());
}
diff --git a/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample2.java b/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample2.java
index 6c713f8..6825e76 100644
--- a/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample2.java
+++ b/user/javadoc/com/google/gwt/examples/cellview/CellTreeExample2.java
@@ -210,7 +210,7 @@
// Create a cell to display a composer.
Cell<Composer> cell = new AbstractCell<Composer>() {
@Override
- public void render(Composer value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Composer value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.getName());
}
@@ -226,7 +226,7 @@
((Composer) value).getPlaylists());
Cell<Playlist> cell = new AbstractCell<Playlist>() {
@Override
- public void render(Playlist value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Playlist value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.getName());
}
diff --git a/user/javadoc/com/google/gwt/examples/view/KeyProviderExample.java b/user/javadoc/com/google/gwt/examples/view/KeyProviderExample.java
index f3cfc89..434019e 100644
--- a/user/javadoc/com/google/gwt/examples/view/KeyProviderExample.java
+++ b/user/javadoc/com/google/gwt/examples/view/KeyProviderExample.java
@@ -54,7 +54,7 @@
*/
private static class ContactCell extends AbstractCell<Contact> {
@Override
- public void render(Contact value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Contact value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.name);
}
diff --git a/user/src/com/google/gwt/autobean/server/MethodPropertyContext.java b/user/src/com/google/gwt/autobean/server/MethodPropertyContext.java
index ac2653b..315e185 100644
--- a/user/src/com/google/gwt/autobean/server/MethodPropertyContext.java
+++ b/user/src/com/google/gwt/autobean/server/MethodPropertyContext.java
@@ -23,6 +23,7 @@
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;
+import java.util.WeakHashMap;
/**
* A base type to handle analyzing the return value of a getter method. The
@@ -30,47 +31,61 @@
*/
abstract class MethodPropertyContext implements CollectionPropertyContext,
MapPropertyContext {
- private final Class<?> keyType;
- private final Class<?> valueType;
- private final Class<?> elementType;
- private final Class<?> type;
+ private static class Data {
+ Class<?> keyType;
+ Class<?> valueType;
+ Class<?> elementType;
+ Class<?> type;
+ }
+
+ /**
+ * Save prior instances in order to decrease the amount of data computed.
+ */
+ private static final Map<Method, Data> cache = new WeakHashMap<Method, Data>();
+
+ private final Data data;
public MethodPropertyContext(Method getter) {
- this.type = getter.getReturnType();
+ synchronized (cache) {
+ Data previous = cache.get(getter);
+ if (previous != null) {
+ this.data = previous;
+ return;
+ }
- // Compute collection element type
- if (Collection.class.isAssignableFrom(getType())) {
- elementType = TypeUtils.ensureBaseType(TypeUtils.getSingleParameterization(
- Collection.class, getter.getGenericReturnType(),
- getter.getReturnType()));
- keyType = valueType = null;
- } else if (Map.class.isAssignableFrom(getType())) {
- Type[] types = TypeUtils.getParameterization(Map.class,
- getter.getGenericReturnType());
- keyType = TypeUtils.ensureBaseType(types[0]);
- valueType = TypeUtils.ensureBaseType(types[1]);
- elementType = null;
- } else {
- elementType = keyType = valueType = null;
+ this.data = new Data();
+ data.type = getter.getReturnType();
+ // Compute collection element type
+ if (Collection.class.isAssignableFrom(getType())) {
+ data.elementType = TypeUtils.ensureBaseType(TypeUtils.getSingleParameterization(
+ Collection.class, getter.getGenericReturnType(),
+ getter.getReturnType()));
+ } else if (Map.class.isAssignableFrom(getType())) {
+ Type[] types = TypeUtils.getParameterization(Map.class,
+ getter.getGenericReturnType());
+ data.keyType = TypeUtils.ensureBaseType(types[0]);
+ data.valueType = TypeUtils.ensureBaseType(types[1]);
+ }
+ cache.put(getter, data);
}
}
public abstract boolean canSet();
public Class<?> getElementType() {
- return elementType;
+ return data.elementType;
}
public Class<?> getKeyType() {
- return keyType;
+ return data.keyType;
}
public Class<?> getType() {
- return type;
+ return data.type;
}
public Class<?> getValueType() {
- return valueType;
+ return data.valueType;
}
public abstract void set(Object value);
diff --git a/user/src/com/google/gwt/autobean/server/ProxyAutoBean.java b/user/src/com/google/gwt/autobean/server/ProxyAutoBean.java
index 7c4772d..0992adc 100644
--- a/user/src/com/google/gwt/autobean/server/ProxyAutoBean.java
+++ b/user/src/com/google/gwt/autobean/server/ProxyAutoBean.java
@@ -28,9 +28,10 @@
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.WeakHashMap;
/**
* An implementation of an AutoBean that uses reflection.
@@ -38,9 +39,60 @@
* @param <T> the type of interface being wrapped
*/
class ProxyAutoBean<T> extends AbstractAutoBean<T> {
+ private static class Data {
+ final List<Method> getters = new ArrayList<Method>();
+ final List<String> getterNames = new ArrayList<String>();
+ final List<PropertyType> propertyType = new ArrayList<PropertyType>();
+ }
+
+ private enum PropertyType {
+ VALUE, REFERENCE, COLLECTION, MAP;
+ }
+
+ private static final Map<Class<?>, Data> cache = new WeakHashMap<Class<?>, Data>();
+
+ private static Data calculateData(Class<?> beanType) {
+ Data toReturn;
+ synchronized (cache) {
+ toReturn = cache.get(beanType);
+ if (toReturn == null) {
+ toReturn = new Data();
+ for (Method method : beanType.getMethods()) {
+ if (BeanMethod.GET.matches(method)) {
+ toReturn.getters.add(method);
+
+ String name;
+ PropertyName annotation = method.getAnnotation(PropertyName.class);
+ if (annotation != null) {
+ name = annotation.value();
+ } else {
+ name = method.getName();
+ name = Character.toLowerCase(name.charAt(3))
+ + (name.length() >= 5 ? name.substring(4) : "");
+ }
+ toReturn.getterNames.add(name);
+
+ Class<?> returnType = method.getReturnType();
+ if (TypeUtils.isValueType(returnType)) {
+ toReturn.propertyType.add(PropertyType.VALUE);
+ } else if (Collection.class.isAssignableFrom(returnType)) {
+ toReturn.propertyType.add(PropertyType.COLLECTION);
+ } else if (Map.class.isAssignableFrom(returnType)) {
+ toReturn.propertyType.add(PropertyType.MAP);
+ } else {
+ toReturn.propertyType.add(PropertyType.REFERENCE);
+ }
+ }
+ }
+ cache.put(beanType, toReturn);
+ }
+ }
+ return toReturn;
+ }
+
private final Class<T> beanType;
private final Configuration configuration;
- private final List<Method> getters;
+ private final Data data;
private final T shim;
// These constructors mirror the generated constructors.
@@ -50,7 +102,7 @@
super(factory);
this.beanType = (Class<T>) beanType;
this.configuration = configuration;
- this.getters = calculateGetters();
+ this.data = calculateData(beanType);
this.shim = createShim();
}
@@ -63,7 +115,7 @@
}
this.beanType = (Class<T>) beanType;
this.configuration = configuration;
- this.getters = calculateGetters();
+ this.data = calculateData(beanType);
this.shim = createShim();
}
@@ -71,7 +123,7 @@
super(toClone, deep);
this.beanType = toClone.beanType;
this.configuration = toClone.configuration;
- this.getters = toClone.getters;
+ this.data = toClone.data;
this.shim = createShim();
}
@@ -156,16 +208,15 @@
// TODO: Port to model-based when class-based TypeOracle is available.
@Override
protected void traverseProperties(AutoBeanVisitor visitor, OneShotContext ctx) {
- for (final Method getter : getters) {
- String name;
- PropertyName annotation = getter.getAnnotation(PropertyName.class);
- if (annotation != null) {
- name = annotation.value();
- } else {
- name = getter.getName();
- name = Character.toLowerCase(name.charAt(3))
- + (name.length() >= 5 ? name.substring(4) : "");
- }
+ assert data.getters.size() == data.getterNames.size()
+ && data.getters.size() == data.propertyType.size();
+ Iterator<Method> getterIt = data.getters.iterator();
+ Iterator<String> nameIt = data.getterNames.iterator();
+ Iterator<PropertyType> typeIt = data.propertyType.iterator();
+ while (getterIt.hasNext()) {
+ Method getter = getterIt.next();
+ String name = nameIt.next();
+ PropertyType propertyType = typeIt.next();
// Use the shim to handle automatic wrapping
Object value;
@@ -184,42 +235,51 @@
MethodPropertyContext x = isUsingSimplePeer() ? new BeanPropertyContext(
this, getter) : new GetterPropertyContext(this, getter);
- if (TypeUtils.isValueType(x.getType())) {
- if (visitor.visitValueProperty(name, value, x)) {
- }
- visitor.endVisitValueProperty(name, value, x);
- } else if (Collection.class.isAssignableFrom(x.getType())) {
- // Workaround for generics bug in mac javac 1.6.0_22
- @SuppressWarnings("rawtypes")
- AutoBean temp = AutoBeanUtils.getAutoBean((Collection) value);
- @SuppressWarnings("unchecked")
- AutoBean<Collection<?>> bean = (AutoBean<Collection<?>>) temp;
- if (visitor.visitCollectionProperty(name, bean, x)) {
- if (value != null) {
- ((ProxyAutoBean<?>) bean).traverse(visitor, ctx);
+ switch (propertyType) {
+ case VALUE: {
+ if (visitor.visitValueProperty(name, value, x)) {
}
+ visitor.endVisitValueProperty(name, value, x);
+ break;
}
- visitor.endVisitCollectionProperty(name, bean, x);
- } else if (Map.class.isAssignableFrom(x.getType())) {
- // Workaround for generics bug in mac javac 1.6.0_22
- @SuppressWarnings("rawtypes")
- AutoBean temp = AutoBeanUtils.getAutoBean((Map) value);
- @SuppressWarnings("unchecked")
- AutoBean<Map<?, ?>> bean = (AutoBean<Map<?, ?>>) temp;
- if (visitor.visitMapProperty(name, bean, x)) {
- if (value != null) {
- ((ProxyAutoBean<?>) bean).traverse(visitor, ctx);
+ case COLLECTION: {
+ // Workaround for generics bug in mac javac 1.6.0_22
+ @SuppressWarnings("rawtypes")
+ AutoBean temp = AutoBeanUtils.getAutoBean((Collection) value);
+ @SuppressWarnings("unchecked")
+ AutoBean<Collection<?>> bean = (AutoBean<Collection<?>>) temp;
+ if (visitor.visitCollectionProperty(name, bean, x)) {
+ if (value != null) {
+ ((ProxyAutoBean<?>) bean).traverse(visitor, ctx);
+ }
}
+ visitor.endVisitCollectionProperty(name, bean, x);
+ break;
}
- visitor.endVisitMapProperty(name, bean, x);
- } else {
- ProxyAutoBean<?> bean = (ProxyAutoBean<?>) AutoBeanUtils.getAutoBean(value);
- if (visitor.visitReferenceProperty(name, bean, x)) {
- if (value != null) {
- bean.traverse(visitor, ctx);
+ case MAP: {
+ // Workaround for generics bug in mac javac 1.6.0_22
+ @SuppressWarnings("rawtypes")
+ AutoBean temp = AutoBeanUtils.getAutoBean((Map) value);
+ @SuppressWarnings("unchecked")
+ AutoBean<Map<?, ?>> bean = (AutoBean<Map<?, ?>>) temp;
+ if (visitor.visitMapProperty(name, bean, x)) {
+ if (value != null) {
+ ((ProxyAutoBean<?>) bean).traverse(visitor, ctx);
+ }
}
+ visitor.endVisitMapProperty(name, bean, x);
+ break;
}
- visitor.endVisitReferenceProperty(name, bean, x);
+ case REFERENCE: {
+ ProxyAutoBean<?> bean = (ProxyAutoBean<?>) AutoBeanUtils.getAutoBean(value);
+ if (visitor.visitReferenceProperty(name, bean, x)) {
+ if (value != null) {
+ bean.traverse(visitor, ctx);
+ }
+ }
+ visitor.endVisitReferenceProperty(name, bean, x);
+ break;
+ }
}
}
}
@@ -232,16 +292,6 @@
return values;
}
- private List<Method> calculateGetters() {
- List<Method> toReturn = new ArrayList<Method>();
- for (Method method : beanType.getMethods()) {
- if (BeanMethod.GET.matches(method)) {
- toReturn.add(method);
- }
- }
- return Collections.unmodifiableList(toReturn);
- }
-
private T createShim() {
T toReturn = AutoBeanFactoryMagic.makeProxy(beanType, new ShimHandler<T>(
this, getWrapped()));
diff --git a/user/src/com/google/gwt/autobean/shared/AutoBeanCodex.java b/user/src/com/google/gwt/autobean/shared/AutoBeanCodex.java
index 9d228f4..2ae2f0e 100644
--- a/user/src/com/google/gwt/autobean/shared/AutoBeanCodex.java
+++ b/user/src/com/google/gwt/autobean/shared/AutoBeanCodex.java
@@ -295,7 +295,8 @@
if (ValueCodex.canDecode(ctx.getElementType())) {
for (Object element : collection) {
- sb.append(",").append(encodeValue(element).getPayload());
+ sb.append(",").append(
+ encodeValue(ctx.getElementType(), element).getPayload());
}
} else {
boolean isEncoded = Splittable.class.equals(ctx.getElementType());
@@ -330,15 +331,18 @@
return false;
}
- boolean isEncodedKey = Splittable.class.equals(ctx.getKeyType());
- boolean isEncodedValue = Splittable.class.equals(ctx.getValueType());
- boolean isValueKey = ValueCodex.canDecode(ctx.getKeyType());
- boolean isValueValue = ValueCodex.canDecode(ctx.getValueType());
+ Class<?> keyType = ctx.getKeyType();
+ Class<?> valueType = ctx.getValueType();
+ boolean isEncodedKey = Splittable.class.equals(keyType);
+ boolean isEncodedValue = Splittable.class.equals(valueType);
+ boolean isValueKey = ValueCodex.canDecode(keyType);
+ boolean isValueValue = ValueCodex.canDecode(valueType);
if (isValueKey) {
- writeValueKeyMap(map, isEncodedValue, isValueValue);
+ writeValueKeyMap(map, keyType, valueType, isEncodedValue, isValueValue);
} else {
- writeObjectKeyMap(map, isEncodedKey, isEncodedValue, isValueValue);
+ writeObjectKeyMap(map, valueType, isEncodedKey, isEncodedValue,
+ isValueValue);
}
return false;
@@ -377,7 +381,7 @@
// Special handling for enums if we have an obfuscation map
Splittable split;
- split = encodeValue(value);
+ split = encodeValue(type, value);
sb.append(",\"").append(propertyName).append("\":").append(
split.getPayload());
return false;
@@ -409,12 +413,13 @@
* Encodes a value, with special handling for enums to allow the field name
* to be overridden.
*/
- private Splittable encodeValue(Object value) {
+ private Splittable encodeValue(Class<?> expectedType, Object value) {
Splittable split;
if (value instanceof Enum<?> && enumMap != null) {
- split = ValueCodex.encode(enumMap.getToken((Enum<?>) value));
+ split = ValueCodex.encode(String.class,
+ enumMap.getToken((Enum<?>) value));
} else {
- split = ValueCodex.encode(value);
+ split = ValueCodex.encode(expectedType, value);
}
return split;
}
@@ -429,8 +434,8 @@
* encoded as a list of two lists, since it's possible that two distinct
* objects have the same encoded form.
*/
- private void writeObjectKeyMap(Map<?, ?> map, boolean isEncodedKey,
- boolean isEncodedValue, boolean isValueValue) {
+ private void writeObjectKeyMap(Map<?, ?> map, Class<?> valueType,
+ boolean isEncodedKey, boolean isEncodedValue, boolean isValueValue) {
StringBuilder keys = new StringBuilder();
StringBuilder values = new StringBuilder();
@@ -445,7 +450,8 @@
values.append(",").append(
((Splittable) entry.getValue()).getPayload());
} else if (isValueValue) {
- values.append(",").append(encodeValue(entry.getValue()).getPayload());
+ values.append(",").append(
+ encodeValue(valueType, entry.getValue()).getPayload());
} else {
encodeToStringBuilder(values.append(","), entry.getValue());
}
@@ -462,15 +468,15 @@
/**
* Writes a map JSON literal where the keys are value types.
*/
- private void writeValueKeyMap(Map<?, ?> map, boolean isEncodedValue,
- boolean isValueValue) {
+ private void writeValueKeyMap(Map<?, ?> map, Class<?> keyType,
+ Class<?> valueType, boolean isEncodedValue, boolean isValueValue) {
for (Map.Entry<?, ?> entry : map.entrySet()) {
- sb.append(",").append(encodeValue(entry.getKey()).getPayload()).append(
+ sb.append(",").append(encodeValue(keyType, entry.getKey()).getPayload()).append(
":");
if (isEncodedValue) {
sb.append(((Splittable) entry.getValue()).getPayload());
} else if (isValueValue) {
- sb.append(encodeValue(entry.getValue()).getPayload());
+ sb.append(encodeValue(valueType, entry.getValue()).getPayload());
} else {
encodeToStringBuilder(sb, entry.getValue());
}
diff --git a/user/src/com/google/gwt/autobean/shared/ValueCodex.java b/user/src/com/google/gwt/autobean/shared/ValueCodex.java
index 19ef456..ca867eb 100644
--- a/user/src/com/google/gwt/autobean/shared/ValueCodex.java
+++ b/user/src/com/google/gwt/autobean/shared/ValueCodex.java
@@ -20,9 +20,11 @@
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
/**
* Provides unified encoding and decoding of value objects.
@@ -31,6 +33,11 @@
enum Type {
BIG_DECIMAL(BigDecimal.class) {
@Override
+ public boolean canUpcast(Object value) {
+ return value instanceof BigDecimal;
+ }
+
+ @Override
public BigDecimal decode(Class<?> clazz, String value) {
return new BigDecimal(value);
}
@@ -42,6 +49,11 @@
},
BIG_INTEGER(BigInteger.class) {
@Override
+ public boolean canUpcast(Object value) {
+ return value instanceof BigInteger;
+ }
+
+ @Override
public BigInteger decode(Class<?> clazz, String value) {
return new BigInteger(value);
}
@@ -71,6 +83,11 @@
},
DATE(Date.class) {
@Override
+ public boolean canUpcast(Object value) {
+ return value instanceof Date;
+ }
+
+ @Override
public Date decode(Class<?> clazz, String value) {
return new Date(Long.valueOf(value));
}
@@ -158,6 +175,15 @@
this.defaultValue = defaultValue;
}
+ /**
+ * Determines whether or not the Type can handle the given value via
+ * upcasting semantics.
+ */
+ public boolean canUpcast(Object value) {
+ // Most value types are final, so this method is meaningless
+ return false;
+ }
+
public abstract Object decode(Class<?> clazz, String value);
public Object getDefaultValue() {
@@ -177,14 +203,18 @@
}
}
- private static Map<Class<?>, Type> typesByClass = new HashMap<Class<?>, Type>();
+ private static final Set<Class<?>> ALL_VALUE_TYPES;
+ private static final Map<Class<?>, Type> TYPES_BY_CLASS;
static {
+ Map<Class<?>, Type> temp = new HashMap<Class<?>, Type>();
for (Type t : Type.values()) {
- typesByClass.put(t.getType(), t);
+ temp.put(t.getType(), t);
if (t.getPrimitiveType() != null) {
- typesByClass.put(t.getPrimitiveType(), t);
+ temp.put(t.getPrimitiveType(), t);
}
}
+ ALL_VALUE_TYPES = Collections.unmodifiableSet(temp.keySet());
+ TYPES_BY_CLASS = Collections.unmodifiableMap(temp);
}
/**
@@ -194,7 +224,11 @@
* @return {@code true} if the given object type can be decoded
*/
public static boolean canDecode(Class<?> clazz) {
- return findType(clazz) != null;
+ if (findType(clazz) != null) {
+ return true;
+ }
+ // Use other platform-specific tests
+ return ValueCodexHelper.canDecode(clazz);
}
public static <T> T decode(Class<T> clazz, Splittable split) {
@@ -212,12 +246,42 @@
return (T) getTypeOrDie(clazz).decode(clazz, string);
}
+ /**
+ * Encode a value object when the wire format type is known. This method
+ * should be preferred over {@link #encode(Object)} when possible.
+ */
+ public static Splittable encode(Class<?> clazz, Object obj) {
+ if (obj == null) {
+ return LazySplittable.NULL;
+ }
+ return new LazySplittable(getTypeOrDie(clazz).toJsonExpression(obj));
+ }
+
public static Splittable encode(Object obj) {
if (obj == null) {
return LazySplittable.NULL;
}
- return new LazySplittable(
- getTypeOrDie(obj.getClass()).toJsonExpression(obj));
+ Type t = findType(obj.getClass());
+ // Try upcasting
+ if (t == null) {
+ for (Type maybe : Type.values()) {
+ if (maybe.canUpcast(obj)) {
+ t = maybe;
+ break;
+ }
+ }
+ }
+ if (t == null) {
+ throw new UnsupportedOperationException(obj.getClass().getName());
+ }
+ return new LazySplittable(t.toJsonExpression(obj));
+ }
+
+ /**
+ * Return all Value types that can be processed by the ValueCodex.
+ */
+ public static Set<Class<?>> getAllValueTypes() {
+ return ALL_VALUE_TYPES;
}
/**
@@ -235,14 +299,10 @@
* May return <code>null</code>.
*/
private static <T> Type findType(Class<T> clazz) {
- Type type = typesByClass.get(clazz);
- if (type == null) {
- // Necessary due to lack of Class.isAssignable() in client-side
- if (clazz.getEnumConstants() != null) {
- return Type.ENUM;
- }
+ if (clazz.isEnum()) {
+ return Type.ENUM;
}
- return type;
+ return TYPES_BY_CLASS.get(clazz);
}
private static <T> Type getTypeOrDie(Class<T> clazz) {
diff --git a/user/src/com/google/gwt/autobean/shared/ValueCodexHelper.java b/user/src/com/google/gwt/autobean/shared/ValueCodexHelper.java
new file mode 100644
index 0000000..c6f72c8
--- /dev/null
+++ b/user/src/com/google/gwt/autobean/shared/ValueCodexHelper.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010 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.autobean.shared;
+
+import com.google.gwt.core.client.GWT;
+
+/**
+ * Provides reflection-based operation for server (JVM) implementation. There is
+ * a no-op super-source version for client (dev- and web-mode) code.
+ */
+class ValueCodexHelper {
+ /**
+ * Returns {@code true} if {@code clazz} is assignable to any of the value
+ * types.
+ */
+ static boolean canDecode(Class<?> clazz) {
+ assert !GWT.isClient();
+ for (Class<?> valueType : ValueCodex.getAllValueTypes()) {
+ if (valueType.isAssignableFrom(clazz)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/user/src/com/google/gwt/autobean/shared/impl/StringQuoter.java b/user/src/com/google/gwt/autobean/shared/impl/StringQuoter.java
index 9f65e5e..15ce275 100644
--- a/user/src/com/google/gwt/autobean/shared/impl/StringQuoter.java
+++ b/user/src/com/google/gwt/autobean/shared/impl/StringQuoter.java
@@ -17,7 +17,8 @@
import com.google.gwt.autobean.server.impl.JsonSplittable;
import com.google.gwt.autobean.shared.Splittable;
-import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter;
+
+import org.json.JSONObject;
/**
* This class has a super-source version with a client-only implementation.
@@ -27,7 +28,7 @@
* Create a quoted JSON string.
*/
public static String quote(String raw) {
- return ServerSerializationStreamWriter.escapeString(raw);
+ return JSONObject.quote(raw);
}
public static Splittable split(String payload) {
diff --git a/user/src/com/google/gwt/cell/client/AbstractCell.java b/user/src/com/google/gwt/cell/client/AbstractCell.java
index d47edee..e98f6af 100644
--- a/user/src/com/google/gwt/cell/client/AbstractCell.java
+++ b/user/src/com/google/gwt/cell/client/AbstractCell.java
@@ -1,12 +1,12 @@
/*
* Copyright 2010 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
@@ -15,6 +15,7 @@
*/
package com.google.gwt.cell.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.KeyCodes;
@@ -26,7 +27,7 @@
/**
* A default implementation of the {@link Cell} interface.
- *
+ *
* <p>
* <h3>Examples</h3>
* <dl>
@@ -38,7 +39,7 @@
* <dd>{@example com.google.gwt.examples.cell.EditableCellExample}</dd>
* </dl>
* </p>
- *
+ *
* @param <C> the type that this Cell represents
*/
public abstract class AbstractCell<C> implements Cell<C> {
@@ -51,7 +52,7 @@
/**
* Construct a new {@link AbstractCell} with the specified consumed events.
* The input arguments are passed by copy.
- *
+ *
* @param consumedEvents the events that this cell consumes
*/
public AbstractCell(String... consumedEvents) {
@@ -67,7 +68,7 @@
/**
* Construct a new {@link AbstractCell} with the specified consumed events.
- *
+ *
* @param consumedEvents the events that this cell consumes
*/
public AbstractCell(Set<String> consumedEvents) {
@@ -90,45 +91,45 @@
* Returns false. Subclasses that support editing should override this method
* to return the current editing status.
*/
- public boolean isEditing(Element parent, C value, Object key) {
+ public boolean isEditing(Context context, Element parent, C value) {
return false;
}
/**
* {@inheritDoc}
- *
+ *
* <p>
* If you override this method to add support for events, remember to pass the
* event types that the cell expects into the constructor.
* </p>
*/
- public void onBrowserEvent(Element parent, C value, Object key,
+ public void onBrowserEvent(Context context, Element parent, C value,
NativeEvent event, ValueUpdater<C> valueUpdater) {
String eventType = event.getType();
// Special case the ENTER key for a unified user experience.
if ("keydown".equals(eventType) && event.getKeyCode() == KeyCodes.KEY_ENTER) {
- onEnterKeyDown(parent, value, key, event, valueUpdater);
+ onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
- public abstract void render(C value, Object key, SafeHtmlBuilder sb);
+ public abstract void render(Context context, C value, SafeHtmlBuilder sb);
/**
* {@inheritDoc}
- *
+ *
* <p>
* This method is a no-op and returns false. If your cell is editable or can
* be focused by the user, override this method to reset focus when the
* containing widget is refreshed.
* </p>
*/
- public boolean resetFocus(Element parent, C value, Object key) {
+ public boolean resetFocus(Context context, Element parent, C value) {
return false;
}
- public void setValue(Element parent, C value, Object key) {
+ public void setValue(Context context, Element parent, C value) {
SafeHtmlBuilder sb = new SafeHtmlBuilder();
- render(value, key, sb);
+ render(context, value, sb);
parent.setInnerHTML(sb.toSafeHtml().asString());
}
@@ -138,20 +139,20 @@
* should override this method to provide a consistent user experience. Your
* widget must consume <code>keydown</code> events for this method to be
* called.
- *
+ *
+ * @param context the {@link Context} of the cell
* @param parent the parent Element
* @param value the value associated with the cell
- * @param key the unique key associated with the row object
* @param event the native browser event
* @param valueUpdater a {@link ValueUpdater}, or null if not specified
*/
- protected void onEnterKeyDown(Element parent, C value, Object key,
+ protected void onEnterKeyDown(Context context, Element parent, C value,
NativeEvent event, ValueUpdater<C> valueUpdater) {
}
/**
* Initialize the cell.
- *
+ *
* @param consumedEvents the events that the cell consumes
*/
private void init(Set<String> consumedEvents) {
diff --git a/user/src/com/google/gwt/cell/client/AbstractEditableCell.java b/user/src/com/google/gwt/cell/client/AbstractEditableCell.java
index a99eb8f..66a4bcb 100644
--- a/user/src/com/google/gwt/cell/client/AbstractEditableCell.java
+++ b/user/src/com/google/gwt/cell/client/AbstractEditableCell.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.cell.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.Element;
import java.util.HashMap;
@@ -76,7 +77,7 @@
*
* @param key the key identifying the row object
* @return the view data, or null if none has been set
- * @see #setViewData(Object, Object)V
+ * @see #setViewData(Object, Object)
*/
public V getViewData(Object key) {
return (key == null) ? null : viewDataMap.get(key);
@@ -87,14 +88,14 @@
* given element and key. While a cell is editing, widgets containing the cell
* may choose to pass keystrokes directly to the cell rather than using them
* for navigation purposes.
- *
+ *
+ * @param context the {@link Context} of the cell
* @param parent the parent Element
* @param value the value associated with the cell
- * @param key the unique key associated with the row object
* @return true if the cell is in edit mode
*/
@Override
- public abstract boolean isEditing(Element parent, C value, Object key);
+ public abstract boolean isEditing(Context context, Element parent, C value);
/**
* Associate view data with the specified key. If the key is null, the view
diff --git a/user/src/com/google/gwt/cell/client/AbstractInputCell.java b/user/src/com/google/gwt/cell/client/AbstractInputCell.java
index e67ccf5..b9719fc 100644
--- a/user/src/com/google/gwt/cell/client/AbstractInputCell.java
+++ b/user/src/com/google/gwt/cell/client/AbstractInputCell.java
@@ -1,12 +1,12 @@
/*
* Copyright 2010 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
@@ -23,7 +23,7 @@
/**
* An {@link AbstractCell} used to render input elements that can receive focus.
- *
+ *
* @param <C> the type that this Cell represents
* @param <V> the data type of the view data state
*/
@@ -32,7 +32,7 @@
/**
* Get the events consumed by the input cell.
- *
+ *
* @param userEvents the events consumed by the subclass
* @return the events
*/
@@ -49,7 +49,7 @@
/**
* Get the events consumed by the input cell.
- *
+ *
* @param userEvents the events consumed by the subclass
* @return the events
*/
@@ -71,7 +71,7 @@
/**
* Construct a new {@link AbstractInputCell} with the specified consumed
* events.
- *
+ *
* @param consumedEvents the events that this cell consumes
*/
public AbstractInputCell(String... consumedEvents) {
@@ -81,7 +81,7 @@
/**
* Construct a new {@link AbstractInputCell} with the specified consumed
* events.
- *
+ *
* @param consumedEvents the events that this cell consumes
*/
public AbstractInputCell(Set<String> consumedEvents) {
@@ -89,14 +89,14 @@
}
@Override
- public boolean isEditing(Element parent, C value, Object key) {
- return focusedKey != null && focusedKey.equals(key);
+ public boolean isEditing(Context context, Element parent, C value) {
+ return focusedKey != null && focusedKey.equals(context.getKey());
}
@Override
- public void onBrowserEvent(Element parent, C value, Object key,
+ public void onBrowserEvent(Context context, Element parent, C value,
NativeEvent event, ValueUpdater<C> valueUpdater) {
- super.onBrowserEvent(parent, value, key, event, valueUpdater);
+ super.onBrowserEvent(context, parent, value, event, valueUpdater);
// Ignore events that don't target the input.
Element target = event.getEventTarget().cast();
@@ -106,15 +106,15 @@
String eventType = event.getType();
if ("focus".equals(eventType)) {
- focusedKey = key;
+ focusedKey = context.getKey();
} else if ("blur".equals(eventType)) {
focusedKey = null;
}
}
@Override
- public boolean resetFocus(Element parent, C value, Object key) {
- if (isEditing(parent, value, key)) {
+ public boolean resetFocus(Context context, Element parent, C value) {
+ if (isEditing(context, parent, value)) {
getInputElement(parent).focus();
return true;
}
@@ -123,7 +123,7 @@
/**
* Call this method when editing is complete.
- *
+ *
* @param parent the parent Element
* @param value the value associated with the cell
* @param key the unique key associated with the row object
@@ -137,7 +137,7 @@
/**
* Get the input element.
- *
+ *
* @param parent the cell parent element
* @return the input element
*/
@@ -146,10 +146,11 @@
}
@Override
- protected void onEnterKeyDown(Element parent, C value, Object key,
+ protected void onEnterKeyDown(Context context, Element parent, C value,
NativeEvent event, ValueUpdater<C> valueUpdater) {
Element input = getInputElement(parent);
Element target = event.getEventTarget().cast();
+ Object key = context.getKey();
if (getInputElement(parent).isOrHasChild(target)) {
finishEditing(parent, value, key, valueUpdater);
} else {
diff --git a/user/src/com/google/gwt/cell/client/AbstractSafeHtmlCell.java b/user/src/com/google/gwt/cell/client/AbstractSafeHtmlCell.java
index 4d7bc32..73f7ac7 100644
--- a/user/src/com/google/gwt/cell/client/AbstractSafeHtmlCell.java
+++ b/user/src/com/google/gwt/cell/client/AbstractSafeHtmlCell.java
@@ -73,11 +73,11 @@
}
@Override
- public void render(C data, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, C data, SafeHtmlBuilder sb) {
if (data == null) {
- render((SafeHtml) null, key, sb);
+ render(context, (SafeHtml) null, sb);
} else {
- render(renderer.render(data), key, sb);
+ render(context, renderer.render(data), sb);
}
}
@@ -85,9 +85,10 @@
* Render the cell contents after they have been converted to {@link SafeHtml}
* form.
*
+ * @param context the original context to render
* @param data a {@link SafeHtml} string
- * @param key the unique key associated with the row object
* @param sb the {@link SafeHtmlBuilder} to be written to
*/
- protected abstract void render(SafeHtml data, Object key, SafeHtmlBuilder sb);
+ protected abstract void render(Context context, SafeHtml data,
+ SafeHtmlBuilder sb);
}
diff --git a/user/src/com/google/gwt/cell/client/ActionCell.java b/user/src/com/google/gwt/cell/client/ActionCell.java
index 0003118..c72c63d 100644
--- a/user/src/com/google/gwt/cell/client/ActionCell.java
+++ b/user/src/com/google/gwt/cell/client/ActionCell.java
@@ -72,21 +72,21 @@
}
@Override
- public void onBrowserEvent(Element parent, C value, Object key,
+ public void onBrowserEvent(Context context, Element parent, C value,
NativeEvent event, ValueUpdater<C> valueUpdater) {
- super.onBrowserEvent(parent, value, key, event, valueUpdater);
+ super.onBrowserEvent(context, parent, value, event, valueUpdater);
if ("click".equals(event.getType())) {
- onEnterKeyDown(parent, value, key, event, valueUpdater);
+ onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
@Override
- public void render(C value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, C value, SafeHtmlBuilder sb) {
sb.append(html);
}
@Override
- protected void onEnterKeyDown(Element parent, C value, Object key,
+ protected void onEnterKeyDown(Context context, Element parent, C value,
NativeEvent event, ValueUpdater<C> valueUpdater) {
delegate.execute(value);
}
diff --git a/user/src/com/google/gwt/cell/client/ButtonCell.java b/user/src/com/google/gwt/cell/client/ButtonCell.java
index d8caa83..cabd39e 100644
--- a/user/src/com/google/gwt/cell/client/ButtonCell.java
+++ b/user/src/com/google/gwt/cell/client/ButtonCell.java
@@ -44,16 +44,16 @@
}
@Override
- public void onBrowserEvent(Element parent, String value, Object key,
+ public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
- super.onBrowserEvent(parent, value, key, event, valueUpdater);
+ super.onBrowserEvent(context, parent, value, event, valueUpdater);
if ("click".equals(event.getType())) {
- onEnterKeyDown(parent, value, key, event, valueUpdater);
+ onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
@Override
- public void render(SafeHtml data, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, SafeHtml data, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<button type=\"button\" tabindex=\"-1\">");
if (data != null) {
sb.append(data);
@@ -62,7 +62,7 @@
}
@Override
- protected void onEnterKeyDown(Element parent, String value, Object key,
+ protected void onEnterKeyDown(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
if (valueUpdater != null) {
valueUpdater.update(value);
diff --git a/user/src/com/google/gwt/cell/client/Cell.java b/user/src/com/google/gwt/cell/client/Cell.java
index 217217f..2f32358 100644
--- a/user/src/com/google/gwt/cell/client/Cell.java
+++ b/user/src/com/google/gwt/cell/client/Cell.java
@@ -1,12 +1,12 @@
/*
* Copyright 2010 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
@@ -23,19 +23,70 @@
/**
* A light weight representation of a renderable object.
- *
+ *
* <p>
* <h3>Example</h3>
* {@example com.google.gwt.examples.cell.CellExample}
* </p>
- *
+ *
* @param <C> the type that this Cell represents
*/
public interface Cell<C> {
/**
+ * Contains information about the context of the Cell.
+ */
+ public static class Context {
+
+ private final int column;
+ private final int index;
+ private final Object key;
+
+ /**
+ * Create a new {@link Context}.
+ *
+ * @param index the absolute index of the value
+ * @param column the column index of the cell, or 0
+ * @param key the unique key that represents the row value
+ */
+ public Context(int index, int column, Object key) {
+ this.index = index;
+ this.column = column;
+ this.key = key;
+ }
+
+ /**
+ * Get the column index of the cell. If the view only contains a single
+ * column, this method returns 0.
+ *
+ * @return the column index of the cell
+ */
+ public int getColumn() {
+ return column;
+ }
+
+ /**
+ * Get the absolute index of the value.
+ *
+ * @return the index
+ */
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * Get the key that uniquely identifies the row object.
+ *
+ * @return the unique key
+ */
+ public Object getKey() {
+ return key;
+ }
+ }
+
+ /**
* Check if this cell depends on the selection state.
- *
+ *
* @return true if dependent on selection, false if not
*/
boolean dependsOnSelection();
@@ -43,13 +94,14 @@
/**
* Get the set of events that this cell consumes. The container that uses this
* cell should only pass these events to
- * {@link #onBrowserEvent(Element, Object, Object, NativeEvent, ValueUpdater)}.
- *
+ * {@link #onBrowserEvent(Context, Element, Object, NativeEvent, ValueUpdater))}
+ * when the event occurs.
+ *
* <p>
* The returned value should not be modified, and may be an unmodifiable set.
* Changes to the return value may not be reflected in the cell.
* </p>
- *
+ *
* @return the consumed events, or null if no events are consumed
*/
Set<String> getConsumedEvents();
@@ -57,7 +109,7 @@
/**
* Check if this cell handles selection. If the cell handles selection, then
* its container should not automatically handle selection.
- *
+ *
* @return true if the cell handles selection, false if not
*/
boolean handlesSelection();
@@ -65,32 +117,32 @@
/**
* Returns true if the cell is currently editing the data identified by the
* given element and key. While a cell is editing, widgets containing the cell
- * may chooses to pass keystrokes directly to the cell rather than using them
+ * may choose to pass keystrokes directly to the cell rather than using them
* for navigation purposes.
- *
+ *
+ * @param context the {@link Context} of the cell
* @param parent the parent Element
* @param value the value associated with the cell
- * @param key the unique key associated with the row object
* @return true if the cell is in edit mode
*/
- boolean isEditing(Element parent, C value, Object key);
+ boolean isEditing(Context context, Element parent, C value);
/**
* Handle a browser event that took place within the cell. The default
* implementation returns null.
- *
+ *
+ * @param context the {@link Context} of the cell
* @param parent the parent Element
* @param value the value associated with the cell
- * @param key the unique key associated with the row object
* @param event the native browser event
* @param valueUpdater a {@link ValueUpdater}, or null if not specified
*/
- void onBrowserEvent(Element parent, C value, Object key, NativeEvent event,
- ValueUpdater<C> valueUpdater);
+ void onBrowserEvent(Context context, Element parent, C value,
+ NativeEvent event, ValueUpdater<C> valueUpdater);
/**
* Render a cell as HTML into a {@link SafeHtmlBuilder}, suitable for passing
- * to {@link Element#setInnerHTML} on a container element.
+ * to {@link Element#setInnerHTML(String)} on a container element.
*
* <p>
* Note: If your cell contains natively focusable elements, such as buttons or
@@ -98,33 +150,32 @@
* focus away from the containing widget.
* </p>
*
+ * @param context the {@link Context} of the cell
* @param value the cell value to be rendered
- * @param key the unique key associated with the row object
* @param sb the {@link SafeHtmlBuilder} to be written to
*/
- void render(C value, Object key, SafeHtmlBuilder sb);
+ void render(Context context, C value, SafeHtmlBuilder sb);
/**
* Reset focus on the Cell. This method is called if the cell has focus when
* it is refreshed.
- *
+ *
+ * @param context the {@link Context} of the cell
* @param parent the parent Element
* @param value the value associated with the cell
- * @param key the unique key associated with the row object
- *
* @return true if focus is taken, false if not
*/
- boolean resetFocus(Element parent, C value, Object key);
+ boolean resetFocus(Context context, Element parent, C value);
/**
* This method may be used by cell containers to set the value on a single
* cell directly, rather than using {@link Element#setInnerHTML(String)}. See
- * {@link AbstractCell#setValue(Element, Object, Object)} for a default
- * implementation that uses {@link #render(Object, Object, SafeHtmlBuilder)}.
- *
+ * {@link AbstractCell#setValue(Context)} for a default implementation that
+ * uses {@link #render(Context, SafeHtmlBuilder))}.
+ *
+ * @param context the {@link Context} of the cell
* @param parent the parent Element
* @param value the value associated with the cell
- * @param key the unique key associated with the row object
*/
- void setValue(Element parent, C value, Object key);
+ void setValue(Context context, Element parent, C value);
}
diff --git a/user/src/com/google/gwt/cell/client/CheckboxCell.java b/user/src/com/google/gwt/cell/client/CheckboxCell.java
index 1f51a1d..e0eae00 100644
--- a/user/src/com/google/gwt/cell/client/CheckboxCell.java
+++ b/user/src/com/google/gwt/cell/client/CheckboxCell.java
@@ -83,14 +83,14 @@
}
@Override
- public boolean isEditing(Element parent, Boolean value, Object key) {
+ public boolean isEditing(Context context, Element parent, Boolean value) {
// A checkbox is never in "edit mode". There is no intermediate state
// between checked and unchecked.
return false;
}
@Override
- public void onBrowserEvent(Element parent, Boolean value, Object key,
+ public void onBrowserEvent(Context context, Element parent, Boolean value,
NativeEvent event, ValueUpdater<Boolean> valueUpdater) {
String type = event.getType();
@@ -117,9 +117,9 @@
* do not save the value because we can get into an inconsistent state.
*/
if (value != isChecked && !dependsOnSelection()) {
- setViewData(key, isChecked);
+ setViewData(context.getKey(), isChecked);
} else {
- clearViewData(key);
+ clearViewData(context.getKey());
}
if (valueUpdater != null) {
@@ -129,8 +129,9 @@
}
@Override
- public void render(Boolean value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Boolean value, SafeHtmlBuilder sb) {
// Get the view data.
+ Object key = context.getKey();
Boolean viewData = getViewData(key);
if (viewData != null && viewData.equals(value)) {
clearViewData(key);
diff --git a/user/src/com/google/gwt/cell/client/ClickableTextCell.java b/user/src/com/google/gwt/cell/client/ClickableTextCell.java
index 16fbe38..a3a41d7 100644
--- a/user/src/com/google/gwt/cell/client/ClickableTextCell.java
+++ b/user/src/com/google/gwt/cell/client/ClickableTextCell.java
@@ -47,16 +47,16 @@
}
@Override
- public void onBrowserEvent(Element parent, String value, Object key,
+ public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
- super.onBrowserEvent(parent, value, key, event, valueUpdater);
+ super.onBrowserEvent(context, parent, value, event, valueUpdater);
if ("click".equals(event.getType())) {
- onEnterKeyDown(parent, value, key, event, valueUpdater);
+ onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
@Override
- protected void onEnterKeyDown(Element parent, String value, Object key,
+ protected void onEnterKeyDown(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
if (valueUpdater != null) {
valueUpdater.update(value);
@@ -64,7 +64,7 @@
}
@Override
- protected void render(SafeHtml value, Object key, SafeHtmlBuilder sb) {
+ protected void render(Context context, SafeHtml value, SafeHtmlBuilder sb) {
if (value != null) {
sb.append(value);
}
diff --git a/user/src/com/google/gwt/cell/client/CompositeCell.java b/user/src/com/google/gwt/cell/client/CompositeCell.java
index 6013d46..c1328b6 100644
--- a/user/src/com/google/gwt/cell/client/CompositeCell.java
+++ b/user/src/com/google/gwt/cell/client/CompositeCell.java
@@ -1,12 +1,12 @@
/*
* Copyright 2010 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
@@ -30,13 +30,13 @@
* <p>
* A {@link Cell} that is composed of other {@link Cell}s.
* </p>
- *
+ *
* <p>
* When this cell is rendered, it will render each component {@link Cell} inside
* a span. If the component {@link Cell} uses block level elements (such as a
* Div), the component cells will stack vertically.
* </p>
- *
+ *
* @param <C> the type that this Cell represents
*/
public class CompositeCell<C> extends AbstractCell<C> {
@@ -58,7 +58,7 @@
/**
* The cells that compose this {@link Cell}.
- *
+ *
* NOTE: Do not add add/insert/remove hasCells methods to the API. This cell
* assumes that the index of the cellParent corresponds to the index in the
* hasCells array.
@@ -67,7 +67,7 @@
/**
* Construct a new {@link CompositeCell}.
- *
+ *
* @param hasCells the cells that makeup the composite
*/
public CompositeCell(List<HasCell<C, ?>> hasCells) {
@@ -113,7 +113,7 @@
}
@Override
- public void onBrowserEvent(Element parent, C value, Object key,
+ public void onBrowserEvent(Context context, Element parent, C value,
NativeEvent event, ValueUpdater<C> valueUpdater) {
int index = 0;
EventTarget eventTarget = event.getEventTarget();
@@ -123,7 +123,7 @@
Element wrapper = container.getFirstChildElement();
while (wrapper != null) {
if (wrapper.isOrHasChild(target)) {
- onBrowserEventImpl(wrapper, value, key, event, valueUpdater,
+ onBrowserEventImpl(context, wrapper, value, event, valueUpdater,
hasCells.get(index));
}
@@ -134,19 +134,19 @@
}
@Override
- public void render(C value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, C value, SafeHtmlBuilder sb) {
for (HasCell<C, ?> hasCell : hasCells) {
- render(value, key, sb, hasCell);
+ render(context, value, sb, hasCell);
}
}
@Override
- public boolean resetFocus(Element parent, C value, Object key) {
+ public boolean resetFocus(Context context, Element parent, C value) {
Element curChild = getContainerElement(parent).getFirstChildElement();
for (HasCell<C, ?> hasCell : hasCells) {
// The first child that takes focus wins. Only one child should ever be in
// edit mode, so this is safe.
- if (resetFocusImpl(curChild, value, key, hasCell)) {
+ if (resetFocusImpl(context, curChild, value, hasCell)) {
return true;
}
curChild = curChild.getNextSiblingElement();
@@ -155,10 +155,10 @@
}
@Override
- public void setValue(Element parent, C object, Object key) {
+ public void setValue(Context context, Element parent, C object) {
Element curChild = getContainerElement(parent).getFirstChildElement();
for (HasCell<C, ?> hasCell : hasCells) {
- setValueImpl(curChild, object, key, hasCell);
+ setValueImpl(context, curChild, object, hasCell);
curChild = curChild.getNextSiblingElement();
}
}
@@ -167,7 +167,7 @@
* Get the element that acts as the container for all children. If children
* are added directly to the parent, the parent is the container. If children
* are added in a table row, the row is the parent.
- *
+ *
* @param parent the parent element of the cell
* @return the container element
*/
@@ -185,22 +185,22 @@
* focus away from the containing widget.
* </p>
*
+ * @param context the {@link Context} of the cell
* @param value the cell value to be rendered
- * @param key the unique key associated with the row object
* @param sb the {@link SafeHtmlBuilder} to be written to
* @param hasCell a {@link HasCell} instance containing the cells to be
* rendered within this cell
*/
- protected <X> void render(C value, Object key, SafeHtmlBuilder sb,
- HasCell<C, X> hasCell) {
+ protected <X> void render(Context context, C value,
+ SafeHtmlBuilder sb, HasCell<C, X> hasCell) {
Cell<X> cell = hasCell.getCell();
sb.appendHtmlConstant("<span>");
- cell.render(hasCell.getValue(value), key, sb);
+ cell.render(context, hasCell.getValue(value), sb);
sb.appendHtmlConstant("</span>");
}
- private <X> void onBrowserEventImpl(Element parent, final C object,
- Object key, NativeEvent event, final ValueUpdater<C> valueUpdater,
+ private <X> void onBrowserEventImpl(Context context, Element parent,
+ final C object, NativeEvent event, final ValueUpdater<C> valueUpdater,
final HasCell<C, X> hasCell) {
ValueUpdater<X> tempUpdater = null;
final FieldUpdater<C, X> fieldUpdater = hasCell.getFieldUpdater();
@@ -215,18 +215,18 @@
};
}
Cell<X> cell = hasCell.getCell();
- cell.onBrowserEvent(parent, hasCell.getValue(object), key, event,
+ cell.onBrowserEvent(context, parent, hasCell.getValue(object), event,
tempUpdater);
}
- private <X> boolean resetFocusImpl(Element cellParent, C value, Object key,
- HasCell<C, X> hasCell) {
+ private <X> boolean resetFocusImpl(Context context, Element cellParent,
+ C value, HasCell<C, X> hasCell) {
X cellValue = hasCell.getValue(value);
- return hasCell.getCell().resetFocus(cellParent, cellValue, key);
+ return hasCell.getCell().resetFocus(context, cellParent, cellValue);
}
- private <X> void setValueImpl(Element cellParent, C object, Object key,
+ private <X> void setValueImpl(Context context, Element cellParent, C object,
HasCell<C, X> hasCell) {
- hasCell.getCell().setValue(cellParent, hasCell.getValue(object), key);
- }
+ hasCell.getCell().setValue(context, cellParent, hasCell.getValue(object));
+ }
}
diff --git a/user/src/com/google/gwt/cell/client/DateCell.java b/user/src/com/google/gwt/cell/client/DateCell.java
index bfab2af..bed5b8b 100644
--- a/user/src/com/google/gwt/cell/client/DateCell.java
+++ b/user/src/com/google/gwt/cell/client/DateCell.java
@@ -82,7 +82,7 @@
}
@Override
- public void render(Date value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Date value, SafeHtmlBuilder sb) {
if (value != null) {
sb.append(renderer.render(format.format(value)));
}
diff --git a/user/src/com/google/gwt/cell/client/DatePickerCell.java b/user/src/com/google/gwt/cell/client/DatePickerCell.java
index 49df900..4b1252b 100644
--- a/user/src/com/google/gwt/cell/client/DatePickerCell.java
+++ b/user/src/com/google/gwt/cell/client/DatePickerCell.java
@@ -61,6 +61,8 @@
private int offsetY = 10;
private Object lastKey;
private Element lastParent;
+ private int lastIndex;
+ private int lastColumn;
private Date lastValue;
private PopupPanel panel;
private final SafeHtmlRenderer<String> renderer;
@@ -131,6 +133,8 @@
public void onClose(CloseEvent<PopupPanel> event) {
lastKey = null;
lastValue = null;
+ lastIndex = -1;
+ lastColumn = -1;
if (lastParent != null && !event.isAutoClosed()) {
// Refocus on the containing cell after the user selects a value, but
// not if the popup is auto closed.
@@ -148,12 +152,14 @@
Element cellParent = lastParent;
Date oldValue = lastValue;
Object key = lastKey;
+ int index = lastIndex;
+ int column = lastColumn;
panel.hide();
// Update the cell and value updater.
Date date = event.getValue();
setViewData(key, date);
- setValue(cellParent, oldValue, key);
+ setValue(new Context(index, column, key), cellParent, oldValue);
if (valueUpdater != null) {
valueUpdater.update(date);
}
@@ -162,22 +168,23 @@
}
@Override
- public boolean isEditing(Element parent, Date value, Object key) {
- return lastKey != null && lastKey.equals(key);
+ public boolean isEditing(Context context, Element parent, Date value) {
+ return lastKey != null && lastKey.equals(context.getKey());
}
@Override
- public void onBrowserEvent(Element parent, Date value, Object key,
+ public void onBrowserEvent(Context context, Element parent, Date value,
NativeEvent event, ValueUpdater<Date> valueUpdater) {
- super.onBrowserEvent(parent, value, key, event, valueUpdater);
+ super.onBrowserEvent(context, parent, value, event, valueUpdater);
if ("click".equals(event.getType())) {
- onEnterKeyDown(parent, value, key, event, valueUpdater);
+ onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
@Override
- public void render(Date value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Date value, SafeHtmlBuilder sb) {
// Get the view data.
+ Object key = context.getKey();
Date viewData = getViewData(key);
if (viewData != null && viewData.equals(value)) {
clearViewData(key);
@@ -196,21 +203,23 @@
}
@Override
- protected void onEnterKeyDown(final Element parent, Date value, Object key,
+ protected void onEnterKeyDown(Context context, Element parent, Date value,
NativeEvent event, ValueUpdater<Date> valueUpdater) {
- this.lastKey = key;
+ this.lastKey = context.getKey();
this.lastParent = parent;
this.lastValue = value;
+ this.lastIndex = context.getIndex();
+ this.lastColumn = context.getColumn();
this.valueUpdater = valueUpdater;
- Date viewData = getViewData(key);
- Date date = (viewData == null) ? value : viewData;
+ Date viewData = getViewData(lastKey);
+ Date date = (viewData == null) ? lastValue : viewData;
datePicker.setCurrentMonth(date);
datePicker.setValue(date);
panel.setPopupPositionAndShow(new PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight) {
- panel.setPopupPosition(parent.getAbsoluteLeft() + offsetX,
- parent.getAbsoluteTop() + offsetY);
+ panel.setPopupPosition(lastParent.getAbsoluteLeft() + offsetX,
+ lastParent.getAbsoluteTop() + offsetY);
}
});
}
diff --git a/user/src/com/google/gwt/cell/client/EditTextCell.java b/user/src/com/google/gwt/cell/client/EditTextCell.java
index 57f214f..e180a69 100644
--- a/user/src/com/google/gwt/cell/client/EditTextCell.java
+++ b/user/src/com/google/gwt/cell/client/EditTextCell.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.cell.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
@@ -161,18 +162,19 @@
}
@Override
- public boolean isEditing(Element element, String value, Object key) {
- ViewData viewData = getViewData(key);
+ public boolean isEditing(Context context, Element parent, String value) {
+ ViewData viewData = getViewData(context.getKey());
return viewData == null ? false : viewData.isEditing();
}
@Override
- public void onBrowserEvent(Element parent, String value, Object key,
+ public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
+ Object key = context.getKey();
ViewData viewData = getViewData(key);
if (viewData != null && viewData.isEditing()) {
// Handle the edit event.
- editEvent(parent, key, viewData, event, valueUpdater);
+ editEvent(context, parent, value, viewData, event, valueUpdater);
} else {
String type = event.getType();
int keyCode = event.getKeyCode();
@@ -186,14 +188,15 @@
} else {
viewData.setEditing(true);
}
- edit(parent, value, key);
+ edit(context, parent, value);
}
}
}
@Override
- public void render(String value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, String value, SafeHtmlBuilder sb) {
// Get the view data.
+ Object key = context.getKey();
ViewData viewData = getViewData(key);
if (viewData != null && !viewData.isEditing() && value != null
&& value.equals(viewData.getText())) {
@@ -218,8 +221,8 @@
}
@Override
- public boolean resetFocus(Element parent, String value, Object key) {
- if (isEditing(parent, value, key)) {
+ public boolean resetFocus(Context context, Element parent, String value) {
+ if (isEditing(context, parent, value)) {
getInputElement(parent).focus();
return true;
}
@@ -229,12 +232,12 @@
/**
* Convert the cell to edit mode.
*
+ * @param context the {@link Context} of the cell
* @param parent the parent element
* @param value the current value
- * @param key the key of the row object
*/
- protected void edit(Element parent, String value, Object key) {
- setValue(parent, value, key);
+ protected void edit(Context context, Element parent, String value) {
+ setValue(context, parent, value);
InputElement input = getInputElement(parent);
input.focus();
input.select();
@@ -242,13 +245,14 @@
/**
* Convert the cell to non-edit mode.
- *
- * @param parent the parent element
- * @param value the current value
+ *
+ * @param context the context of the cell
+ * @param parent the parent Element
+ * @param value the value associated with the cell
*/
- private void cancel(Element parent, String value) {
+ private void cancel(Context context, Element parent, String value) {
clearInput(getInputElement(parent));
- setValue(parent, value, null);
+ setValue(context, parent, value);
}
/**
@@ -267,23 +271,24 @@
/**
* Commit the current value.
- *
- * @param parent the parent element
+ *
+ * @param context the context of the cell
+ * @param parent the parent Element
* @param viewData the {@link ViewData} object
* @param valueUpdater the {@link ValueUpdater}
*/
- private void commit(Element parent, ViewData viewData,
+ private void commit(Context context, Element parent, ViewData viewData,
ValueUpdater<String> valueUpdater) {
String value = updateViewData(parent, viewData, false);
clearInput(getInputElement(parent));
- setValue(parent, value, viewData);
+ setValue(context, parent, viewData.getOriginal());
if (valueUpdater != null) {
valueUpdater.update(value);
}
}
- private void editEvent(Element parent, Object key, ViewData viewData,
- NativeEvent event, ValueUpdater<String> valueUpdater) {
+ private void editEvent(Context context, Element parent, String value,
+ ViewData viewData, NativeEvent event, ValueUpdater<String> valueUpdater) {
String type = event.getType();
boolean keyUp = "keyup".equals(type);
boolean keyDown = "keydown".equals(type);
@@ -291,7 +296,7 @@
int keyCode = event.getKeyCode();
if (keyUp && keyCode == KeyCodes.KEY_ENTER) {
// Commit the change.
- commit(parent, viewData, valueUpdater);
+ commit(context, parent, viewData, valueUpdater);
} else if (keyUp && keyCode == KeyCodes.KEY_ESCAPE) {
// Cancel edit mode.
String originalText = viewData.getOriginal();
@@ -299,9 +304,9 @@
viewData.setText(originalText);
viewData.setEditing(false);
} else {
- setViewData(key, null);
+ setViewData(context.getKey(), null);
}
- cancel(parent, originalText);
+ cancel(context, parent, value);
} else {
// Update the text in the view data on each key.
updateViewData(parent, viewData, true);
@@ -313,7 +318,7 @@
if (Element.is(eventTarget)) {
Element target = Element.as(eventTarget);
if ("input".equals(target.getTagName().toLowerCase())) {
- commit(parent, viewData, valueUpdater);
+ commit(context, parent, viewData, valueUpdater);
}
}
}
diff --git a/user/src/com/google/gwt/cell/client/IconCellDecorator.java b/user/src/com/google/gwt/cell/client/IconCellDecorator.java
index 496ac3c..3e0c7da 100644
--- a/user/src/com/google/gwt/cell/client/IconCellDecorator.java
+++ b/user/src/com/google/gwt/cell/client/IconCellDecorator.java
@@ -1,12 +1,12 @@
/*
* Copyright 2010 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
@@ -32,7 +32,7 @@
/**
* A {@link Cell} decorator that adds an icon to another {@link Cell}.
- *
+ *
* @param <C> the type that this Cell represents
*/
public class IconCellDecorator<C> implements Cell<C> {
@@ -83,7 +83,7 @@
/**
* Construct a new {@link IconCellDecorator}. The icon and the content will be
* middle aligned by default.
- *
+ *
* @param icon the icon to use
* @param cell the cell to decorate
*/
@@ -93,7 +93,7 @@
/**
* Construct a new {@link IconCellDecorator}.
- *
+ *
* @param icon the icon to use
* @param cell the cell to decorate
* @param valign the vertical alignment attribute of the contents
@@ -122,35 +122,36 @@
return cell.handlesSelection();
}
- public boolean isEditing(Element element, C value, Object key) {
- return cell.isEditing(element, value, key);
+ public boolean isEditing(Context context, Element parent, C value) {
+ return cell.isEditing(context, getCellParent(parent), value);
}
- public void onBrowserEvent(Element parent, C value, Object key,
+ public void onBrowserEvent(Context context, Element parent, C value,
NativeEvent event, ValueUpdater<C> valueUpdater) {
- cell.onBrowserEvent(getCellParent(parent), value, key, event, valueUpdater);
+ cell.onBrowserEvent(context, getCellParent(parent), value, event,
+ valueUpdater);
}
- public void render(C value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, C value, SafeHtmlBuilder sb) {
SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
- cell.render(value, key, cellBuilder);
+ cell.render(context, value, cellBuilder);
sb.append(template.outerDiv(direction, imageWidth, isIconUsed(value)
? getIconHtml(value) : placeHolderHtml, cellBuilder.toSafeHtml()));
}
- public boolean resetFocus(Element parent, C value, Object key) {
- return cell.resetFocus(getCellParent(parent), value, key);
+ public boolean resetFocus(Context context, Element parent, C value) {
+ return cell.resetFocus(context, getCellParent(parent), value);
}
- public void setValue(Element parent, C value, Object key) {
- cell.setValue(getCellParent(parent), value, key);
+ public void setValue(Context context, Element parent, C value) {
+ cell.setValue(context, getCellParent(parent), value);
}
/**
* Get the safe HTML string that represents the icon. Override this method to
* change the icon based on the value.
- *
+ *
* @param value the value being rendered
* @return the HTML string that represents the icon
*/
@@ -162,7 +163,7 @@
* Check if the icon should be used for the value. If the icon should not be
* used, a placeholder of the same size will be used instead. The default
* implementations returns true.
- *
+ *
* @param value the value being rendered
* @return true to use the icon, false to use a placeholder
*/
@@ -172,7 +173,7 @@
/**
* Get the HTML representation of an image. Visible for testing.
- *
+ *
* @param res the {@link ImageResource} to render as HTML
* @param valign the vertical alignment
* @param isPlaceholder if true, do not include the background image
@@ -203,7 +204,7 @@
/**
* Get the parent element of the decorated cell.
- *
+ *
* @param parent the parent of this cell
* @return the decorated cell's parent
*/
diff --git a/user/src/com/google/gwt/cell/client/ImageCell.java b/user/src/com/google/gwt/cell/client/ImageCell.java
index 25f173d..18ea3c8 100644
--- a/user/src/com/google/gwt/cell/client/ImageCell.java
+++ b/user/src/com/google/gwt/cell/client/ImageCell.java
@@ -51,7 +51,7 @@
}
@Override
- public void render(String value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, String value, SafeHtmlBuilder sb) {
if (value != null) {
// The template will sanitize the URI.
sb.append(template.img(value));
diff --git a/user/src/com/google/gwt/cell/client/ImageLoadingCell.java b/user/src/com/google/gwt/cell/client/ImageLoadingCell.java
index 67a3e23..e72e7a4 100644
--- a/user/src/com/google/gwt/cell/client/ImageLoadingCell.java
+++ b/user/src/com/google/gwt/cell/client/ImageLoadingCell.java
@@ -179,7 +179,7 @@
}
@Override
- public void onBrowserEvent(Element parent, String value, Object key,
+ public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
// The loading indicator can fire its own load or error event, so we check
// that the event actually occurred on the main image.
@@ -201,7 +201,7 @@
}
@Override
- public void render(String value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, String value, SafeHtmlBuilder sb) {
// We can't use ViewData because we don't know the caching policy of the
// browser. The browser may fetch the image every time we render.
if (value != null) {
diff --git a/user/src/com/google/gwt/cell/client/ImageResourceCell.java b/user/src/com/google/gwt/cell/client/ImageResourceCell.java
index ce9fb37..c2a0c8c 100644
--- a/user/src/com/google/gwt/cell/client/ImageResourceCell.java
+++ b/user/src/com/google/gwt/cell/client/ImageResourceCell.java
@@ -40,7 +40,7 @@
}
@Override
- public void render(ImageResource value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, ImageResource value, SafeHtmlBuilder sb) {
if (value != null) {
SafeHtml html = SafeHtmlUtils.fromTrustedString(AbstractImagePrototype.create(
value).getHTML());
diff --git a/user/src/com/google/gwt/cell/client/NumberCell.java b/user/src/com/google/gwt/cell/client/NumberCell.java
index 14b301b..cdf0201 100644
--- a/user/src/com/google/gwt/cell/client/NumberCell.java
+++ b/user/src/com/google/gwt/cell/client/NumberCell.java
@@ -84,7 +84,7 @@
}
@Override
- public void render(Number value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, Number value, SafeHtmlBuilder sb) {
if (value != null) {
sb.append(renderer.render(format.format(value)));
}
diff --git a/user/src/com/google/gwt/cell/client/SafeHtmlCell.java b/user/src/com/google/gwt/cell/client/SafeHtmlCell.java
index 69f46ed..bb4109b 100644
--- a/user/src/com/google/gwt/cell/client/SafeHtmlCell.java
+++ b/user/src/com/google/gwt/cell/client/SafeHtmlCell.java
@@ -30,7 +30,7 @@
}
@Override
- public void render(SafeHtml value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, SafeHtml value, SafeHtmlBuilder sb) {
if (value != null) {
sb.append(value);
}
diff --git a/user/src/com/google/gwt/cell/client/SelectionCell.java b/user/src/com/google/gwt/cell/client/SelectionCell.java
index 79c9b76..1695d19 100644
--- a/user/src/com/google/gwt/cell/client/SelectionCell.java
+++ b/user/src/com/google/gwt/cell/client/SelectionCell.java
@@ -64,11 +64,12 @@
}
@Override
- public void onBrowserEvent(Element parent, String value, Object key,
+ public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
- super.onBrowserEvent(parent, value, key, event, valueUpdater);
+ super.onBrowserEvent(context, parent, value, event, valueUpdater);
String type = event.getType();
if ("change".equals(type)) {
+ Object key = context.getKey();
SelectElement select = parent.getFirstChild().cast();
String newValue = options.get(select.getSelectedIndex());
setViewData(key, newValue);
@@ -80,8 +81,9 @@
}
@Override
- public void render(String value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, String value, SafeHtmlBuilder sb) {
// Get the view data.
+ Object key = context.getKey();
String viewData = getViewData(key);
if (viewData != null && viewData.equals(value)) {
clearViewData(key);
diff --git a/user/src/com/google/gwt/cell/client/TextCell.java b/user/src/com/google/gwt/cell/client/TextCell.java
index 48db9eb..2df83ec 100644
--- a/user/src/com/google/gwt/cell/client/TextCell.java
+++ b/user/src/com/google/gwt/cell/client/TextCell.java
@@ -44,7 +44,7 @@
}
@Override
- public void render(SafeHtml value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, SafeHtml value, SafeHtmlBuilder sb) {
if (value != null) {
sb.append(value);
}
diff --git a/user/src/com/google/gwt/cell/client/TextInputCell.java b/user/src/com/google/gwt/cell/client/TextInputCell.java
index be1f7d5..e90d295 100644
--- a/user/src/com/google/gwt/cell/client/TextInputCell.java
+++ b/user/src/com/google/gwt/cell/client/TextInputCell.java
@@ -156,9 +156,9 @@
}
@Override
- public void onBrowserEvent(Element parent, String value, Object key,
+ public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
- super.onBrowserEvent(parent, value, key, event, valueUpdater);
+ super.onBrowserEvent(context, parent, value, event, valueUpdater);
// Ignore events that don't target the input.
InputElement input = getInputElement(parent);
@@ -168,6 +168,7 @@
}
String eventType = event.getType();
+ Object key = context.getKey();
if ("change".equals(eventType)) {
finishEditing(parent, value, key, valueUpdater);
} else if ("keyup".equals(eventType)) {
@@ -182,8 +183,9 @@
}
@Override
- public void render(String value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, String value, SafeHtmlBuilder sb) {
// Get the view data.
+ Object key = context.getKey();
ViewData viewData = getViewData(key);
if (viewData != null && viewData.getCurrentValue().equals(value)) {
clearViewData(key);
diff --git a/user/src/com/google/gwt/editor/client/adapters/ListEditorWrapper.java b/user/src/com/google/gwt/editor/client/adapters/ListEditorWrapper.java
index 18820db..b028a79 100644
--- a/user/src/com/google/gwt/editor/client/adapters/ListEditorWrapper.java
+++ b/user/src/com/google/gwt/editor/client/adapters/ListEditorWrapper.java
@@ -33,6 +33,7 @@
private final CompositeEditor.EditorChain<T, E> chain;
private final List<E> editors;
private final EditorSource<E> editorSource;
+ private final List<T> workingCopy;
public ListEditorWrapper(List<T> backing,
CompositeEditor.EditorChain<T, E> chain, EditorSource<E> editorSource) {
@@ -40,11 +41,12 @@
this.chain = chain;
this.editorSource = editorSource;
editors = new ArrayList<E>(backing.size());
+ workingCopy = new ArrayList<T>(backing);
}
@Override
public void add(int index, T element) {
- backing.add(index, element);
+ workingCopy.add(index, element);
E subEditor = editorSource.create(index);
editors.add(index, subEditor);
for (int i = index + 1, j = editors.size(); i < j; i++) {
@@ -55,13 +57,12 @@
@Override
public T get(int index) {
- return backing.get(index);
+ return workingCopy.get(index);
}
@Override
public T remove(int index) {
- // Try to mutate the list first, in case it is immutable
- T toReturn = backing.remove(index);
+ T toReturn = workingCopy.remove(index);
E subEditor = editors.remove(index);
editorSource.dispose(subEditor);
for (int i = index, j = editors.size(); i < j; i++) {
@@ -73,15 +74,14 @@
@Override
public T set(int index, T element) {
- // Try to mutate the list first, in case it is immutable
- T toReturn = backing.set(index, element);
+ T toReturn = workingCopy.set(index, element);
chain.attach(element, editors.get(index));
return toReturn;
}
@Override
public int size() {
- return backing.size();
+ return workingCopy.size();
}
/**
@@ -90,9 +90,9 @@
* {@link ListEditor#getList()}
*/
void attach() {
- editors.addAll(editorSource.create(backing.size(), 0));
- for (int i = 0, j = backing.size(); i < j; i++) {
- chain.attach(backing.get(i), editors.get(i));
+ editors.addAll(editorSource.create(workingCopy.size(), 0));
+ for (int i = 0, j = workingCopy.size(); i < j; i++) {
+ chain.attach(workingCopy.get(i), editors.get(i));
}
}
@@ -104,14 +104,16 @@
}
void flush() {
- for (int i = 0, j = backing.size(); i < j; i++) {
+ for (int i = 0, j = workingCopy.size(); i < j; i++) {
E subEditor = editors.get(i);
T value = chain.getValue(subEditor);
// Use of object-identity intentional
- if (backing.get(i) != value) {
- backing.set(i, value);
+ if (workingCopy.get(i) != value) {
+ workingCopy.set(i, value);
}
}
+ backing.clear();
+ backing.addAll(workingCopy);
}
/**
diff --git a/user/src/com/google/gwt/editor/rebind/model/ModelUtils.java b/user/src/com/google/gwt/editor/rebind/model/ModelUtils.java
index 583c49d..310b9dd 100644
--- a/user/src/com/google/gwt/editor/rebind/model/ModelUtils.java
+++ b/user/src/com/google/gwt/editor/rebind/model/ModelUtils.java
@@ -15,15 +15,14 @@
*/
package com.google.gwt.editor.rebind.model;
+import com.google.gwt.autobean.shared.ValueCodex;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.Date;
import java.util.HashSet;
import java.util.Set;
@@ -32,16 +31,12 @@
*/
public class ModelUtils {
- @SuppressWarnings("unchecked")
- static final Set<Class<?>> VALUE_TYPES = Collections.unmodifiableSet(new HashSet<Class<?>>(
- Arrays.asList(Boolean.class, Character.class, Class.class, Date.class,
- Enum.class, Number.class, String.class, Void.class)));
-
static final Set<String> VALUE_TYPE_NAMES;
static {
- Set<String> names = new HashSet<String>(VALUE_TYPES.size());
- for (Class<?> clazz : VALUE_TYPES) {
+ Set<Class<?>> valueTypes = ValueCodex.getAllValueTypes();
+ Set<String> names = new HashSet<String>(valueTypes.size());
+ for (Class<?> clazz : valueTypes) {
names.add(clazz.getName());
}
VALUE_TYPE_NAMES = Collections.unmodifiableSet(names);
@@ -110,11 +105,14 @@
if (classType == null) {
return true;
}
+ if (type.isEnum() != null) {
+ return true;
+ }
for (String valueType : VALUE_TYPE_NAMES) {
JClassType found = oracle.findType(valueType);
// null check to accommodate limited mock CompilationStates
- if (found != null && found.isAssignableFrom(classType)) {
+ if (found != null && found.equals(classType)) {
return true;
}
}
diff --git a/user/src/com/google/gwt/event/shared/HandlerManager.java b/user/src/com/google/gwt/event/shared/HandlerManager.java
index 4621491..73d181e 100644
--- a/user/src/com/google/gwt/event/shared/HandlerManager.java
+++ b/user/src/com/google/gwt/event/shared/HandlerManager.java
@@ -19,12 +19,16 @@
/**
* Manager responsible for adding handlers to event sources and firing those
- * handlers on passed in events. Primitive ancestor of {@link EventBus},
- * and used at the core of {com.google.gwt.user.client.ui.Widget}.
- *
- * @deprecated use {@link SimpleEventBus}.
+ * handlers on passed in events. Primitive ancestor of {@link EventBus}, and
+ * used at the core of {com.google.gwt.user.client.ui.Widget}.
+ * <p>
+ * While widget authors should continue to use
+ * {@link com.google.gwt.user.client.ui.Widget#addDomHandler(EventHandler, com.google.gwt.event.dom.client.DomEvent.Type)}
+ * and
+ * {@link com.google.gwt.user.client.ui.Widget#addHandler(EventHandler, Type)},
+ * application developers are strongly discouraged from using a HandlerManager
+ * instance as a global event dispatch mechanism.
*/
-@Deprecated
public class HandlerManager implements HasHandlers {
private final SimpleEventBus eventBus;
@@ -50,6 +54,7 @@
* @param source the event source
* @param fireInReverseOrder true to fire handlers in reverse order
*/
+ @SuppressWarnings("deprecation")
public HandlerManager(Object source, boolean fireInReverseOrder) {
eventBus = new SimpleEventBus(fireInReverseOrder);
this.source = source;
@@ -114,6 +119,7 @@
* @param type the handler's event type
* @return the given handler
*/
+ @SuppressWarnings("deprecation")
public <H extends EventHandler> H getHandler(GwtEvent.Type<H> type, int index) {
return eventBus.getHandler(type, index);
}
@@ -124,6 +130,7 @@
* @param type the event type
* @return the number of registered handlers
*/
+ @SuppressWarnings("deprecation")
public int getHandlerCount(Type<?> type) {
return eventBus.getHandlerCount(type);
}
@@ -134,6 +141,7 @@
* @param e the event type
* @return whether the given event type is handled
*/
+ @SuppressWarnings("deprecation")
public boolean isEventHandled(Type<?> e) {
return eventBus.isEventHandled(e);
}
diff --git a/user/src/com/google/gwt/i18n/client/DateTimeFormatInfo.java b/user/src/com/google/gwt/i18n/client/DateTimeFormatInfo.java
index a4d3fb2..6672ac8 100644
--- a/user/src/com/google/gwt/i18n/client/DateTimeFormatInfo.java
+++ b/user/src/com/google/gwt/i18n/client/DateTimeFormatInfo.java
@@ -98,7 +98,7 @@
* @param timePattern the time pattern String
* @param datePattern the data pattern String
*/
- String dateTimeShort(String datePattern, String timePattern);
+ String dateTimeShort(String timePattern, String datePattern);
/**
* Returns an array of the full era names.
diff --git a/user/src/com/google/gwt/requestfactory/server/LocatorServiceLayer.java b/user/src/com/google/gwt/requestfactory/server/LocatorServiceLayer.java
index a2922e4..d5efc04 100644
--- a/user/src/com/google/gwt/requestfactory/server/LocatorServiceLayer.java
+++ b/user/src/com/google/gwt/requestfactory/server/LocatorServiceLayer.java
@@ -17,12 +17,19 @@
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.Locator;
-import com.google.gwt.requestfactory.shared.LocatorFor;
-import com.google.gwt.requestfactory.shared.LocatorForName;
+import com.google.gwt.requestfactory.shared.ProxyFor;
+import com.google.gwt.requestfactory.shared.ProxyForName;
+import com.google.gwt.requestfactory.shared.Request;
+import com.google.gwt.requestfactory.shared.Service;
+import com.google.gwt.requestfactory.shared.ServiceLocator;
+import com.google.gwt.requestfactory.shared.ServiceName;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
/**
- * Adds support to the ServiceLayer chain for using {@link Locator} helper
- * objects.
+ * Adds support to the ServiceLayer chain for using {@link Locator} and
+ * {@link ServiceLocator} helper objects.
*/
final class LocatorServiceLayer extends ServiceLayerDecorator {
@@ -37,17 +44,15 @@
@Override
public <T extends Locator<?, ?>> T createLocator(Class<T> clazz) {
- Throwable ex;
- try {
- return clazz.newInstance();
- } catch (InstantiationException e) {
- ex = e;
- } catch (IllegalAccessException e) {
- ex = e;
- }
- return this.<T> die(ex,
- "Could not instantiate Locator %s. It is default-instantiable?",
- clazz.getCanonicalName());
+ return newInstance(clazz, Locator.class);
+ }
+
+ @Override
+ public Object createServiceInstance(Method contextMethod, Method domainMethod) {
+ Class<? extends ServiceLocator> locatorType = getTop().resolveServiceLocator(
+ contextMethod, domainMethod);
+ ServiceLocator locator = newInstance(locatorType, ServiceLocator.class);
+ return locator.getInstance(domainMethod.getDeclaringClass());
}
@Override
@@ -79,6 +84,17 @@
return doLoadDomainObject(clazz, domainId);
}
+ /**
+ * Returns true if the context method returns a {@link Request} and the domain
+ * method is non-static.
+ */
+ @Override
+ public boolean requiresServiceLocator(Method contextMethod,
+ Method domainMethod) {
+ return Request.class.isAssignableFrom(contextMethod.getReturnType())
+ && !Modifier.isStatic(domainMethod.getModifiers());
+ }
+
@Override
public Class<? extends Locator<?, ?>> resolveLocator(Class<?> domainType) {
// Find the matching BaseProxy
@@ -90,21 +106,24 @@
// Check it for annotations
Class<? extends Locator<?, ?>> locatorType;
- LocatorFor l = proxyType.getAnnotation(LocatorFor.class);
- LocatorForName ln = proxyType.getAnnotation(LocatorForName.class);
- if (l != null) {
- locatorType = l.value();
- } else if (ln != null) {
+ ProxyFor l = proxyType.getAnnotation(ProxyFor.class);
+ ProxyForName ln = proxyType.getAnnotation(ProxyForName.class);
+ if (l != null && !Locator.class.equals(l.locator())) {
+ @SuppressWarnings("unchecked")
+ Class<? extends Locator<?, ?>> found = (Class<? extends Locator<?, ?>>) l.locator();
+ locatorType = found;
+ } else if (ln != null && ln.locator().length() > 0) {
try {
@SuppressWarnings("unchecked")
Class<? extends Locator<?, ?>> found = (Class<? extends Locator<?, ?>>) Class.forName(
- ln.value(), false, domainType.getClassLoader()).asSubclass(
+ ln.locator(), false, domainType.getClassLoader()).asSubclass(
Locator.class);
locatorType = found;
} catch (ClassNotFoundException e) {
- return die(e,
- "Could not find the type specified in the @%s annotation %s",
- LocatorForName.class.getCanonicalName(), ln.value());
+ return die(
+ e,
+ "Could not find the locator type specified in the @%s annotation %s",
+ ProxyForName.class.getCanonicalName(), ln.value());
}
} else {
// No locator annotation
@@ -113,6 +132,34 @@
return locatorType;
}
+ @Override
+ public Class<? extends ServiceLocator> resolveServiceLocator(
+ Method contextMethod, Method domainMethod) {
+ Class<? extends ServiceLocator> locatorType;
+
+ // Look at the RequestContext
+ Class<?> requestContextClass = contextMethod.getDeclaringClass();
+ Service l = requestContextClass.getAnnotation(Service.class);
+ ServiceName ln = requestContextClass.getAnnotation(ServiceName.class);
+ if (l != null && !ServiceLocator.class.equals(l.locator())) {
+ locatorType = l.locator();
+ } else if (ln != null && ln.locator().length() > 0) {
+ try {
+ locatorType = Class.forName(ln.locator(), false,
+ requestContextClass.getClassLoader()).asSubclass(
+ ServiceLocator.class);
+ } catch (ClassNotFoundException e) {
+ return die(
+ e,
+ "Could not find the locator type specified in the @%s annotation %s",
+ ServiceName.class.getCanonicalName(), ln.value());
+ }
+ } else {
+ locatorType = null;
+ }
+ return locatorType;
+ }
+
private <T> Object doGetId(T domainObject) {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) domainObject.getClass();
@@ -162,4 +209,18 @@
}
return (Locator<T, I>) getTop().createLocator(locatorType);
}
+
+ private <T> T newInstance(Class<T> clazz, Class<? super T> base) {
+ Throwable ex;
+ try {
+ return clazz.newInstance();
+ } catch (InstantiationException e) {
+ ex = e;
+ } catch (IllegalAccessException e) {
+ ex = e;
+ }
+ return this.<T> die(ex,
+ "Could not instantiate %s %s. Is it default-instantiable?",
+ base.getSimpleName(), clazz.getCanonicalName());
+ }
}
diff --git a/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java b/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java
index 5dafce4..f034b1c 100644
--- a/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java
+++ b/user/src/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidator.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.requestfactory.server;
+import com.google.gwt.autobean.shared.ValueCodex;
import com.google.gwt.dev.asm.AnnotationVisitor;
import com.google.gwt.dev.asm.ClassReader;
import com.google.gwt.dev.asm.ClassVisitor;
@@ -31,8 +32,6 @@
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.EntityProxy;
import com.google.gwt.requestfactory.shared.InstanceRequest;
-import com.google.gwt.requestfactory.shared.LocatorFor;
-import com.google.gwt.requestfactory.shared.LocatorForName;
import com.google.gwt.requestfactory.shared.ProxyFor;
import com.google.gwt.requestfactory.shared.ProxyForName;
import com.google.gwt.requestfactory.shared.Request;
@@ -44,10 +43,9 @@
import java.io.IOException;
import java.io.InputStream;
+import java.lang.annotation.Annotation;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -142,6 +140,7 @@
private class DomainMapper extends EmptyVisitor {
private final ErrorContext logger;
private String domainInternalName;
+ private List<Class<? extends Annotation>> found = new ArrayList<Class<? extends Annotation>>();
private String locatorInternalName;
public DomainMapper(ErrorContext logger) {
@@ -165,65 +164,93 @@
}
}
+ /**
+ * This method examines one annotation at a time.
+ */
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
- final boolean foundLocator = desc.equals(Type.getDescriptor(LocatorFor.class));
- final boolean foundLocatorName = desc.equals(Type.getDescriptor(LocatorForName.class));
- boolean foundProxy = desc.equals(Type.getDescriptor(ProxyFor.class));
- boolean foundProxyName = desc.equals(Type.getDescriptor(ProxyForName.class));
- boolean foundService = desc.equals(Type.getDescriptor(Service.class));
- boolean foundServiceName = desc.equals(Type.getDescriptor(ServiceName.class));
+ // Set to true if the annotation should have class literal values
+ boolean expectClasses = false;
+ // Set to true if the annonation has string values
+ boolean expectNames = false;
- if (foundLocator || foundProxy || foundService) {
+ if (desc.equals(Type.getDescriptor(ProxyFor.class))) {
+ expectClasses = true;
+ found.add(ProxyFor.class);
+ } else if (desc.equals(Type.getDescriptor(ProxyForName.class))) {
+ expectNames = true;
+ found.add(ProxyForName.class);
+ } else if (desc.equals(Type.getDescriptor(Service.class))) {
+ expectClasses = true;
+ found.add(Service.class);
+ } else if (desc.equals(Type.getDescriptor(ServiceName.class))) {
+ expectNames = true;
+ found.add(ServiceName.class);
+ }
+
+ if (expectClasses) {
return new EmptyVisitor() {
@Override
public void visit(String name, Object value) {
if ("value".equals(name)) {
- String found = ((Type) value).getInternalName();
- if (foundLocator) {
- locatorInternalName = found;
- } else {
- domainInternalName = found;
- }
+ domainInternalName = ((Type) value).getInternalName();
+ } else if ("locator".equals(name)) {
+ locatorInternalName = ((Type) value).getInternalName();
}
}
};
}
- if (foundLocatorName || foundProxyName || foundServiceName) {
+ if (expectNames) {
return new EmptyVisitor() {
@Override
public void visit(String name, Object value) {
- if ("value".equals(name)) {
- String sourceName = (String) value;
-
- /*
- * The input is a source name, so we need to convert it to an
- * internal name. We'll do this by substituting dollar signs for
- * the last slash in the name until there are no more slashes.
- */
- StringBuffer desc = new StringBuffer(sourceName.replace('.', '/'));
- while (!loader.exists(desc.toString() + ".class")) {
- logger.spam("Did not find " + desc.toString());
- int idx = desc.lastIndexOf("/");
- if (idx == -1) {
- return;
- }
- desc.setCharAt(idx, '$');
- }
-
- if (foundLocatorName) {
- locatorInternalName = desc.toString();
- } else {
- domainInternalName = desc.toString();
- }
- logger.spam(domainInternalName);
+ String sourceName;
+ if ("value".equals(name) || "locator".equals(name)) {
+ sourceName = (String) value;
+ } else {
+ return;
}
+
+ /*
+ * The input is a source name, so we need to convert it to an
+ * internal name. We'll do this by substituting dollar signs for the
+ * last slash in the name until there are no more slashes.
+ */
+ StringBuffer desc = new StringBuffer(sourceName.replace('.', '/'));
+ while (!loader.exists(desc.toString() + ".class")) {
+ logger.spam("Did not find " + desc.toString());
+ int idx = desc.lastIndexOf("/");
+ if (idx == -1) {
+ return;
+ }
+ desc.setCharAt(idx, '$');
+ }
+
+ if ("locator".equals(name)) {
+ locatorInternalName = desc.toString();
+ } else {
+ domainInternalName = desc.toString();
+ }
+ logger.spam(domainInternalName);
}
};
}
return null;
}
+
+ @Override
+ public void visitEnd() {
+ // Only allow one annotation
+ if (found.size() > 1) {
+ StringBuilder sb = new StringBuilder();
+ for (Class<?> clazz : found) {
+ sb.append(" @").append(clazz.getSimpleName());
+ }
+ logger.poison("Redundant domain mapping annotations present:%s",
+ sb.toString());
+ }
+ }
}
/**
@@ -489,10 +516,7 @@
}
}
- @SuppressWarnings("unchecked")
- static final Set<Class<?>> VALUE_TYPES = Collections.unmodifiableSet(new HashSet<Class<?>>(
- Arrays.asList(Boolean.class, Character.class, Class.class, Date.class,
- Enum.class, Number.class, String.class, Void.class)));
+ static final Set<Class<?>> VALUE_TYPES = ValueCodex.getAllValueTypes();
public static void main(String[] args) {
if (args.length == 0) {
@@ -536,10 +560,10 @@
*/
private final Map<Type, Type> clientToDomainType = new HashMap<Type, Type>();
/**
- * Maps client types (e.g. FooProxy) to their locator types (e.g. FooLocator).
+ * Maps client types (e.g. FooProxy or FooContext) to their locator types
+ * (e.g. FooLocator or FooServiceLocator).
*/
private final Map<Type, Type> clientToLocatorMap = new HashMap<Type, Type>();
-
/**
* Maps domain types (e.g Foo) to client proxy types (e.g. FooAProxy,
* FooBProxy).
@@ -550,6 +574,10 @@
*/
private final Type entityProxyIntf = Type.getType(EntityProxy.class);
/**
+ * The type {@link Enum}.
+ */
+ private final Type enumType = Type.getType(Enum.class);
+ /**
* A placeholder type for client types that could not be resolved to a domain
* type.
*/
@@ -731,7 +759,8 @@
}
// Check the client method against the domain
- checkClientMethodInDomain(logger, method, domainServiceType);
+ checkClientMethodInDomain(logger, method, domainServiceType,
+ !clientToLocatorMap.containsKey(requestContextType));
maybeCheckReferredProxies(logger, method);
}
@@ -887,7 +916,7 @@
* to the server's domain type.
*/
private void checkClientMethodInDomain(ErrorContext logger, RFMethod method,
- Type domainServiceType) {
+ Type domainServiceType, boolean requireStaticMethodsForRequestType) {
logger = logger.setMethod(method);
// Create a "translated" method declaration to search for
@@ -905,7 +934,8 @@
logger.poison("The method %s is declared to return %s, but the"
+ " service method is static", method.getName(),
InstanceRequest.class.getCanonicalName());
- } else if (!isInstance && !found.isDeclaredStatic) {
+ } else if (requireStaticMethodsForRequestType && !isInstance
+ && !found.isDeclaredStatic()) {
logger.poison("The method %s is declared to return %s, but the"
+ " service method is not static", method.getName(),
Request.class.getCanonicalName());
@@ -1331,12 +1361,8 @@
return true;
}
logger = logger.setType(type);
- List<Type> types = getSupertypes(logger, type);
- for (Type t : types) {
- if (valueTypes.contains(t)) {
- valueTypes.add(type);
- return true;
- }
+ if (isAssignable(logger, enumType, type)) {
+ return true;
}
return false;
}
diff --git a/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java b/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java
index c0e1418..4ad67c1 100644
--- a/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java
+++ b/user/src/com/google/gwt/requestfactory/server/RequestFactoryServlet.java
@@ -130,7 +130,6 @@
if (DUMP_PAYLOAD) {
System.out.println(">>> " + jsonRequestString);
}
- PrintWriter writer = response.getWriter();
try {
// Check that user is logged in before proceeding
@@ -146,6 +145,8 @@
response.setHeader("userId", String.format("%s", userInfo.getId()));
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(RequestFactory.JSON_CONTENT_TYPE_UTF8);
+ // The Writer must be obtained after setting the content type
+ PrintWriter writer = response.getWriter();
writer.print(payload);
writer.flush();
}
diff --git a/user/src/com/google/gwt/requestfactory/server/ServiceLayer.java b/user/src/com/google/gwt/requestfactory/server/ServiceLayer.java
index a906e9f..8cd93a4 100644
--- a/user/src/com/google/gwt/requestfactory/server/ServiceLayer.java
+++ b/user/src/com/google/gwt/requestfactory/server/ServiceLayer.java
@@ -17,6 +17,7 @@
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.Locator;
+import com.google.gwt.requestfactory.shared.ServiceLocator;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
@@ -109,6 +110,17 @@
public abstract <T extends Locator<?, ?>> T createLocator(Class<T> clazz);
/**
+ * Create an instance of a service object that can be used as the target for
+ * the given method invocation.
+ *
+ * @param contextMethod a method defined in a RequestContext
+ * @param domainMethod the method that the service object must implement
+ * @return an instance of the requested service object
+ */
+ public abstract Object createServiceInstance(Method contextMethod,
+ Method domainMethod);
+
+ /**
* Return the persistent id for a domain object. May return {@code null} to
* indicate that the domain object has not been persisted. The value returned
* from this method must be a simple type (e.g. Integer, String) or a domain
@@ -209,6 +221,18 @@
List<Object> domainIds);
/**
+ * Determines if the invocation of a domain method requires a
+ * {@link ServiceLocator} as the 0th parameter when passed into
+ * {@link #invoke(Method, Object...)}.
+ *
+ * @param contextMethod a method defined in a RequestContext
+ * @param domainMethod a domain method
+ * @return {@code true} if a ServiceLocator is required
+ */
+ public abstract boolean requiresServiceLocator(Method contextMethod,
+ Method domainMethod);
+
+ /**
* Given a type token previously returned from
* {@link #resolveTypeToken(Class)}, return the Class literal associated with
* the token.
@@ -278,6 +302,19 @@
String requestContextClass, String methodName);
/**
+ * Given a RequestContext method declaration, resolve the
+ * {@link ServiceLocator} that should be used when invoking the domain method.
+ * This method will only be called if {@link #requiresServiceLocator(Method)}
+ * returned {@code true} for the associated domain method.
+ *
+ * @param contextMethod a RequestContext method declaration
+ * @param domainMethod the domain method that will be invoked
+ * @return the type of ServiceLocator to use
+ */
+ public abstract Class<? extends ServiceLocator> resolveServiceLocator(
+ Method contextMethod, Method domainMethod);
+
+ /**
* Return a string used to represent the given type in the wire protocol.
*
* @param proxyType a client-side EntityProxy or ValueProxy type
diff --git a/user/src/com/google/gwt/requestfactory/server/ServiceLayerCache.java b/user/src/com/google/gwt/requestfactory/server/ServiceLayerCache.java
index 887d49c..0c89f75 100644
--- a/user/src/com/google/gwt/requestfactory/server/ServiceLayerCache.java
+++ b/user/src/com/google/gwt/requestfactory/server/ServiceLayerCache.java
@@ -17,6 +17,7 @@
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.Locator;
+import com.google.gwt.requestfactory.shared.ServiceLocator;
import com.google.gwt.rpc.server.Pair;
import java.lang.ref.SoftReference;
@@ -42,20 +43,27 @@
private static SoftReference<Map<Method, Map<Object, Object>>> methodCache;
private static final Method createLocator;
+ private static final Method createServiceInstance;
private static final Method getIdType;
private static final Method getRequestReturnType;
+ private static final Method requiresServiceLocator;
private static final Method resolveClass;
private static final Method resolveClientType;
private static final Method resolveDomainClass;
private static final Method resolveDomainMethod;
private static final Method resolveLocator;
private static final Method resolveRequestContextMethod;
+ private static final Method resolveServiceLocator;
private static final Method resolveTypeToken;
static {
createLocator = getMethod("createLocator", Class.class);
+ createServiceInstance = getMethod("createServiceInstance", Method.class,
+ Method.class);
getIdType = getMethod("getIdType", Class.class);
getRequestReturnType = getMethod("getRequestReturnType", Method.class);
+ requiresServiceLocator = getMethod("requiresServiceLocator", Method.class,
+ Method.class);
resolveClass = getMethod("resolveClass", String.class);
resolveClientType = getMethod("resolveClientType", Class.class,
Class.class, boolean.class);
@@ -64,6 +72,8 @@
resolveLocator = getMethod("resolveLocator", Class.class);
resolveRequestContextMethod = getMethod("resolveRequestContextMethod",
String.class, String.class);
+ resolveServiceLocator = getMethod("resolveServiceLocator", Method.class,
+ Method.class);
resolveTypeToken = getMethod("resolveTypeToken", Class.class);
}
@@ -98,6 +108,12 @@
}
@Override
+ public Object createServiceInstance(Method contextMethod, Method domainMethod) {
+ return getOrCache(createServiceInstance, new Pair<Method, Method>(
+ contextMethod, domainMethod), Object.class, contextMethod, domainMethod);
+ }
+
+ @Override
public Class<?> getIdType(Class<?> domainType) {
return getOrCache(getIdType, domainType, Class.class, domainType);
}
@@ -109,18 +125,26 @@
}
@Override
+ public boolean requiresServiceLocator(Method contextMethod,
+ Method domainMethod) {
+ return getOrCache(requiresServiceLocator, new Pair<Method, Method>(
+ contextMethod, domainMethod), Boolean.class, contextMethod,
+ domainMethod);
+ }
+
+ @Override
public Class<? extends BaseProxy> resolveClass(String typeToken) {
Class<?> found = getOrCache(resolveClass, typeToken, Class.class, typeToken);
return found.asSubclass(BaseProxy.class);
}
@Override
- @SuppressWarnings("unchecked")
public <T> Class<? extends T> resolveClientType(Class<?> domainClass,
Class<T> clientType, boolean required) {
- return getOrCache(resolveClientType, new Pair<Class<?>, Class<?>>(
- domainClass, clientType), Class.class, domainClass, clientType,
- required);
+ Class<?> clazz = getOrCache(resolveClientType,
+ new Pair<Class<?>, Class<?>>(domainClass, clientType), Class.class,
+ domainClass, clientType, required);
+ return clazz == null ? null : clazz.asSubclass(clientType);
}
@Override
@@ -149,6 +173,15 @@
}
@Override
+ public Class<? extends ServiceLocator> resolveServiceLocator(
+ Method contextMethod, Method domainMethod) {
+ Class<?> clazz = getOrCache(resolveServiceLocator,
+ new Pair<Method, Method>(contextMethod, domainMethod), Class.class,
+ contextMethod, domainMethod);
+ return clazz == null ? null : clazz.asSubclass(ServiceLocator.class);
+ }
+
+ @Override
public String resolveTypeToken(Class<? extends BaseProxy> domainClass) {
return getOrCache(resolveTypeToken, domainClass, String.class, domainClass);
}
diff --git a/user/src/com/google/gwt/requestfactory/server/ServiceLayerDecorator.java b/user/src/com/google/gwt/requestfactory/server/ServiceLayerDecorator.java
index b9a2248..c642d94 100644
--- a/user/src/com/google/gwt/requestfactory/server/ServiceLayerDecorator.java
+++ b/user/src/com/google/gwt/requestfactory/server/ServiceLayerDecorator.java
@@ -17,6 +17,7 @@
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.Locator;
+import com.google.gwt.requestfactory.shared.ServiceLocator;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -54,6 +55,11 @@
}
@Override
+ public Object createServiceInstance(Method contextMethod, Method domainMethod) {
+ return getNext().createServiceInstance(contextMethod, domainMethod);
+ }
+
+ @Override
public Object getId(Object domainObject) {
return getNext().getId(domainObject);
}
@@ -100,6 +106,12 @@
}
@Override
+ public boolean requiresServiceLocator(Method contextMethod,
+ Method domainMethod) {
+ return getNext().requiresServiceLocator(contextMethod, domainMethod);
+ }
+
+ @Override
public Class<? extends BaseProxy> resolveClass(String typeToken) {
return getNext().resolveClass(typeToken);
}
@@ -133,6 +145,12 @@
}
@Override
+ public Class<? extends ServiceLocator> resolveServiceLocator(
+ Method contextMethod, Method domainMethod) {
+ return getNext().resolveServiceLocator(contextMethod, domainMethod);
+ }
+
+ @Override
public String resolveTypeToken(Class<? extends BaseProxy> proxyType) {
return getNext().resolveTypeToken(proxyType);
}
diff --git a/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java b/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java
index 4be0769..07fe1f5 100644
--- a/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java
+++ b/user/src/com/google/gwt/requestfactory/server/SimpleRequestProcessor.java
@@ -27,6 +27,7 @@
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.EntityProxyId;
import com.google.gwt.requestfactory.shared.InstanceRequest;
+import com.google.gwt.requestfactory.shared.Request;
import com.google.gwt.requestfactory.shared.ServerFailure;
import com.google.gwt.requestfactory.shared.WriteOperation;
import com.google.gwt.requestfactory.shared.impl.BaseProxyCategory;
@@ -47,7 +48,6 @@
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
@@ -346,7 +346,7 @@
*/
private List<Object> decodeInvocationArguments(RequestState source,
InvocationMessage invocation, Method contextMethod, Method domainMethod) {
- boolean isStatic = Modifier.isStatic(domainMethod.getModifiers());
+ boolean isStatic = Request.class.isAssignableFrom(contextMethod.getReturnType());
int baseLength = contextMethod.getParameterTypes().length;
int length = baseLength + (isStatic ? 0 : 1);
int offset = isStatic ? 0 : 1;
@@ -418,9 +418,16 @@
+ invocation.getOperation(), null);
}
- // Invoke it
+ // Compute the arguments
List<Object> args = decodeInvocationArguments(state, invocation,
contextMethod, domainMethod);
+ // Possibly use a ServiceLocator
+ if (service.requiresServiceLocator(contextMethod, domainMethod)) {
+ Object serviceInstance = service.createServiceInstance(contextMethod,
+ domainMethod);
+ args.add(0, serviceInstance);
+ }
+ // Invoke it
Object returnValue = service.invoke(domainMethod, args.toArray());
// Convert domain object to client object
diff --git a/user/src/com/google/gwt/requestfactory/shared/Locator.java b/user/src/com/google/gwt/requestfactory/shared/Locator.java
index a88032b..3516984 100644
--- a/user/src/com/google/gwt/requestfactory/shared/Locator.java
+++ b/user/src/com/google/gwt/requestfactory/shared/Locator.java
@@ -29,7 +29,7 @@
* @param <T> the type of domain object the Locator will operate on
* @param <I> the type of object the Locator expects to use as an id for the
* domain object
- * @see LocatorFor
+ * @see ProxyFor#locator()
*/
public abstract class Locator<T, I> {
/**
diff --git a/user/src/com/google/gwt/requestfactory/shared/LocatorFor.java b/user/src/com/google/gwt/requestfactory/shared/LocatorFor.java
deleted file mode 100644
index 2c237fd..0000000
--- a/user/src/com/google/gwt/requestfactory/shared/LocatorFor.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2010 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.requestfactory.shared;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation on BaseProxy classes specifying the domain (server-side) object
- * {@link Locator}. Specifying an explicit {@code Locator} removes the
- * requirement to have a {@code findFoo()}, {@code getId()}, and
- * {@code getVersion()} method in the domain object type.
- *
- * @see LocatorForName
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface LocatorFor {
- Class<? extends Locator<?, ?>> value();
-}
diff --git a/user/src/com/google/gwt/requestfactory/shared/LocatorForName.java b/user/src/com/google/gwt/requestfactory/shared/LocatorForName.java
deleted file mode 100644
index f537cf4..0000000
--- a/user/src/com/google/gwt/requestfactory/shared/LocatorForName.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2010 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.requestfactory.shared;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation on BaseProxy classes specifying the domain (server-side) object
- * {@link Locator}. This annotation can be used in place of {@link LocatorFor}
- * if the domain Locator is not available to the GWT compiler or DevMode
- * runtime.
- *
- * @see LocatorFor
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface LocatorForName {
- String value();
-}
diff --git a/user/src/com/google/gwt/requestfactory/shared/ProxyFor.java b/user/src/com/google/gwt/requestfactory/shared/ProxyFor.java
index 4da1afe..38f6df6 100644
--- a/user/src/com/google/gwt/requestfactory/shared/ProxyFor.java
+++ b/user/src/com/google/gwt/requestfactory/shared/ProxyFor.java
@@ -21,13 +21,22 @@
import java.lang.annotation.Target;
/**
- * Annotation on EntityProxy classes specifying the domain (server-side) object
- * type.
+ * Annotation on EntityProxy and ValueProxy classes specifying the domain
+ * (server-side) object type.
*
* @see ProxyForName
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ProxyFor {
+ /**
+ * The domain type that the proxy is mapped to.
+ */
Class<?> value();
+
+ /**
+ * An optional {@link Locator} that provides instances of the domain objects.
+ */
+ @SuppressWarnings("rawtypes")
+ Class<? extends Locator> locator() default Locator.class;
}
diff --git a/user/src/com/google/gwt/requestfactory/shared/ProxyForName.java b/user/src/com/google/gwt/requestfactory/shared/ProxyForName.java
index fa3f5bd..5eb5594 100644
--- a/user/src/com/google/gwt/requestfactory/shared/ProxyForName.java
+++ b/user/src/com/google/gwt/requestfactory/shared/ProxyForName.java
@@ -28,5 +28,14 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ProxyForName {
+ /**
+ * The name of the domain type that the proxy is mapped to.
+ */
String value();
+
+ /**
+ * An optional name of a {@link Locator} that provides instances of the domain
+ * objects.
+ */
+ String locator() default "";
}
diff --git a/user/src/com/google/gwt/requestfactory/shared/Service.java b/user/src/com/google/gwt/requestfactory/shared/Service.java
index 29d8829..de14983 100644
--- a/user/src/com/google/gwt/requestfactory/shared/Service.java
+++ b/user/src/com/google/gwt/requestfactory/shared/Service.java
@@ -29,5 +29,16 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Service {
+ /**
+ * The domain type that provides the implementations for the methods defined
+ * in the RequestContext.
+ */
Class<?> value();
+
+ /**
+ * An optional {@link ServiceLocator} that provides instances of service
+ * objects used when invoking instance methods on the type returned by
+ * {@link #value()}.
+ */
+ Class<? extends ServiceLocator> locator() default ServiceLocator.class;
}
diff --git a/user/src/com/google/gwt/requestfactory/shared/ServiceLocator.java b/user/src/com/google/gwt/requestfactory/shared/ServiceLocator.java
new file mode 100644
index 0000000..dfa841d
--- /dev/null
+++ b/user/src/com/google/gwt/requestfactory/shared/ServiceLocator.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010 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.requestfactory.shared;
+
+/**
+ * A ServiceLocator provides instances of a type specified by a {@link Service}
+ * when {@link Request} methods declared in a {@link RequestContext}are mapped
+ * onto instance (non-static) methods.
+ * <p>
+ * ServiceLocator subtypes must be default instantiable (i.e. public static
+ * types with a no-arg constructor). Instances of ServiceLocators may be
+ * retained and reused by the RequestFactory service layer.
+ *
+ * @see Service#locator()
+ */
+public interface ServiceLocator {
+ /**
+ * Returns an instance of the service object.
+ *
+ * @param clazz the requested type of service object
+ * @return an instance of the service object
+ */
+ Object getInstance(Class<?> clazz);
+}
diff --git a/user/src/com/google/gwt/requestfactory/shared/ServiceName.java b/user/src/com/google/gwt/requestfactory/shared/ServiceName.java
index beb72b6..464c032 100644
--- a/user/src/com/google/gwt/requestfactory/shared/ServiceName.java
+++ b/user/src/com/google/gwt/requestfactory/shared/ServiceName.java
@@ -28,5 +28,16 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ServiceName {
+ /**
+ * The binary name of the domain type that provides the implementations for
+ * the methods defined in the RequestContext.
+ */
String value();
+
+ /**
+ * An optional binary name of a {@link ServiceLocator} that provides instances
+ * of service objects used when invoking instance methods on the type returned
+ * by {@link #value()}.
+ */
+ String locator() default "";
}
diff --git a/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestContext.java b/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestContext.java
index 2a45831..839f4ee 100644
--- a/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestContext.java
+++ b/user/src/com/google/gwt/requestfactory/shared/impl/AbstractRequestContext.java
@@ -434,7 +434,10 @@
if (properties.containsKey(propertyName)) {
Splittable raw = properties.get(propertyName);
Object decoded = ValueCodex.decode(ctx.getType(), raw);
- // Hack for Date, consider generalizing for "custom serializers"
+ /*
+ * Hack for Date subtypes, consider generalizing for
+ * "custom serializers"
+ */
if (decoded != null && Date.class.equals(ctx.getType())) {
decoded = new DatePoser((Date) decoded);
}
diff --git a/user/src/com/google/gwt/text/client/DateTimeFormatRenderer.java b/user/src/com/google/gwt/text/client/DateTimeFormatRenderer.java
index 9a8699b..78af84d 100644
--- a/user/src/com/google/gwt/text/client/DateTimeFormatRenderer.java
+++ b/user/src/com/google/gwt/text/client/DateTimeFormatRenderer.java
@@ -47,6 +47,7 @@
* Create an instance with the given format and time zone.
*/
public DateTimeFormatRenderer(DateTimeFormat format, TimeZone timeZone) {
+ assert format != null;
this.format = format;
this.timeZone = timeZone;
}
diff --git a/user/src/com/google/gwt/text/client/DoubleParser.java b/user/src/com/google/gwt/text/client/DoubleParser.java
index c3977dd..dca4195 100644
--- a/user/src/com/google/gwt/text/client/DoubleParser.java
+++ b/user/src/com/google/gwt/text/client/DoubleParser.java
@@ -46,7 +46,7 @@
}
try {
- return Math.rint(NumberFormat.getDecimalFormat().parse(object.toString()));
+ return NumberFormat.getDecimalFormat().parse(object.toString());
} catch (NumberFormatException e) {
throw new ParseException(e.getMessage(), 0);
}
diff --git a/user/src/com/google/gwt/text/client/NumberFormatRenderer.java b/user/src/com/google/gwt/text/client/NumberFormatRenderer.java
new file mode 100644
index 0000000..b6e1e88
--- /dev/null
+++ b/user/src/com/google/gwt/text/client/NumberFormatRenderer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010 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.text.client;
+
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.text.shared.AbstractRenderer;
+
+/**
+ * Renders {@link Number} objects with a {@link NumberFormat}.
+ */
+public class NumberFormatRenderer extends AbstractRenderer<Number> {
+ private final NumberFormat format;
+
+ /**
+ * Create an instance using {@link NumberFormat#getDecimalFormat()}.
+ */
+ public NumberFormatRenderer() {
+ this(NumberFormat.getDecimalFormat());
+ }
+
+ /**
+ * Create an instance with the given format.
+ */
+ public NumberFormatRenderer(NumberFormat format) {
+ this.format = format;
+ }
+
+ public String render(Number object) {
+ if (object == null) {
+ return "";
+ }
+ return format.format(object);
+ }
+}
diff --git a/user/src/com/google/gwt/uibinder/client/UiChild.java b/user/src/com/google/gwt/uibinder/client/UiChild.java
index 3f11958..d9bca54 100644
--- a/user/src/com/google/gwt/uibinder/client/UiChild.java
+++ b/user/src/com/google/gwt/uibinder/client/UiChild.java
@@ -42,14 +42,15 @@
*
* @UiChild MyWidget#addCustomChild(Widget w) </code> and
*
- * <pre>
- * <p:MyWidget>
- * <p:customchild>
- * <g:SomeWidget />
- * </p:customchild>
- * </p:MyWidget>
- * </pre> would invoke the <code>addCustomChild</code> function to add
- * an instance of SomeWidget.
+ * <pre>
+ * <p:MyWidget>
+ * <p:customchild>
+ * <g:SomeWidget />
+ * </p:customchild>
+ * </p:MyWidget>
+ * </pre>
+ * would invoke the <code>addCustomChild</code> function to add an instance of
+ * SomeWidget.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/DateLabelParser.java b/user/src/com/google/gwt/uibinder/elementparsers/DateLabelParser.java
new file mode 100644
index 0000000..1359664
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/elementparsers/DateLabelParser.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2010 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.uibinder.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.core.ext.typeinfo.TypeOracleException;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.TimeZone;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
+import com.google.gwt.uibinder.rebind.UiBinderWriter;
+import com.google.gwt.uibinder.rebind.XMLElement;
+
+/**
+ * Parses {@link com.google.gwt.user.client.ui.DateLabel} widgets.
+ */
+public class DateLabelParser implements ElementParser {
+
+ static final String AT_MOST_ONE_SPECIFIED_FORMAT = "May have at most one of format, predefinedFormat and customFormat.";
+ static final String AT_MOST_ONE_SPECIFIED_TIME_ZONE = "May have at most one of timezone and timezoneOffset.";
+ static final String NO_TIMEZONE_WITHOUT_SPECIFIED_FORMAT = "May not specify a time zone if no format is given.";
+
+ public void parse(XMLElement elem, String fieldName, JClassType type,
+ UiBinderWriter writer) throws UnableToCompleteException {
+ boolean supportsTimeZone = hasDateTimeFormatAndTimeZoneConstructor(
+ writer.getOracle(), type);
+ if (hasDateTimeFormatConstructor(writer.getOracle(), type)
+ || supportsTimeZone) {
+ String format = consumeFormat(elem, writer);
+
+ if (format != null) {
+ String timeZone = (supportsTimeZone ? consumeTimeZone(elem, writer)
+ : null);
+
+ writer.setFieldInitializerAsConstructor(fieldName, type, makeArgs(
+ format, timeZone));
+ } else if (supportsTimeZone && hasTimeZone(elem)) {
+ writer.die(elem, NO_TIMEZONE_WITHOUT_SPECIFIED_FORMAT);
+ }
+ }
+ }
+
+ private String consumeFormat(XMLElement elem, UiBinderWriter writer)
+ throws UnableToCompleteException {
+ String format = elem.consumeAttribute("format",
+ writer.getOracle().findType(DateTimeFormat.class.getCanonicalName()));
+ String predefinedFormat = elem.consumeAttribute("predefinedFormat",
+ writer.getOracle().findType(PredefinedFormat.class.getCanonicalName()));
+ String customFormat = elem.consumeStringAttribute("customFormat");
+
+ if (format != null) {
+ if (predefinedFormat != null || customFormat != null) {
+ writer.die(elem, AT_MOST_ONE_SPECIFIED_FORMAT);
+ }
+ return format;
+ }
+ if (predefinedFormat != null) {
+ if (customFormat != null) {
+ writer.die(elem, AT_MOST_ONE_SPECIFIED_FORMAT);
+ }
+ return makeGetFormat(predefinedFormat);
+ }
+ if (customFormat != null) {
+ return makeGetFormat(customFormat);
+ }
+ return null;
+ }
+
+ private String consumeTimeZone(XMLElement elem, UiBinderWriter writer)
+ throws UnableToCompleteException {
+ String timeZone = elem.consumeAttribute("timezone",
+ writer.getOracle().findType(TimeZone.class.getCanonicalName()));
+ String timeZoneOffset = elem.consumeAttribute("timezoneOffset",
+ getIntType(writer.getOracle()));
+ if (timeZone != null && timeZoneOffset != null) {
+ writer.die(elem, AT_MOST_ONE_SPECIFIED_TIME_ZONE);
+ }
+ if (timeZone != null) {
+ return timeZone;
+ }
+ if (timeZoneOffset != null) {
+ return TimeZone.class.getCanonicalName() + ".createTimeZone("
+ + timeZoneOffset + ")";
+ }
+ return null;
+ }
+
+ private JType getIntType(TypeOracle oracle) {
+ try {
+ return oracle.parse("int");
+ } catch (TypeOracleException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private boolean hasDateTimeFormatAndTimeZoneConstructor(
+ TypeOracle typeOracle, JClassType type) {
+ JType dateTimeFormatType = typeOracle.findType(DateTimeFormat.class.getName());
+ JType timeZoneType = typeOracle.findType(TimeZone.class.getName());
+ return type.findConstructor(new JType[] {dateTimeFormatType, timeZoneType}) != null;
+ }
+
+ private boolean hasDateTimeFormatConstructor(TypeOracle typeOracle,
+ JClassType type) {
+ JType dateTimeFormatType = typeOracle.findType(DateTimeFormat.class.getName());
+ return type.findConstructor(new JType[] {dateTimeFormatType}) != null;
+ }
+
+ private boolean hasTimeZone(XMLElement elem) {
+ return elem.hasAttribute("timezone") || elem.hasAttribute("timezoneOffset");
+ }
+
+ private String[] makeArgs(String format, String timeZone) {
+ if (timeZone == null) {
+ return new String[] {format};
+ }
+ return new String[] {format, timeZone};
+ }
+
+ private String makeGetFormat(String format) {
+ return DateTimeFormat.class.getCanonicalName() + ".getFormat(" + format
+ + ")";
+ }
+}
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/NumberLabelParser.java b/user/src/com/google/gwt/uibinder/elementparsers/NumberLabelParser.java
new file mode 100644
index 0000000..5ff6656
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/elementparsers/NumberLabelParser.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2010 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.uibinder.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.i18n.client.CurrencyData;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.uibinder.rebind.UiBinderWriter;
+import com.google.gwt.uibinder.rebind.XMLElement;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Parses {@link com.google.gwt.user.client.ui.DateLabel} widgets.
+ */
+public class NumberLabelParser implements ElementParser {
+
+ static final String AT_MOST_ONE_SPECIFIED_FORMAT = "May have only one of format, predefinedFormat and customFormat.";
+ static final String AT_MOST_ONE_SPECIFIED_CURRENCY = "May have only one of currencyData and customCode.";
+ static final String NO_CURRENCY_WITH_FORMAT = "May not specify both a NumberFormat and a currency code.";
+ static final String NO_CURRENCY_WITHOUT_SPECIFIED_FORMAT = "May not specify a currency code if no format is given.";
+ static final String NO_CURRENCY_WITH_PREDEFINED_FORMAT = "May not specify a currency code with a predefined format (except the CURRENCY format)";
+ static final String UNKNOWN_PREDEFINED_FORMAT = "Unknown predefined format: %s";
+
+ private static final Map<String, String> predefinedFormats;
+
+ static {
+ String prefix = NumberFormat.class.getCanonicalName();
+ Map<String, String> formats = new HashMap<String, String>(4);
+ formats.put("DECIMAL", prefix + ".getDecimalFormat()");
+ formats.put("PERCENT", prefix + ".getPercentFormat()");
+ formats.put("SCIENTIFIC", prefix + ".getScientificFormat()");
+ // CURRENCY is special-cased in consumeFormat.
+ predefinedFormats = Collections.unmodifiableMap(formats);
+ }
+
+ public void parse(XMLElement elem, String fieldName, JClassType type,
+ UiBinderWriter writer) throws UnableToCompleteException {
+ if (hasNumberFormatConstructor(writer.getOracle(), type)) {
+ String format = consumeFormat(elem, writer);
+
+ if (format != null) {
+ writer.setFieldInitializerAsConstructor(fieldName, type, format);
+ }
+ }
+ }
+
+ private String consumeCurrency(XMLElement elem, UiBinderWriter writer)
+ throws UnableToCompleteException {
+ String currencyData = elem.consumeAttribute("currencyData",
+ writer.getOracle().findType(CurrencyData.class.getCanonicalName()));
+ String currencyCode = elem.consumeStringAttribute("currencyCode");
+
+ if (currencyData != null && currencyCode != null) {
+ writer.die(elem, AT_MOST_ONE_SPECIFIED_CURRENCY);
+ }
+ return currencyData != null ? currencyData : currencyCode;
+ }
+
+ private String consumeFormat(XMLElement elem, UiBinderWriter writer)
+ throws UnableToCompleteException {
+ String format = elem.consumeAttribute("format",
+ writer.getOracle().findType(DateTimeFormat.class.getCanonicalName()));
+ String predefinedFormat = elem.consumeRawAttribute("predefinedFormat");
+ String customFormat = elem.consumeStringAttribute("customFormat");
+
+ if (format != null) {
+ if (predefinedFormat != null || customFormat != null) {
+ writer.die(elem, AT_MOST_ONE_SPECIFIED_FORMAT);
+ }
+ if (hasCurrency(elem)) {
+ writer.die(elem, NO_CURRENCY_WITH_FORMAT);
+ }
+ return format;
+ }
+ if (predefinedFormat != null) {
+ if (customFormat != null) {
+ writer.die(elem, AT_MOST_ONE_SPECIFIED_FORMAT);
+ }
+ if ("CURRENCY".equals(predefinedFormat)) {
+ String currency = consumeCurrency(elem, writer);
+ return NumberFormat.class.getCanonicalName() + ".getCurrencyFormat("
+ + (currency != null ? currency : "") + ")";
+ }
+ if (hasCurrency(elem)) {
+ writer.die(elem, NO_CURRENCY_WITH_PREDEFINED_FORMAT);
+ }
+ String f = predefinedFormats.get(predefinedFormat);
+ if (f == null) {
+ writer.die(elem, UNKNOWN_PREDEFINED_FORMAT, predefinedFormat);
+ }
+ return f;
+ }
+ if (customFormat != null) {
+ String currency = consumeCurrency(elem, writer);
+ return NumberFormat.class.getCanonicalName() + ".getFormat(" + customFormat
+ + (currency != null ? ", " + currency : "") + ")";
+ }
+ if (hasCurrency(elem)) {
+ writer.die(elem, NO_CURRENCY_WITHOUT_SPECIFIED_FORMAT);
+ }
+ return null;
+ }
+
+ private boolean hasCurrency(XMLElement elem) {
+ return elem.hasAttribute("currencyData")
+ || elem.hasAttribute("currencyCode");
+ }
+
+ private boolean hasNumberFormatConstructor(TypeOracle typeOracle,
+ JClassType type) {
+ JType numberFormatType = typeOracle.findType(NumberFormat.class.getName());
+ return type.findConstructor(new JType[] {numberFormatType}) != null;
+ }
+}
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
index bc5c3a3..4297a32 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
@@ -264,10 +264,10 @@
/* Perhaps it is provided via @UiField */
if (ownerField != null) {
- if (!resourceType.equals(ownerField.getType().getRawType())) {
+ if (!resourceType.getErasedType().equals(ownerField.getType().getRawType()
+ .getErasedType())) {
writer.die(elem, "Type must match %s", ownerField);
}
-
if (ownerField.isProvided()) {
String initializer;
if (writer.getDesignTime().isDesignTime()) {
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
index e807ac6..a7589b5 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
@@ -998,6 +998,8 @@
addWidgetParser("ListBox");
addWidgetParser("Grid");
addWidgetParser("HasAlignment");
+ addWidgetParser("DateLabel");
+ addWidgetParser("NumberLabel");
}
/**
diff --git a/user/src/com/google/gwt/user/cellview/client/CellBrowser.java b/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
index 1776e45..d92b913 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
@@ -17,6 +17,7 @@
import com.google.gwt.animation.client.Animation;
import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
@@ -300,7 +301,8 @@
}
SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
- cell.render(value, getValueKey(value), cellBuilder);
+ Context context = new Context(i, 0, getValueKey(value));
+ cell.render(context, value, cellBuilder);
// Figure out which image to use.
SafeHtml image;
diff --git a/user/src/com/google/gwt/user/cellview/client/CellList.java b/user/src/com/google/gwt/user/cellview/client/CellList.java
index 9034ae3..2c557d5 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellList.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellList.java
@@ -16,6 +16,7 @@
package com.google.gwt.user.cellview.client;
import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
@@ -289,18 +290,19 @@
/**
* Fire an event to the cell.
- *
+ *
+ * @param context the {@link Context} of the cell
* @param event the event that was fired
* @param parent the parent of the cell
* @param value the value of the cell
*/
- protected void fireEventToCell(Event event, Element parent, T value) {
+ protected void fireEventToCell(Context context, Event event, Element parent,
+ T value) {
Set<String> consumedEvents = cell.getConsumedEvents();
if (consumedEvents != null && consumedEvents.contains(event.getType())) {
- Object key = getValueKey(value);
- boolean cellWasEditing = cell.isEditing(parent, value, key);
- cell.onBrowserEvent(parent, value, key, event, valueUpdater);
- cellIsEditing = cell.isEditing(parent, value, key);
+ boolean cellWasEditing = cell.isEditing(context, parent, value);
+ cell.onBrowserEvent(context, parent, value, event, valueUpdater);
+ cellIsEditing = cell.isEditing(context, parent, value);
if (cellWasEditing && !cellIsEditing) {
CellBasedWidgetImpl.get().resetFocus(new Scheduler.ScheduledCommand() {
public void execute() {
@@ -393,8 +395,9 @@
|| KeyboardSelectionPolicy.BOUND_TO_SELECTION == getKeyboardSelectionPolicy();
Element cellParent = getCellParent(cellTarget);
T value = getVisibleItem(indexOnPage);
+ Context context = new Context(idx, 0, getValueKey(value));
CellPreviewEvent<T> previewEvent = CellPreviewEvent.fire(this, event,
- this, indexOnPage, value, cellIsEditing, isSelectionHandled);
+ this, context, value, cellIsEditing, isSelectionHandled);
if (isClick && !cellIsEditing && !isSelectionHandled) {
doSelection(event, value, indexOnPage);
}
@@ -412,7 +415,7 @@
// Fire the event to the cell if the list has not been refreshed.
if (!previewEvent.isCanceled()) {
- fireEventToCell(event, cellParent, value);
+ fireEventToCell(context, event, cellParent, value);
}
}
}
@@ -448,7 +451,8 @@
}
SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
- cell.render(value, getValueKey(value), cellBuilder);
+ Context context = new Context(i, 0, getValueKey(value));
+ cell.render(context, value, cellBuilder);
if (i == keyboardSelectedRow) {
// This is the focused item.
@@ -477,8 +481,8 @@
Element rowElem = getKeyboardSelectedElement();
Element cellParent = getCellParent(rowElem);
T value = getVisibleItem(row);
- Object key = getValueKey(value);
- return cell.resetFocus(cellParent, value, key);
+ Context context = new Context(row + getPageStart(), 0, getValueKey(value));
+ return cell.resetFocus(context, cellParent, value);
}
return false;
}
diff --git a/user/src/com/google/gwt/user/cellview/client/CellTable.java b/user/src/com/google/gwt/user/cellview/client/CellTable.java
index 31517bd..0c5e6a6 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellTable.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellTable.java
@@ -16,18 +16,19 @@
package com.google.gwt.user.cellview.client;
import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.NodeList;
+import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableColElement;
import com.google.gwt.dom.client.TableElement;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.dom.client.TableSectionElement;
-import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.resources.client.ClientBundle;
@@ -292,7 +293,6 @@
@Template("<td class=\"{0}\" align=\"{1}\" valign=\"{2}\">{3}</td>")
SafeHtml tdBothAlign(String classes, String hAlign, String vAlign,
-
SafeHtml contents);
@Template("<td class=\"{0}\" align=\"{1}\">{2}</td>")
@@ -939,12 +939,14 @@
if (section == thead) {
Header<?> header = headers.get(col);
if (header != null && cellConsumesEventType(header.getCell(), eventType)) {
- header.onBrowserEvent(tableCell, event);
+ Context context = new Context(0, col, header.getKey());
+ header.onBrowserEvent(context, tableCell, event);
}
} else if (section == tfoot) {
Header<?> footer = footers.get(col);
if (footer != null && cellConsumesEventType(footer.getCell(), eventType)) {
- footer.onBrowserEvent(tableCell, event);
+ Context context = new Context(0, col, footer.getKey());
+ footer.onBrowserEvent(context, tableCell, event);
}
} else if (section == tbody) {
// Update the hover state.
@@ -964,8 +966,7 @@
style.cellTableHoveredRowCell(), false);
hoveringRow = null;
} else if (isClick
- && ((getPresenter().getKeyboardSelectedRowInView() != row)
- || (keyboardSelectedColumn != col))) {
+ && ((getPresenter().getKeyboardSelectedRowInView() != row) || (keyboardSelectedColumn != col))) {
// Move keyboard focus. Since the user clicked, allow focus to go to a
// non-interactive column.
boolean isFocusable = CellBasedWidgetImpl.get().isFocusable(target);
@@ -984,14 +985,17 @@
boolean isSelectionHandled = handlesSelection
|| KeyboardSelectionPolicy.BOUND_TO_SELECTION == getKeyboardSelectionPolicy();
T value = getVisibleItem(row);
+ Context context = new Context(row + getPageStart(), col,
+ getValueKey(value));
CellPreviewEvent<T> previewEvent = CellPreviewEvent.fire(this, event,
- this, row, col, value, cellIsEditing, isSelectionHandled);
+ this, context, value, cellIsEditing, isSelectionHandled);
if (isClick && !cellIsEditing && !isSelectionHandled) {
doSelection(event, value, row, col);
}
+ // Pass the event to the cell.
if (!previewEvent.isCanceled()) {
- fireEventToCell(event, eventType, tableCell, value, row,
+ fireEventToCell(event, eventType, tableCell, value, context,
columns.get(col));
}
}
@@ -1015,7 +1019,6 @@
createHeadersAndFooters();
int keyboardSelectedRow = getKeyboardSelectedRow() + getPageStart();
- ProvidesKey<T> keyProvider = getKeyProvider();
String evenRowStyle = style.cellTableEvenRow();
String oddRowStyle = style.cellTableOddRow();
String cellStyle = style.cellTableCell();
@@ -1075,7 +1078,8 @@
SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
if (value != null) {
- column.render(value, keyProvider, cellBuilder);
+ Context context = new Context(i, curColumn, getValueKey(value));
+ column.render(context, value, cellBuilder);
}
// Build the contents.
@@ -1132,7 +1136,7 @@
int row = getKeyboardSelectedRow();
if (isRowWithinBounds(row) && columns.size() > 0) {
Column<T, ?> column = columns.get(keyboardSelectedColumn);
- return resetFocusOnCellImpl(row, column);
+ return resetFocusOnCellImpl(row, keyboardSelectedColumn, column);
}
return false;
}
@@ -1218,7 +1222,8 @@
: style.cellTableFirstColumnHeader());
// Loop through all column headers.
- for (int curColumn = 1; curColumn < columnCount; curColumn++) {
+ int curColumn;
+ for (curColumn = 1; curColumn < columnCount; curColumn++) {
Header<?> header = theHeaders.get(curColumn);
if (header != prevHeader) {
@@ -1226,7 +1231,9 @@
SafeHtmlBuilder headerBuilder = new SafeHtmlBuilder();
if (prevHeader != null) {
hasHeader = true;
- prevHeader.render(headerBuilder);
+ Context context = new Context(0, curColumn - prevColspan,
+ prevHeader.getKey());
+ prevHeader.render(context, headerBuilder);
}
sb.append(template.th(prevColspan, classesBuilder.toString(),
headerBuilder.toSafeHtml()));
@@ -1245,7 +1252,9 @@
SafeHtmlBuilder headerBuilder = new SafeHtmlBuilder();
if (prevHeader != null) {
hasHeader = true;
- prevHeader.render(headerBuilder);
+ Context context = new Context(0, curColumn - prevColspan,
+ prevHeader.getKey());
+ prevHeader.render(context, headerBuilder);
}
// The first and last columns could be the same column.
@@ -1348,17 +1357,15 @@
* Fire an event to the Cell within the specified {@link TableCellElement}.
*/
private <C> void fireEventToCell(Event event, String eventType,
- TableCellElement tableCell, T value, int row, Column<T, C> column) {
+ TableCellElement tableCell, T value, Context context,
+ Column<T, C> column) {
Cell<C> cell = column.getCell();
if (cellConsumesEventType(cell, eventType)) {
C cellValue = column.getValue(value);
- ProvidesKey<T> providesKey = getKeyProvider();
- Object key = getValueKey(value);
Element parentElem = getCellParent(tableCell);
- boolean cellWasEditing = cell.isEditing(parentElem, cellValue, key);
- column.onBrowserEvent(parentElem, getPageStart() + row, value, event,
- providesKey);
- cellIsEditing = cell.isEditing(parentElem, cellValue, key);
+ boolean cellWasEditing = cell.isEditing(context, parentElem, cellValue);
+ column.onBrowserEvent(context, parentElem, value, event);
+ cellIsEditing = cell.isEditing(context, parentElem, cellValue);
if (cellWasEditing && !cellIsEditing) {
CellBasedWidgetImpl.get().resetFocus(new Scheduler.ScheduledCommand() {
public void execute() {
@@ -1438,13 +1445,14 @@
return consumedEvents != null && consumedEvents.size() > 0;
}
- private <C> boolean resetFocusOnCellImpl(int row, Column<T, C> column) {
+ private <C> boolean resetFocusOnCellImpl(int row, int col, Column<T, C> column) {
Element parent = getKeyboardSelectedElement();
T value = getVisibleItem(row);
Object key = getValueKey(value);
C cellValue = column.getValue(value);
Cell<C> cell = column.getCell();
- return cell.resetFocus(parent, cellValue, key);
+ Context context = new Context(row + getPageStart(), col, key);
+ return cell.resetFocus(context, parent, cellValue);
}
/**
@@ -1505,4 +1513,3 @@
}
}
}
-
diff --git a/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java b/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java
index 5598364..22c0938 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java
@@ -16,6 +16,7 @@
package com.google.gwt.user.cellview.client;
import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.AnchorElement;
@@ -63,6 +64,7 @@
*
* @param <T> the type that this view contains
*/
+// TODO(jlabanca): Convert this to be the type of the child and create lazily.
class CellTreeNodeView<T> extends UIObject {
interface Template extends SafeHtmlTemplates {
@@ -138,7 +140,8 @@
// Render the child nodes.
ProvidesKey<C> keyProvider = nodeInfo.getProvidesKey();
TreeViewModel model = nodeView.tree.getTreeViewModel();
- for (C value : values) {
+ for (int i = start; i < end; i++) {
+ C value = values.get(i - start);
Object key = keyProvider.getKey(value);
boolean isOpen = openNodes.contains(key);
@@ -171,7 +174,8 @@
}
// Render cell contents
SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
- cell.render(value, key, cellBuilder);
+ Context context = new Context(i, 0, key);
+ cell.render(context, value, cellBuilder);
SafeHtml innerDiv = template.innerDiv(paddingDirection, imageWidth,
innerClasses.toString(), image, itemValueStyle,
@@ -397,7 +401,6 @@
}
private final Cell<C> cell;
-
private final int defaultPageSize;
private HandlerManager handlerManger = new HandlerManager(this);
private final NodeInfo<C> nodeInfo;
@@ -999,14 +1002,15 @@
String eventType = event.getType();
Element cellParent = getCellParent();
Object key = getValueKey();
- boolean cellWasEditing = parentCell.isEditing(cellParent, value, key);
+ Context context = new Context(getIndex(), 0, key);
+ boolean cellWasEditing = parentCell.isEditing(context, cellParent, value);
// Update selection.
boolean isSelectionHandled = parentCell.handlesSelection()
|| KeyboardSelectionPolicy.BOUND_TO_SELECTION == tree.getKeyboardSelectionPolicy();
HasData<T> display = (HasData<T>) parentNode.listView;
CellPreviewEvent<T> previewEvent = CellPreviewEvent.fire(display, event,
- display, getIndex(), value, cellWasEditing, isSelectionHandled);
+ display, context, value, cellWasEditing, isSelectionHandled);
// Forward the event to the cell.
if (previewEvent.isCanceled()
@@ -1015,9 +1019,9 @@
}
Set<String> consumedEvents = parentCell.getConsumedEvents();
if (consumedEvents != null && consumedEvents.contains(eventType)) {
- parentCell.onBrowserEvent(cellParent, value, key, event,
+ parentCell.onBrowserEvent(context, cellParent, value, event,
parentNodeInfo.getValueUpdater());
- tree.cellIsEditing = parentCell.isEditing(cellParent, value, key);
+ tree.cellIsEditing = parentCell.isEditing(context, cellParent, value);
if (cellWasEditing && !tree.cellIsEditing) {
CellBasedWidgetImpl.get().resetFocus(new Scheduler.ScheduledCommand() {
public void execute() {
@@ -1198,13 +1202,14 @@
/**
* Reset focus on this node.
- *
+ *
* @return true of the cell takes focus, false if not
*/
boolean resetFocusOnCell() {
if (parentNodeInfo != null) {
+ Context context = new Context(getIndex(), 0, getValueKey());
Cell<T> cell = parentNodeInfo.getCell();
- return cell.resetFocus(getCellParent(), value, getValueKey());
+ return cell.resetFocus(context, getCellParent(), value);
}
return false;
}
diff --git a/user/src/com/google/gwt/user/cellview/client/Column.java b/user/src/com/google/gwt/user/cellview/client/Column.java
index 0ad4215..f74f5da 100644
--- a/user/src/com/google/gwt/user/cellview/client/Column.java
+++ b/user/src/com/google/gwt/user/cellview/client/Column.java
@@ -16,6 +16,7 @@
package com.google.gwt.user.cellview.client;
import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.HasCell;
import com.google.gwt.cell.client.ValueUpdater;
@@ -23,7 +24,6 @@
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.client.ui.HasAlignment;
-import com.google.gwt.view.client.ProvidesKey;
/**
* A representation of a column in a table. The column may maintain view data
@@ -93,35 +93,32 @@
/**
* Handle a browser event that took place within the column.
*
+ * @param context the cell context
* @param elem the parent Element
- * @param index the current row index of the object
* @param object the base object to be updated
* @param event the native browser event
- * @param keyProvider an instance of ProvidesKey<T>, or null if the record
- * object should act as its own key.
*/
- public void onBrowserEvent(Element elem, final int index, final T object,
- NativeEvent event, ProvidesKey<T> keyProvider) {
- Object key = getKey(object, keyProvider);
+ public void onBrowserEvent(Context context, Element elem, final T object,
+ NativeEvent event) {
+ final int index = context.getIndex();
ValueUpdater<C> valueUpdater = (fieldUpdater == null) ? null
: new ValueUpdater<C>() {
public void update(C value) {
fieldUpdater.update(index, object, value);
}
};
- cell.onBrowserEvent(elem, getValue(object), key, event, valueUpdater);
+ cell.onBrowserEvent(context, elem, getValue(object), event, valueUpdater);
}
/**
* Render the object into the cell.
*
+ * @param context the cell context
* @param object the object to render
- * @param keyProvider the {@link ProvidesKey} for the object
* @param sb the buffer to render into
*/
- public void render(T object, ProvidesKey<T> keyProvider, SafeHtmlBuilder sb) {
- Object key = getKey(object, keyProvider);
- cell.render(getValue(object), key, sb);
+ public void render(Context context, T object, SafeHtmlBuilder sb) {
+ cell.render(context, getValue(object), sb);
}
/**
@@ -156,16 +153,4 @@
public void setVerticalAlignment(VerticalAlignmentConstant align) {
this.vAlign = align;
}
-
- /**
- * Get the view key for the object given the {@link ProvidesKey}. If the
- * {@link ProvidesKey} is null, the object is used as the key.
- *
- * @param object the row object
- * @param keyProvider the {@link ProvidesKey}
- * @return the key for the object
- */
- private Object getKey(T object, ProvidesKey<T> keyProvider) {
- return keyProvider == null ? object : keyProvider.getKey(object);
- }
}
diff --git a/user/src/com/google/gwt/user/cellview/client/Header.java b/user/src/com/google/gwt/user/cellview/client/Header.java
index 3739fc3..c38ad35 100644
--- a/user/src/com/google/gwt/user/cellview/client/Header.java
+++ b/user/src/com/google/gwt/user/cellview/client/Header.java
@@ -1,12 +1,12 @@
/*
* Copyright 2010 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
@@ -16,6 +16,7 @@
package com.google.gwt.user.cellview.client;
import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
@@ -23,7 +24,7 @@
/**
* A table column header or footer.
- *
+ *
* @param <H> the {@link Cell} type
*/
public abstract class Header<H> {
@@ -43,7 +44,7 @@
/**
* Return the {@link Cell} responsible for rendering items in the header.
- *
+ *
* @return the header Cell
*/
public Cell<H> getCell() {
@@ -51,30 +52,41 @@
}
/**
+ * Get the key for the header value. By default, the key is the same as the
+ * value. Override this method to return a custom key.
+ *
+ * @return the key associated with the value
+ */
+ public Object getKey() {
+ return getValue();
+ }
+
+ /**
* Return the header value.
- *
+ *
* @return the header value
*/
public abstract H getValue();
/**
* Handle a browser event that took place within the header.
- *
+ *
+ * @param context the context of the header
* @param elem the parent Element
* @param event the native browser event
*/
- public void onBrowserEvent(Element elem, NativeEvent event) {
- H value = getValue();
- cell.onBrowserEvent(elem, value, getKey(), event, updater);
+ public void onBrowserEvent(Context context, Element elem, NativeEvent event) {
+ cell.onBrowserEvent(context, elem, getValue(), event, updater);
}
/**
* Render the header.
*
+ * @param context the context of the header
* @param sb a {@link SafeHtmlBuilder} to render into
*/
- public void render(SafeHtmlBuilder sb) {
- cell.render(getValue(), getKey(), sb);
+ public void render(Context context, SafeHtmlBuilder sb) {
+ cell.render(context, getValue(), sb);
}
/**
@@ -85,14 +97,4 @@
public void setUpdater(ValueUpdater<H> updater) {
this.updater = updater;
}
-
- /**
- * Get the key for the header value. By default, the key is the same as the
- * value. Override this method to return a custom key.
- *
- * @return the key associated with the value
- */
- protected Object getKey() {
- return getValue();
- }
}
diff --git a/user/src/com/google/gwt/user/client/ui/Anchor.java b/user/src/com/google/gwt/user/client/ui/Anchor.java
index bda6fce..35de8ef 100644
--- a/user/src/com/google/gwt/user/client/ui/Anchor.java
+++ b/user/src/com/google/gwt/user/client/ui/Anchor.java
@@ -20,7 +20,8 @@
import com.google.gwt.dom.client.Element;
import com.google.gwt.i18n.client.BidiUtils;
import com.google.gwt.i18n.client.HasDirection;
-import com.google.gwt.safehtml.client.HasSafeHtml;
+import com.google.gwt.i18n.shared.DirectionEstimator;
+import com.google.gwt.i18n.shared.HasDirectionEstimator;
import com.google.gwt.safehtml.shared.SafeHtml;
/**
@@ -30,6 +31,14 @@
* If you want use this anchor only for changing history states, use
* {@link Hyperlink} instead.
* </p>
+ *
+ * <p>
+ * <h3>Built-in Bidi Text Support</h3>
+ * This widget is capable of automatically adjusting its direction according to
+ * its content. This feature is controlled by {@link #setDirectionEstimator} or
+ * passing a DirectionEstimator parameter to the constructor, and is off by
+ * default.
+ * </p>
*
* <h3>CSS Style Rules</h3>
* <ul class='css'>
@@ -39,7 +48,11 @@
* @see Hyperlink
*/
public class Anchor extends FocusWidget implements HasHorizontalAlignment,
- HasName, HasHTML, HasWordWrap, HasDirection, HasSafeHtml {
+ HasName, HasHTML, HasWordWrap, HasDirection,
+ HasDirectionEstimator, HasDirectionalSafeHtml {
+
+ public static final DirectionEstimator DEFAULT_DIRECTION_ESTIMATOR =
+ DirectionalTextHelper.DEFAULT_DIRECTION_ESTIMATOR;
/**
* Creates an Anchor widget that wraps an existing <a> element.
@@ -63,6 +76,8 @@
return anchor;
}
+ private final DirectionalTextHelper directionalTextHelper;
+
private HorizontalAlignmentConstant horzAlign;
/**
@@ -71,6 +86,45 @@
public Anchor() {
setElement(Document.get().createAnchorElement());
setStyleName("gwt-Anchor");
+ directionalTextHelper = new DirectionalTextHelper(getAnchorElement(),
+ /* is inline */ true);
+ }
+
+ /**
+ * Creates an anchor for scripting.
+ *
+ * @param html the anchor's html
+ */
+ public Anchor(SafeHtml html) {
+ this(html.asString(), true);
+ }
+
+ /**
+ * Creates an anchor for scripting.
+ *
+ * The anchor's href is set to <code>javascript : ;</code>, based on the
+ * expectation that listeners will be added to the anchor.
+ *
+ * @param html the anchor's html
+ * @param dir the html's direction
+ */
+ public Anchor(SafeHtml html, Direction dir) {
+ this(html.asString(), true, dir, "javascript:;");
+ }
+
+ /**
+ * Creates an anchor for scripting.
+ *
+ * The anchor's href is set to <code>javascript : ;</code>, based on the
+ * expectation that listeners will be added to the anchor.
+ *
+ * @param html the anchor's html
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ */
+ public Anchor(SafeHtml html, DirectionEstimator directionEstimator) {
+ this(html.asString(), true, directionEstimator, "javascript:;");
}
/**
@@ -88,10 +142,14 @@
/**
* Creates an anchor for scripting.
*
- * @param html the anchor's text
+ * The anchor's href is set to <code>javascript : ;</code>, based on the
+ * expectation that listeners will be added to the anchor.
+ *
+ * @param text the anchor's text
+ * @param dir the text's direction
*/
- public Anchor(SafeHtml html) {
- this(html.asString(), true);
+ public Anchor(String text, Direction dir) {
+ this(text, dir, "javascript:;");
}
/**
@@ -101,6 +159,21 @@
* expectation that listeners will be added to the anchor.
*
* @param text the anchor's text
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ */
+ public Anchor(String text, DirectionEstimator directionEstimator) {
+ this(text, directionEstimator, "javascript:;");
+ }
+
+ /**
+ * Creates an anchor for scripting.
+ *
+ * The anchor's href is set to <code>javascript:;</code>, based on the
+ * expectation that listeners will be added to the anchor.
+ *
+ * @param text the anchor's text
* @param asHtml <code>true</code> to treat the specified text as html
*/
public Anchor(String text, boolean asHtml) {
@@ -108,7 +181,7 @@
}
/**
- * Creates an anchor with its text and href (target URL) specified.
+ * Creates an anchor with its html and href (target URL) specified.
*
* @param html the anchor's html
* @param href the url to which it will link
@@ -118,6 +191,66 @@
}
/**
+ * Creates an anchor with its html and href (target URL) specified.
+ *
+ * @param html the anchor's html
+ * @param dir the html's direction
+ * @param href the url to which it will link
+ */
+ public Anchor(SafeHtml html, Direction dir, String href) {
+ this(html.asString(), true, dir, href);
+ }
+
+ /**
+ * Creates an anchor with its html and href (target URL) specified.
+ *
+ * @param html the anchor's html
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ * @param href the url to which it will link
+ */
+ public Anchor(SafeHtml html, DirectionEstimator directionEstimator,
+ String href) {
+ this(html.asString(), true, directionEstimator, href);
+ }
+
+ /**
+ * Creates an anchor with its text and href (target URL) specified.
+ *
+ * @param text the anchor's text
+ * @param href the url to which it will link
+ */
+ public Anchor(String text, String href) {
+ this(text, false, href);
+ }
+
+ /**
+ * Creates an anchor with its text and href (target URL) specified.
+ *
+ * @param text the anchor's text
+ * @param dir the text's direction
+ * @param href the url to which it will link
+ */
+ public Anchor(String text, Direction dir, String href) {
+ this(text, false, dir, href);
+ }
+
+ /**
+ * Creates an anchor with its text and href (target URL) specified.
+ *
+ * @param text the anchor's text
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ * @param href the url to which it will link
+ */
+ public Anchor(String text, DirectionEstimator directionEstimator,
+ String href) {
+ this(text, false, directionEstimator, href);
+ }
+
+ /**
* Creates an anchor with its text and href (target URL) specified.
*
* @param text the anchor's text
@@ -126,11 +259,7 @@
*/
public Anchor(String text, boolean asHTML, String href) {
this();
- if (asHTML) {
- setHTML(text);
- } else {
- setText(text);
- }
+ directionalTextHelper.setTextOrHtml(text, asHTML);
setHref(href);
}
@@ -149,6 +278,18 @@
}
/**
+ * Creates a source anchor with a frame target.
+ *
+ * @param text the anchor's text
+ * @param href the url to which it will link
+ * @param target the target frame (e.g. "_blank" to open the link in a new
+ * window)
+ */
+ public Anchor(String text, String href, String target) {
+ this(text, false, href, target);
+ }
+
+ /**
* Creates a source anchor (link to URI).
*
* That is, an anchor with an href attribute specifying the destination URI.
@@ -165,30 +306,6 @@
}
/**
- * Creates an anchor with its text and href (target URL) specified.
- *
- * @param text the anchor's text
- * @param href the url to which it will link
- */
- public Anchor(String text, String href) {
- this();
- setText(text);
- setHref(href);
- }
-
- /**
- * Creates a source anchor with a frame target.
- *
- * @param text the anchor's text
- * @param href the url to which it will link
- * @param target the target frame (e.g. "_blank" to open the link in a new
- * window)
- */
- public Anchor(String text, String href, String target) {
- this(text, false, href, target);
- }
-
- /**
* This constructor may be used by subclasses to explicitly use an existing
* element. This element must be an <a> element.
*
@@ -197,12 +314,50 @@
protected Anchor(Element element) {
AnchorElement.as(element);
setElement(element);
+ directionalTextHelper = new DirectionalTextHelper(getAnchorElement(),
+ /* is inline */ true);
+ }
+
+ /**
+ * Creates an anchor with its text, direction and href (target URL) specified.
+ *
+ * @param text the anchor's text
+ * @param asHTML <code>true</code> to treat the specified text as html
+ * @param dir the text's direction
+ * @param href the url to which it will link
+ */
+ private Anchor(String text, boolean asHTML, Direction dir, String href) {
+ this();
+ directionalTextHelper.setTextOrHtml(text, dir, asHTML);
+ setHref(href);
+ }
+
+ /**
+ * Creates an anchor with its text, direction and href (target URL) specified.
+ *
+ * @param text the anchor's text
+ * @param asHTML <code>true</code> to treat the specified text as html
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ * @param href the url to which it will link
+ */
+ private Anchor(String text, boolean asHTML,
+ DirectionEstimator directionEstimator, String href) {
+ this();
+ directionalTextHelper.setDirectionEstimator(directionEstimator);
+ directionalTextHelper.setTextOrHtml(text, asHTML);
+ setHref(href);
}
public Direction getDirection() {
return BidiUtils.getDirectionOnElement(getElement());
}
+ public DirectionEstimator getDirectionEstimator() {
+ return directionalTextHelper.getDirectionEstimator();
+ }
+
public HorizontalAlignmentConstant getHorizontalAlignment() {
return horzAlign;
}
@@ -240,7 +395,11 @@
}
public String getText() {
- return getElement().getInnerText();
+ return directionalTextHelper.getTextOrHtml(false);
+ }
+
+ public Direction getTextDirection() {
+ return directionalTextHelper.getTextDirection();
}
public boolean getWordWrap() {
@@ -252,8 +411,35 @@
getAnchorElement().setAccessKey(Character.toString(key));
}
+ /**
+ * @deprecated Use {@link #setDirectionEstimator} and / or pass explicit
+ * direction to {@link #setText}, {@link #setHTML} instead
+ */
+ @Deprecated
public void setDirection(Direction direction) {
- BidiUtils.setDirectionOnElement(getElement(), direction);
+ directionalTextHelper.setDirection(direction);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * See note at {@link #setDirectionEstimator(DirectionEstimator)}.
+ */
+ public void setDirectionEstimator(boolean enabled) {
+ directionalTextHelper.setDirectionEstimator(enabled);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Note: DirectionEstimator should be set before the widget has any content;
+ * it's highly recommended to set it using a constructor. Reason: if the
+ * widget already has non-empty content, this will update its direction
+ * according to the new estimator's result. This may cause flicker, and thus
+ * should be avoided.
+ */
+ public void setDirectionEstimator(DirectionEstimator directionEstimator) {
+ directionalTextHelper.setDirectionEstimator(directionEstimator);
}
@Override
@@ -284,7 +470,11 @@
}
public void setHTML(String html) {
- getElement().setInnerHTML(html);
+ directionalTextHelper.setTextOrHtml(html, true);
+ }
+
+ public void setHTML(SafeHtml html, Direction dir) {
+ directionalTextHelper.setTextOrHtml(html.asString(), dir, true);
}
public void setName(String name) {
@@ -307,7 +497,11 @@
}
public void setText(String text) {
- getElement().setInnerText(text);
+ directionalTextHelper.setTextOrHtml(text, false);
+ }
+
+ public void setText(String text, Direction dir) {
+ directionalTextHelper.setTextOrHtml(text, dir, false);
}
public void setWordWrap(boolean wrap) {
diff --git a/user/src/com/google/gwt/user/client/ui/CheckBox.java b/user/src/com/google/gwt/user/client/ui/CheckBox.java
index 75635ee..3549e0d 100644
--- a/user/src/com/google/gwt/user/client/ui/CheckBox.java
+++ b/user/src/com/google/gwt/user/client/ui/CheckBox.java
@@ -59,6 +59,7 @@
HasWordWrap, IsEditor<LeafValueEditor<Boolean>> {
InputElement inputElem;
LabelElement labelElem;
+ private LeafValueEditor<Boolean> editor;
private boolean valueChangeHandlerInitialized;
/**
@@ -134,7 +135,10 @@
}
public LeafValueEditor<Boolean> asEditor() {
- return TakesValueEditor.of(this);
+ if (editor == null) {
+ editor = TakesValueEditor.of(this);
+ }
+ return editor;
}
/**
@@ -172,7 +176,7 @@
/**
* Determines whether this check box is currently checked.
* <p>
- * Note that this <em>is not</em> return the value property of the checkbox
+ * Note that this <em>does not</em> return the value property of the checkbox
* input element wrapped by this widget. For access to that property, see
* {@link #getFormValue()}
*
diff --git a/user/src/com/google/gwt/user/client/ui/DateLabel.java b/user/src/com/google/gwt/user/client/ui/DateLabel.java
new file mode 100644
index 0000000..0c925a8
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/DateLabel.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 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.client.ui;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.TimeZone;
+import com.google.gwt.text.client.DateTimeFormatRenderer;
+
+import java.util.Date;
+
+/**
+ * Extends {@link ValueLabel} for convenience when dealing with dates and
+ * {@link DateTimeFormat}, especially in
+ * {@link com.google.gwt.uibinder.client.UiBinder UiBinder} templates. (Note
+ * that this class does not accept renderers. To do so use {@link ValueLabel}
+ * directly.)
+ *
+ * <h3>Use in UiBinder Templates</h3>
+ * In {@link com.google.gwt.uibinder.client.UiBinder UiBinder} templates, both the format and time zone can be configured.
+ * <p>
+ * The format can be given with one of these attributes:
+ * <dl>
+ * <dt>format</dt><dd>a reference to a {@link DateTimeFormat} instance.</dd>
+ * <dt>predefinedFormat</dt><dd>a {@link DateTimeFormat.PredefinedFormat}.</dd>
+ * <dt>customFormat</dt><dd>a date time pattern that can be passed to {@link DateTimeFormat#getFormat(String)}.</dd>
+ * </dl>
+ * <p>
+ * The time zone can be specified with either of these attributes:
+ * <dl>
+ * <dt>timezone</dt><dd>a reference to a {@link TimeZone} instance.</dd>
+ * <dt>timezoneOffset</dt><dd>the time zone offset in minutes.</dd>
+ * </dl>
+ */
+public class DateLabel extends ValueLabel<Date> {
+
+ public DateLabel() {
+ super(new DateTimeFormatRenderer());
+ }
+
+ public DateLabel(DateTimeFormat format) {
+ super(new DateTimeFormatRenderer(format));
+ }
+
+ public DateLabel(DateTimeFormat format, TimeZone timeZone) {
+ super(new DateTimeFormatRenderer(format, timeZone));
+ }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/DirectionalTextHelper.java b/user/src/com/google/gwt/user/client/ui/DirectionalTextHelper.java
new file mode 100644
index 0000000..68d3fbd
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/DirectionalTextHelper.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2010 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.client.ui;
+
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.i18n.client.BidiUtils;
+import com.google.gwt.i18n.client.HasDirection.Direction;
+import com.google.gwt.i18n.shared.BidiFormatter;
+import com.google.gwt.i18n.shared.DirectionEstimator;
+import com.google.gwt.i18n.shared.HasDirectionEstimator;
+import com.google.gwt.i18n.shared.WordCountDirectionEstimator;
+
+/**
+ * A helper class for displaying bidi (i.e. potentially opposite-direction) text
+ * or HTML in an element.
+ * Note: this class assumes that callers perform all their text/html and
+ * direction manipulations through it alone.
+ */
+public class DirectionalTextHelper implements HasDirectionEstimator {
+
+ /**
+ * A default direction estimator instance.
+ */
+ public static final DirectionEstimator DEFAULT_DIRECTION_ESTIMATOR =
+ WordCountDirectionEstimator.get();
+
+ /**
+ * The DirectionEstimator object.
+ */
+ private DirectionEstimator directionEstimator;
+
+ /**
+ * The target element.
+ */
+ private final Element element;
+
+ /**
+ * The initial direction of the element.
+ */
+ private Direction initialElementDir;
+
+ /**
+ * Whether direction was explicitly set on the last {@code setTextOrHtml}
+ * call. If so, {@link #setDirectionEstimator} will refrain from modifying the
+ * direction until {@link #setTextOrHtml} is called without specifying an
+ * explicit direction.
+ */
+ private boolean isDirectionExplicitlySet;
+
+ /**
+ * Whether the element is inline (e.g. a <span> element, but not a block
+ * element like <div>).
+ * This is needed because direction is handled differently for inline elements
+ * and for non-inline elements.
+ */
+ private final boolean isElementInline;
+
+ /**
+ * Whether the element contains a nested <span> element used to
+ * indicate the content's direction.
+ * <p>
+ * The element itself is used for this purpose when it is a block element
+ * (i.e. !isElementInline), but doing so on an inline element often results in
+ * garbling what follows it. Thus, when the element is inline, a nested
+ * <span> must be used to carry the content's direction, with an LRM or
+ * RLM character afterwards to prevent the garbling.
+ */
+ private boolean isSpanWrapped;
+
+ /**
+ * The direction of the element's content.
+ * Note: this may not match the direction attribute of the element itself.
+ * See
+ * {@link #setTextOrHtml(String, com.google.gwt.i18n.client.HasDirection.Direction, boolean) setTextOrHtml(String, Direction, boolean)}
+ * for details.
+ */
+ private Direction textDir;
+
+ /**
+ * @param element The widget's element holding text.
+ * @param isElementInline Whether the element is an inline element.
+ */
+ public DirectionalTextHelper(Element element, boolean isElementInline) {
+ this.element = element;
+ this.isElementInline = isElementInline;
+ isSpanWrapped = false;
+ this.initialElementDir = BidiUtils.getDirectionOnElement(element);
+ textDir = initialElementDir;
+ // setDirectionEstimator shouldn't refresh appearance of initial empty text.
+ isDirectionExplicitlySet = true;
+ }
+
+ public DirectionEstimator getDirectionEstimator() {
+ return directionEstimator;
+ }
+
+ public Direction getTextDirection() {
+ return textDir;
+ }
+
+ /**
+ * Get the inner text or html of the element, taking the inner span wrap into
+ * consideration, if needed.
+ *
+ * @param isHtml true to get the inner html, false to get the inner text
+ * @return the text or html
+ */
+ public String getTextOrHtml(boolean isHtml) {
+ Element elem = isSpanWrapped ? element.getFirstChildElement() : element;
+ return isHtml ? elem.getInnerHTML() : elem.getInnerText();
+ }
+
+ /**
+ * Provides implementation for HasDirection's method setDirection (normally
+ * deprecated), dealing with backwards compatibility issues.
+ * @deprecated
+ */
+ @Deprecated
+ public void setDirection(Direction direction) {
+ BidiUtils.setDirectionOnElement(element, direction);
+ initialElementDir = direction;
+
+ /*
+ * For backwards compatibility, assure there's no span wrap, and update the
+ * content direction.
+ */
+ setInnerTextOrHtml(getTextOrHtml(true), true);
+ isSpanWrapped = false;
+ textDir = initialElementDir;
+ isDirectionExplicitlySet = true;
+ }
+
+ /**
+ * See note at
+ * {@link #setDirectionEstimator(com.google.gwt.i18n.shared.DirectionEstimator)}.
+ */
+ public void setDirectionEstimator(boolean enabled) {
+ setDirectionEstimator(enabled ? DEFAULT_DIRECTION_ESTIMATOR : null);
+ }
+
+ /**
+ * Note: if the element already has non-empty content, this will update
+ * its direction according to the new estimator's result. This may cause
+ * flicker, and thus should be avoided; DirectionEstimator should be set
+ * before the element has any content.
+ */
+ public void setDirectionEstimator(DirectionEstimator directionEstimator) {
+ this.directionEstimator = directionEstimator;
+ /*
+ * Refresh appearance unless direction was explicitly set on last
+ * setTextOrHtml call.
+ */
+ if (!isDirectionExplicitlySet) {
+ setTextOrHtml(getTextOrHtml(true), true);
+ }
+ }
+
+ /**
+ * Sets the element's content to the given value (either plain text or HTML).
+ * If direction estimation is off, the direction is verified to match the
+ * element's initial direction. Otherwise, the direction is affected as
+ * described at
+ * {@link #setTextOrHtml(String, com.google.gwt.i18n.client.HasDirection.Direction, boolean) setTextOrHtml(String, Direction, boolean)}.
+ *
+ * @param content the element's new content
+ * @param isHtml whether the content is HTML
+ */
+ public void setTextOrHtml(String content, boolean isHtml) {
+ if (directionEstimator == null) {
+ isSpanWrapped = false;
+ setInnerTextOrHtml(content, isHtml);
+
+ /*
+ * Preserves the initial direction of the element. This is different from
+ * passing the direction parameter explicitly as DEFAULT, which forces the
+ * element to inherit the direction from its parent.
+ */
+ if (textDir != initialElementDir) {
+ textDir = initialElementDir;
+ BidiUtils.setDirectionOnElement(element, initialElementDir);
+ }
+ } else {
+ setTextOrHtml(content, directionEstimator.estimateDirection(content,
+ isHtml), isHtml);
+ }
+ isDirectionExplicitlySet = false;
+ }
+
+ /**
+ * Sets the element's content to the given value (either plain text or HTML),
+ * applying the given direction.
+ * <p>
+ * Implementation details:
+ * <ul>
+ * <li> If the element is a block element, sets its dir attribute according
+ * to the given direction.
+ * <li> Otherwise (i.e. the element is inline), the direction is set using a
+ * nested <span dir=...> element which holds the content of the element.
+ * This nested span may be followed by a zero-width Unicode direction
+ * character (LRM or RLM). This manipulation is necessary to prevent garbling
+ * in case the direction of the element is opposite to the direction of its
+ * context. See {@link com.google.gwt.i18n.shared.BidiFormatter} for more
+ * details.
+ * </ul>
+ *
+ * @param content the element's new content
+ * @param dir the content's direction
+ * @param isHtml whether the content is HTML
+ */
+ public void setTextOrHtml(String content, Direction dir, boolean isHtml) {
+ textDir = dir;
+ // Set the text and the direction.
+ if (isElementInline) {
+ isSpanWrapped = true;
+ element.setInnerHTML(BidiFormatter.getInstanceForCurrentLocale(
+ true /* alwaysSpan */).spanWrapWithKnownDir(dir, content, isHtml));
+ } else {
+ isSpanWrapped = false;
+ BidiUtils.setDirectionOnElement(element, dir);
+ setInnerTextOrHtml(content, isHtml);
+ }
+ isDirectionExplicitlySet = true;
+ }
+
+ private void setInnerTextOrHtml(String content, boolean isHtml) {
+ if (isHtml) {
+ element.setInnerHTML(content);
+ } else {
+ element.setInnerText(content);
+ }
+ }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/HTML.java b/user/src/com/google/gwt/user/client/ui/HTML.java
index 6fe54bf..e7e123d 100644
--- a/user/src/com/google/gwt/user/client/ui/HTML.java
+++ b/user/src/com/google/gwt/user/client/ui/HTML.java
@@ -17,6 +17,7 @@
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.i18n.shared.DirectionEstimator;
import com.google.gwt.safehtml.shared.SafeHtml;
/**
@@ -32,6 +33,14 @@
* used properly.
* </p>
*
+ * <p>
+ * <h3>Built-in Bidi Text Support</h3>
+ * This widget is capable of automatically adjusting its direction according to
+ * its content. This feature is controlled by {@link #setDirectionEstimator} or
+ * passing a DirectionEstimator parameter to the constructor, and is off by
+ * default.
+ * </p>
+ *
* <h3>CSS Style Rules</h3>
* <ul class='css'>
* <li>.gwt-HTML { }</li>
@@ -86,18 +95,8 @@
}
/**
- * Creates an HTML widget with the specified HTML contents.
- *
- * @param html the new widget's HTML contents
- */
- public HTML(String html) {
- this();
- setHTML(html);
- }
-
- /**
- * Creates an HTML widget with the specified contents and with the
- * specified direction.
+ * Creates an HTML widget with the specified contents and with the specified
+ * direction.
*
* @param html the new widget's SafeHtml contents
* @param dir the content's direction. Note: {@code Direction.DEFAULT} means
@@ -108,6 +107,31 @@
}
/**
+ * Creates an HTML widget with the specified HTML contents and specifies a
+ * direction estimator.
+ *
+ * @param html the new widget's SafeHtml contents
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link Label#DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ */
+ public HTML(SafeHtml html, DirectionEstimator directionEstimator) {
+ this();
+ setDirectionEstimator(directionEstimator);
+ setHTML(html);
+ }
+
+ /**
+ * Creates an HTML widget with the specified HTML contents.
+ *
+ * @param html the new widget's HTML contents
+ */
+ public HTML(String html) {
+ this();
+ setHTML(html);
+ }
+
+ /**
* Creates an HTML widget with the specified HTML contents and with the
* specified direction.
*
@@ -145,7 +169,7 @@
}
public String getHTML() {
- return getTextOrHtml(true);
+ return directionalTextHelper.getTextOrHtml(true);
}
/**
@@ -156,21 +180,23 @@
* @param html the new widget's HTML content
*/
public void setHTML(String html) {
- setTextOrHtml(html, true);
+ directionalTextHelper.setTextOrHtml(html, true);
+ updateHorizontalAlignment();
}
/**
* Sets the label's content to the given HTML, applying the given direction.
* See
- * {@link #setText(String, com.google.gwt.i18n.client.HasDirection.Direction)
- * setText(String, Direction)} for details on potential effects on alignment.
+ * {@link #setText(String, com.google.gwt.i18n.client.HasDirection.Direction) setText(String, Direction)}
+ * for details on potential effects on alignment.
*
* @param html the new widget's HTML content
* @param dir the content's direction. Note: {@code Direction.DEFAULT} means
* direction should be inherited from the widget's parent element.
*/
public void setHTML(String html, Direction dir) {
- setTextOrHtml(html, dir, true);
+ directionalTextHelper.setTextOrHtml(html, dir, true);
+ updateHorizontalAlignment();
}
/**
@@ -188,4 +214,8 @@
public void setHTML(SafeHtml html, Direction dir) {
setHTML(html.asString(), dir);
}
+
+ protected String getTextOrHtml(boolean isHtml) {
+ return directionalTextHelper.getTextOrHtml(isHtml);
+ }
}
diff --git a/user/src/com/google/gwt/user/client/ui/Hidden.java b/user/src/com/google/gwt/user/client/ui/Hidden.java
index fcd978b..d9f1466 100644
--- a/user/src/com/google/gwt/user/client/ui/Hidden.java
+++ b/user/src/com/google/gwt/user/client/ui/Hidden.java
@@ -18,11 +18,15 @@
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.InputElement;
+import com.google.gwt.editor.client.IsEditor;
+import com.google.gwt.editor.client.LeafValueEditor;
+import com.google.gwt.editor.client.adapters.TakesValueEditor;
+import com.google.gwt.user.client.TakesValue;
/**
* Represents a hidden field in an HTML form.
*/
-public class Hidden extends Widget implements HasName {
+public class Hidden extends Widget implements HasName, TakesValue<String>, IsEditor<LeafValueEditor<String>> {
/**
* Creates a Hidden widget that wraps an existing <input type='hidden'>
@@ -47,6 +51,8 @@
return hidden;
}
+ private LeafValueEditor<String> editor;
+
/**
* Constructor for <code>Hidden</code>.
*/
@@ -87,6 +93,13 @@
setElement(element);
}
+ public LeafValueEditor<String> asEditor() {
+ if (editor == null) {
+ editor = TakesValueEditor.of(this);
+ }
+ return editor;
+ }
+
/**
* Gets the default value of the hidden field.
*
diff --git a/user/src/com/google/gwt/user/client/ui/Hyperlink.java b/user/src/com/google/gwt/user/client/ui/Hyperlink.java
index 9d8f2e0..08e25f8 100644
--- a/user/src/com/google/gwt/user/client/ui/Hyperlink.java
+++ b/user/src/com/google/gwt/user/client/ui/Hyperlink.java
@@ -20,7 +20,9 @@
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.safehtml.client.HasSafeHtml;
+import com.google.gwt.i18n.client.HasDirection.Direction;
+import com.google.gwt.i18n.shared.DirectionEstimator;
+import com.google.gwt.i18n.shared.HasDirectionEstimator;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
@@ -46,6 +48,14 @@
* </p>
*
* <p>
+ * <h3>Built-in Bidi Text Support</h3>
+ * This widget is capable of automatically adjusting its direction according to
+ * its content. This feature is controlled by {@link #setDirectionEstimator} or
+ * passing a DirectionEstimator parameter to the constructor, and is off by
+ * default.
+ * </p>
+ *
+ * <p>
* <img class='gallery' src='doc-files/Hyperlink.png'/>
* </p>
*
@@ -62,10 +72,14 @@
*/
@SuppressWarnings("deprecation")
public class Hyperlink extends Widget implements HasHTML, SourcesClickEvents,
- HasClickHandlers, HasSafeHtml {
+ HasClickHandlers, HasDirectionEstimator, HasDirectionalSafeHtml {
+
+ public static final DirectionEstimator DEFAULT_DIRECTION_ESTIMATOR =
+ DirectionalTextHelper.DEFAULT_DIRECTION_ESTIMATOR;
private static HyperlinkImpl impl = GWT.create(HyperlinkImpl.class);
-
+
+ protected final DirectionalTextHelper directionalTextHelper;
private final Element anchorElem = DOM.createAnchor();
private String targetHistoryToken;
@@ -88,21 +102,30 @@
}
/**
- * Creates a hyperlink with its text and target history token specified.
+ * Creates a hyperlink with its html and target history token specified.
*
- * @param text the hyperlink's text
- * @param asHTML <code>true</code> to treat the specified text as html
+ * @param html the hyperlink's safe html
+ * @param dir the html's direction
* @param targetHistoryToken the history token to which it will link
* @see #setTargetHistoryToken
*/
- public Hyperlink(String text, boolean asHTML, String targetHistoryToken) {
- this();
- if (asHTML) {
- setHTML(text);
- } else {
- setText(text);
- }
- setTargetHistoryToken(targetHistoryToken);
+ public Hyperlink(SafeHtml html, Direction dir, String targetHistoryToken) {
+ this(html.asString(), true, dir, targetHistoryToken);
+ }
+
+ /**
+ * Creates a hyperlink with its html and target history token specified.
+ *
+ * @param html the hyperlink's safe html
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ * @param targetHistoryToken the history token to which it will link
+ * @see #setTargetHistoryToken
+ */
+ public Hyperlink(SafeHtml html, DirectionEstimator directionEstimator,
+ String targetHistoryToken) {
+ this(html.asString(), true, directionEstimator, targetHistoryToken);
}
/**
@@ -114,8 +137,49 @@
* history processing)
*/
public Hyperlink(String text, String targetHistoryToken) {
+ this(text, false, targetHistoryToken);
+ }
+
+ /**
+ * Creates a hyperlink with its text and target history token specified.
+ *
+ * @param text the hyperlink's text
+ * @param dir the text's direction
+ * @param targetHistoryToken the history token to which it will link, which
+ * may not be null (use {@link Anchor} instead if you don't need
+ * history processing)
+ */
+ public Hyperlink(String text, Direction dir, String targetHistoryToken) {
+ this(text, false, dir, targetHistoryToken);
+ }
+
+ /**
+ * Creates a hyperlink with its text and target history token specified.
+ *
+ * @param text the hyperlink's text
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ * @param targetHistoryToken the history token to which it will link, which
+ * may not be null (use {@link Anchor} instead if you don't need
+ * history processing)
+ */
+ public Hyperlink(String text, DirectionEstimator directionEstimator,
+ String targetHistoryToken) {
+ this(text, false, directionEstimator, targetHistoryToken);
+ }
+
+ /**
+ * Creates a hyperlink with its text and target history token specified.
+ *
+ * @param text the hyperlink's text
+ * @param asHTML <code>true</code> to treat the specified text as html
+ * @param targetHistoryToken the history token to which it will link
+ * @see #setTargetHistoryToken
+ */
+ public Hyperlink(String text, boolean asHTML, String targetHistoryToken) {
this();
- setText(text);
+ directionalTextHelper.setTextOrHtml(text, asHTML);
setTargetHistoryToken(targetHistoryToken);
}
@@ -129,6 +193,43 @@
sinkEvents(Event.ONCLICK);
setStyleName("gwt-Hyperlink");
+ directionalTextHelper = new DirectionalTextHelper(anchorElem,
+ /* is inline */ true);
+ }
+
+ /**
+ * Creates a hyperlink with its text target history token specified.
+ *
+ * @param text the hyperlink's text
+ * @param asHTML <code>true</code> to treat the specified text as html
+ * @param dir the text's direction
+ * @param targetHistoryToken the history token to which it will link
+ * @see #setTargetHistoryToken
+ */
+ private Hyperlink(String text, boolean asHTML, Direction dir,
+ String targetHistoryToken) {
+ this();
+ directionalTextHelper.setTextOrHtml(text, dir, asHTML);
+ setTargetHistoryToken(targetHistoryToken);
+ }
+
+ /**
+ * Creates a hyperlink with its text and target history token specified.
+ *
+ * @param text the hyperlink's text
+ * @param asHTML <code>true</code> to treat the specified text as html
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ * @param targetHistoryToken the history token to which it will link
+ * @see #setTargetHistoryToken
+ */
+ private Hyperlink(String text, boolean asHTML,
+ DirectionEstimator directionEstimator, String targetHistoryToken) {
+ this();
+ directionalTextHelper.setDirectionEstimator(directionEstimator);
+ directionalTextHelper.setTextOrHtml(text, asHTML);
+ setTargetHistoryToken(targetHistoryToken);
}
/**
@@ -151,8 +252,12 @@
ListenerWrapper.WrappedClickListener.add(this, listener);
}
+ public DirectionEstimator getDirectionEstimator() {
+ return directionalTextHelper.getDirectionEstimator();
+ }
+
public String getHTML() {
- return DOM.getInnerHTML(anchorElem);
+ return directionalTextHelper.getTextOrHtml(true);
}
/**
@@ -166,7 +271,11 @@
}
public String getText() {
- return DOM.getInnerText(anchorElem);
+ return directionalTextHelper.getTextOrHtml(false);
+ }
+
+ public Direction getTextDirection() {
+ return directionalTextHelper.getTextDirection();
}
@Override
@@ -187,14 +296,40 @@
ListenerWrapper.WrappedClickListener.remove(this, listener);
}
- public void setHTML(String html) {
- DOM.setInnerHTML(anchorElem, html);
+ /**
+ * {@inheritDoc}
+ * <p>
+ * See note at {@link #setDirectionEstimator(DirectionEstimator)}.
+ */
+ public void setDirectionEstimator(boolean enabled) {
+ directionalTextHelper.setDirectionEstimator(enabled);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Note: DirectionEstimator should be set before the widget has any content;
+ * it's highly recommended to set it using a constructor. Reason: if the
+ * widget already has non-empty content, this will update its direction
+ * according to the new estimator's result. This may cause flicker, and thus
+ * should be avoided.
+ */
+ public void setDirectionEstimator(DirectionEstimator directionEstimator) {
+ directionalTextHelper.setDirectionEstimator(directionEstimator);
}
public void setHTML(SafeHtml html) {
setHTML(html.asString());
}
+ public void setHTML(String html) {
+ directionalTextHelper.setTextOrHtml(html, true);
+ }
+
+ public void setHTML(SafeHtml html, Direction dir) {
+ directionalTextHelper.setTextOrHtml(html.asString(), dir, true);
+ }
+
/**
* Sets the history token referenced by this hyperlink. This is the history
* token that will be passed to {@link History#newItem} when this link is
@@ -211,7 +346,11 @@
}
public void setText(String text) {
- DOM.setInnerText(anchorElem, text);
+ directionalTextHelper.setTextOrHtml(text, false);
+ }
+
+ public void setText(String text, Direction dir) {
+ directionalTextHelper.setTextOrHtml(text, dir, false);
}
/**
@@ -228,4 +367,3 @@
ensureDebugId(getElement(), baseID, "wrapper");
}
}
-
diff --git a/user/src/com/google/gwt/user/client/ui/InlineHTML.java b/user/src/com/google/gwt/user/client/ui/InlineHTML.java
index a1a0bc1..d12e526 100644
--- a/user/src/com/google/gwt/user/client/ui/InlineHTML.java
+++ b/user/src/com/google/gwt/user/client/ui/InlineHTML.java
@@ -17,6 +17,8 @@
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
+
+import com.google.gwt.i18n.shared.DirectionEstimator;
import com.google.gwt.safehtml.shared.SafeHtml;
/**
@@ -32,6 +34,14 @@
* used properly.
* </p>
*
+ * <p>
+ * <h3>Built-in Bidi Text Support</h3>
+ * This widget is capable of automatically adjusting its direction according to
+ * its content. This feature is controlled by {@link #setDirectionEstimator} or
+ * passing a DirectionEstimator parameter to the constructor, and is off by
+ * default.
+ * </p>
+ *
* <h3>CSS Style Rules</h3>
* <ul class='css'>
* <li>.gwt-InlineHTML { }</li>
@@ -80,16 +90,6 @@
}
/**
- * Creates an HTML widget with the specified HTML contents.
- *
- * @param html the new widget's HTML contents
- */
- public InlineHTML(String html) {
- this();
- setHTML(html);
- }
-
- /**
* Creates an HTML widget with the specified contents and with the
* specified direction.
*
@@ -102,6 +102,31 @@
}
/**
+ * Creates an HTML widget with the specified HTML contents and with a default
+ * direction estimator.
+ *
+ * @param html the new widget's SafeHtml contents
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link Label#DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ */
+ public InlineHTML(SafeHtml html, DirectionEstimator directionEstimator) {
+ this();
+ setDirectionEstimator(directionEstimator);
+ setHTML(html);
+ }
+
+ /**
+ * Creates an HTML widget with the specified HTML contents.
+ *
+ * @param html the new widget's HTML contents
+ */
+ public InlineHTML(String html) {
+ this();
+ setHTML(html);
+ }
+
+ /**
* Creates an HTML widget with the specified HTML contents and with the
* specified direction.
*
diff --git a/user/src/com/google/gwt/user/client/ui/InlineHyperlink.java b/user/src/com/google/gwt/user/client/ui/InlineHyperlink.java
index 663d6f9..43b20be 100644
--- a/user/src/com/google/gwt/user/client/ui/InlineHyperlink.java
+++ b/user/src/com/google/gwt/user/client/ui/InlineHyperlink.java
@@ -16,6 +16,8 @@
package com.google.gwt.user.client.ui;
+import com.google.gwt.i18n.client.HasDirection.Direction;
+import com.google.gwt.i18n.shared.DirectionEstimator;
import com.google.gwt.safehtml.shared.SafeHtml;
/**
@@ -24,6 +26,14 @@
* {@link com.google.gwt.user.client.ui.Hyperlink}, save that it lays out
* as an inline element, not block.
*
+ * <p>
+ * <h3>Built-in Bidi Text Support</h3>
+ * This widget is capable of automatically adjusting its direction according to
+ * its content. This feature is controlled by {@link #setDirectionEstimator} or
+ * passing a DirectionEstimator parameter to the constructor, and is off by
+ * default.
+ * </p>
+ *
* <h3>CSS Style Rules</h3>
* <ul class='css'>
* <li>.gwt-InlineHyperlink { }</li>
@@ -52,22 +62,31 @@
}
/**
- * Creates a hyperlink with its text and target history token specified.
- *
- * @param text the hyperlink's text
- * @param asHTML <code>true</code> to treat the specified text as html
+ * Creates a hyperlink with its html and target history token specified.
+ *
+ * @param html the hyperlink's html
+ * @param dir the html's direction
* @param targetHistoryToken the history token to which it will link
* @see #setTargetHistoryToken
*/
- public InlineHyperlink(String text, boolean asHTML, String targetHistoryToken) {
- this();
-
- if (asHTML) {
- setHTML(text);
- } else {
- setText(text);
- }
- setTargetHistoryToken(targetHistoryToken);
+ public InlineHyperlink(SafeHtml html, Direction dir,
+ String targetHistoryToken) {
+ this(html.asString(), true, dir, targetHistoryToken);
+ }
+
+ /**
+ * Creates a hyperlink with its html and target history token specified.
+ *
+ * @param html the hyperlink's html
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link Hyperlink#DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ * @param targetHistoryToken the history token to which it will link
+ * @see #setTargetHistoryToken
+ */
+ public InlineHyperlink(SafeHtml html, DirectionEstimator directionEstimator,
+ String targetHistoryToken) {
+ this(html.asString(), true, directionEstimator, targetHistoryToken);
}
/**
@@ -79,4 +98,80 @@
public InlineHyperlink(String text, String targetHistoryToken) {
this(text, false, targetHistoryToken);
}
+
+ /**
+ * Creates a hyperlink with its text and target history token specified.
+ *
+ * @param text the hyperlink's text
+ * @param dir the text's direction
+ * @param targetHistoryToken the history token to which it will link
+ */
+ public InlineHyperlink(String text, Direction dir,
+ String targetHistoryToken) {
+ this(text, false, dir, targetHistoryToken);
+ }
+
+ /**
+ * Creates a hyperlink with its text and target history token specified.
+ *
+ * @param text the hyperlink's text
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link Hyperlink#DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ * @param targetHistoryToken the history token to which it will link
+ */
+ public InlineHyperlink(String text, DirectionEstimator directionEstimator,
+ String targetHistoryToken) {
+ this(text, false, directionEstimator, targetHistoryToken);
+ }
+
+ /**
+ * Creates a hyperlink with its text and target history token specified.
+ *
+ * @param text the hyperlink's text
+ * @param asHTML <code>true</code> to treat the specified text as html
+ * @param targetHistoryToken the history token to which it will link
+ * @see #setTargetHistoryToken
+ */
+ public InlineHyperlink(String text, boolean asHTML,
+ String targetHistoryToken) {
+ this();
+ directionalTextHelper.setTextOrHtml(text, asHTML);
+ setTargetHistoryToken(targetHistoryToken);
+ }
+
+ /**
+ * Creates a hyperlink with its text and target history token specified.
+ *
+ * @param text the hyperlink's text
+ * @param asHTML <code>true</code> to treat the specified text as html
+ * @param dir the text's direction
+ * @param targetHistoryToken the history token to which it will link
+ * @see #setTargetHistoryToken
+ */
+ private InlineHyperlink(String text, boolean asHTML, Direction dir,
+ String targetHistoryToken) {
+ this();
+ directionalTextHelper.setTextOrHtml(text, dir, asHTML);
+ setTargetHistoryToken(targetHistoryToken);
+ }
+
+ /**
+ * Creates a hyperlink with its text and target history token specified.
+ *
+ * @param text the hyperlink's text
+ * @param asHTML <code>true</code> to treat the specified text as html
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link Hyperlink#DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ * @param targetHistoryToken the history token to which it will link
+ * @see #setTargetHistoryToken
+ */
+ private InlineHyperlink(String text, boolean asHTML,
+ DirectionEstimator directionEstimator, String targetHistoryToken) {
+ this();
+ directionalTextHelper.setDirectionEstimator(directionEstimator);
+ directionalTextHelper.setTextOrHtml(text, asHTML);
+ setTargetHistoryToken(targetHistoryToken);
+ }
}
diff --git a/user/src/com/google/gwt/user/client/ui/InlineLabel.java b/user/src/com/google/gwt/user/client/ui/InlineLabel.java
index 75bafab..a6b9efc 100644
--- a/user/src/com/google/gwt/user/client/ui/InlineLabel.java
+++ b/user/src/com/google/gwt/user/client/ui/InlineLabel.java
@@ -18,12 +18,22 @@
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.i18n.shared.DirectionEstimator;
+
/**
* A widget that contains arbitrary text, <i>not</i> interpreted as HTML.
*
* This widget uses a <span> element, causing it to be displayed with
* inline layout.
*
+ * <p>
+ * <h3>Built-in Bidi Text Support</h3>
+ * This widget is capable of automatically adjusting its direction according to
+ * its content. This feature is controlled by {@link #setDirectionEstimator} or
+ * passing a DirectionEstimator parameter to the constructor, and is off by
+ * default.
+ * </p>
+ *
* <h3>CSS Style Rules</h3>
* <ul class='css'>
* <li>.gwt-InlineLabel { }</li>
@@ -85,6 +95,20 @@
}
/**
+ * Creates a label with the specified text and a default direction estimator.
+ *
+ * @param text the new label's text
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link Label#DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ */
+ public InlineLabel(String text, DirectionEstimator directionEstimator) {
+ this();
+ setDirectionEstimator(directionEstimator);
+ setText(text);
+ }
+
+ /**
* This constructor may be used by subclasses to explicitly use an existing
* element. This element must be either a <div> <span> element.
*
diff --git a/user/src/com/google/gwt/user/client/ui/Label.java b/user/src/com/google/gwt/user/client/ui/Label.java
index 9811f76..8d94dde 100644
--- a/user/src/com/google/gwt/user/client/ui/Label.java
+++ b/user/src/com/google/gwt/user/client/ui/Label.java
@@ -42,11 +42,7 @@
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.i18n.client.BidiUtils;
import com.google.gwt.i18n.client.HasDirection;
-import com.google.gwt.i18n.shared.BidiFormatter;
import com.google.gwt.i18n.shared.DirectionEstimator;
-import com.google.gwt.i18n.shared.HasDirectionEstimator;
-import com.google.gwt.i18n.shared.WordCountDirectionEstimator;
-import com.google.gwt.safehtml.shared.SafeHtml;
/**
* A widget that contains arbitrary text, <i>not</i> interpreted as HTML.
@@ -54,6 +50,14 @@
* This widget uses a <div> element, causing it to be displayed with block
* layout.
*
+ * <p>
+ * <h3>Built-in Bidi Text Support</h3>
+ * This widget is capable of automatically adjusting its direction according to
+ * its content. This feature is controlled by {@link #setDirectionEstimator} or
+ * passing a DirectionEstimator parameter to the constructor, and is off by
+ * default.
+ * </p>
+ *
* <h3>CSS Style Rules</h3>
* <ul class='css'>
* <li>.gwt-Label { }</li>
@@ -65,10 +69,12 @@
* </p>
*/
@SuppressWarnings("deprecation")
-public class Label extends Widget implements HasDirectionalText, HasWordWrap,
+public class Label extends LabelBase<String> implements HasDirectionalText,
HasDirection, HasClickHandlers, HasDoubleClickHandlers, SourcesClickEvents,
- SourcesMouseEvents, HasAllMouseHandlers, HasDirectionEstimator,
- HasAutoHorizontalAlignment, IsEditor<LeafValueEditor<String>> {
+ SourcesMouseEvents, HasAllMouseHandlers, IsEditor<LeafValueEditor<String>> {
+
+ public static final DirectionEstimator DEFAULT_DIRECTION_ESTIMATOR =
+ DirectionalTextHelper.DEFAULT_DIRECTION_ESTIMATOR;
/**
* Creates a Label widget that wraps an existing <div> or <span>
@@ -93,69 +99,14 @@
return label;
}
- /**
- * The widget's auto horizontal alignment policy.
- * @see HasAutoHorizontalAlignment
- */
- private AutoHorizontalAlignmentConstant autoHorizontalAlignment;
-
- /**
- * The direction of the widget's content.
- * Note: this may not match the direction of the widget's top DOM element
- * ({@code getElement()}).
- * See {@link #setTextOrHtml(String, Direction, boolean)} for details.
- */
- private Direction textDir;
-
- /**
- * The widget's DirectionEstimator object.
- */
- private DirectionEstimator directionEstimator;
-
- /**
- * The widget's horizontal alignment.
- */
- private HorizontalAlignmentConstant horzAlign;
-
- /**
- * The initial direction of the widget's element.
- */
- private Direction initialElementDir;
-
- /**
- * Whether the widget is inline (a <span> element).
- * This is needed because direction is handled differently for inline elements
- * and for non-inline elements.
- * <p>
- * In case Label supports types of elements other than span and div, this
- * should get true for any element that is inline by default. Another approach
- * could be calculating the element's display property, but this may have some
- * overhead, and is problematic when the element is yet unattached.
- */
- private boolean isElementInline;
-
- /**
- * Whether the widget contains a nested <span> element used to
- * indicate the content's direction.
- * <p>
- * The widget's top element is used for this purpose when it is a <div>,
- * but doing so on an inline element often results in garbling what follows
- * it. Thus, when the widget's top element is a <span>, a nested
- * <span> must be used to carry the content's direction, with an LRM or
- * RLM character afterwards to prevent the garbling.
- */
- private boolean isSpanWrapped;
+ private LeafValueEditor<String> editor;
/**
* Creates an empty label.
*/
public Label() {
- setElement(Document.get().createDivElement());
+ super(false);
setStyleName("gwt-Label");
- isElementInline = false;
- isSpanWrapped = false;
- textDir = Direction.DEFAULT;
- initialElementDir = Direction.DEFAULT;
}
/**
@@ -173,7 +124,7 @@
*
* @param text the new label's text
* @param dir the text's direction. Note that {@code DEFAULT} means direction
- * should be inherited from the widget's parent element.
+ * should be inherited from the widget's parent element.
*/
public Label(String text, Direction dir) {
this();
@@ -181,6 +132,20 @@
}
/**
+ * Creates a label with the specified text and a default direction estimator.
+ *
+ * @param text the new label's text
+ * @param directionEstimator A DirectionEstimator object used for automatic
+ * direction adjustment. For convenience,
+ * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used.
+ */
+ public Label(String text, DirectionEstimator directionEstimator) {
+ this();
+ setDirectionEstimator(directionEstimator);
+ setText(text);
+ }
+
+ /**
* Creates a label with the specified text.
*
* @param text the new label's text
@@ -198,13 +163,7 @@
* @param element the element to be used
*/
protected Label(Element element) {
- setElement(element);
- String tagName = element.getTagName();
- isElementInline = tagName.equalsIgnoreCase("span");
- assert isElementInline || tagName.equalsIgnoreCase("div");
- isSpanWrapped = false;
- initialElementDir = BidiUtils.getDirectionOnElement(element);
- textDir = initialElementDir;
+ super(element);
}
public HandlerRegistration addClickHandler(ClickHandler handler) {
@@ -266,14 +225,10 @@
}
public LeafValueEditor<String> asEditor() {
- return HasTextEditor.of(this);
- }
-
- /**
- * {@inheritDoc}
- */
- public AutoHorizontalAlignmentConstant getAutoHorizontalAlignment() {
- return autoHorizontalAlignment;
+ if (editor == null) {
+ editor = HasTextEditor.of(this);
+ }
+ return editor;
}
/**
@@ -285,27 +240,12 @@
return BidiUtils.getDirectionOnElement(getElement());
}
- public DirectionEstimator getDirectionEstimator() {
- return directionEstimator;
- }
-
- /**
- * {@inheritDoc}
- */
- public HorizontalAlignmentConstant getHorizontalAlignment() {
- return horzAlign;
- }
-
public String getText() {
- return getTextOrHtml(false);
+ return directionalTextHelper.getTextOrHtml(false);
}
public Direction getTextDirection() {
- return textDir;
- }
-
- public boolean getWordWrap() {
- return !getElement().getStyle().getProperty("whiteSpace").equals("nowrap");
+ return directionalTextHelper.getTextDirection();
}
/**
@@ -336,82 +276,29 @@
}
/**
- * {@inheritDoc}
- */
- public void setAutoHorizontalAlignment(AutoHorizontalAlignmentConstant
- autoAlignment) {
- autoHorizontalAlignment = autoAlignment;
- updateHorizontalAlignment();
- }
-
- /**
* Sets the widget element's direction.
* @deprecated Use {@link #setDirectionEstimator} and / or pass explicit
* direction to {@link #setText} instead
*/
@Deprecated
public void setDirection(Direction direction) {
- BidiUtils.setDirectionOnElement(getElement(), direction);
- initialElementDir = direction;
-
- // For backwards compatibility, assure there's no span wrap, and update the
- // content direction.
- setInnerTextOrHtml(getTextOrHtml(true), true);
- isSpanWrapped = false;
- textDir = initialElementDir;
+ directionalTextHelper.setDirection(direction);
updateHorizontalAlignment();
}
/**
- * {@inheritDoc}
- * <p>
- * See note at {@link #setDirectionEstimator(DirectionEstimator)}.
- */
- public void setDirectionEstimator(boolean enabled) {
- setDirectionEstimator(enabled ? WordCountDirectionEstimator.get() : null);
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Note: if the widget already has non-empty content, this will update
- * its direction according to the new estimator's result. This may cause
- * flicker, and thus should be avoided; DirectionEstimator should be set
- * before the widget has any content.
- */
- public void setDirectionEstimator(DirectionEstimator directionEstimator) {
- this.directionEstimator = directionEstimator;
- // Refresh appearance
- setTextOrHtml(getTextOrHtml(true), true);
- }
-
- /**
- * {@inheritDoc}
- *
- * <p> Note: A subsequent call to {@link #setAutoHorizontalAlignment} may
- * override the horizontal alignment set by this method.
- * <p> Note: For {@code null}, the horizontal alignment is cleared, allowing
- * it to be determined by the standard HTML mechanisms such as inheritance and
- * CSS rules.
- * @see #setAutoHorizontalAlignment
- */
- public void setHorizontalAlignment(HorizontalAlignmentConstant align) {
- setAutoHorizontalAlignment(align);
- }
-
- /**
* Sets the label's content to the given text.
* <p>
* Doesn't change the widget's direction or horizontal alignment if {@code
* directionEstimator} is null. Otherwise, the widget's direction is set using
* the estimator, and its alignment may therefore change as described in
- * {@link #setText(String, com.google.gwt.i18n.client.HasDirection.Direction)
- * setText(String, Direction)}.
- *
+ * {@link #setText(String, com.google.gwt.i18n.client.HasDirection.Direction) setText(String, Direction)}.
+ *
* @param text the widget's new text
*/
public void setText(String text) {
- setTextOrHtml(text, false);
+ directionalTextHelper.setTextOrHtml(text, false);
+ updateHorizontalAlignment();
}
/**
@@ -435,141 +322,7 @@
* direction should be inherited from the widget's parent element.
*/
public void setText(String text, Direction dir) {
- setTextOrHtml(text, dir, false);
- }
-
- public void setWordWrap(boolean wrap) {
- getElement().getStyle().setProperty("whiteSpace",
- wrap ? "normal" : "nowrap");
- }
-
- protected String getTextOrHtml(boolean isHtml) {
- Element element = isSpanWrapped ? getElement().getFirstChildElement()
- : getElement();
- return isHtml ? element.getInnerHTML() : element.getInnerText();
- }
-
- /**
- * Sets the label's content to the given safe html. See
- * {@link #setText(String)} for details on potential effects on direction and
- * alignment.
- *
- * @param html the widget's new safe html
- */
- protected void setHTML(SafeHtml html) {
- setTextOrHtml(html.asString(), true);
- }
-
- /**
- * Sets the label's content to the given safe html. See
- * {@link #setText(String)} for details on potential effects on direction and
- * alignment.
- *
- * @param html the widget's new safe html
- * @param dir the content's direction
- */
- protected void setHTML(SafeHtml html, Direction dir) {
- setTextOrHtml(html.asString(), dir, true);
- }
-
- /**
- * Sets the label's content to the given value (either plain text or HTML).
- * See {@link #setText(String)} for details on potential effects on direction
- * and alignment.
- *
- * @param content the widget's new content
- * @param isHtml whether the content is HTML
- */
- protected void setTextOrHtml(String content, boolean isHtml) {
- if (directionEstimator == null) {
- isSpanWrapped = false;
- setInnerTextOrHtml(content, isHtml);
-
- // Preserves the initial direction of the widget. This is different from
- // passing the direction parameter explicitly as DEFAULT, which forces the
- // widget to inherit the direction from its parent.
- if (textDir != initialElementDir) {
- textDir = initialElementDir;
- BidiUtils.setDirectionOnElement(getElement(), initialElementDir);
- updateHorizontalAlignment();
- }
- } else {
- setTextOrHtml(content, directionEstimator.estimateDirection(content,
- isHtml), isHtml);
- }
- }
-
- /**
- * Sets the label's content to the given value (either plain text or HTML),
- * applying the given direction. See
- * {@link #setText(String, com.google.gwt.i18n.client.HasDirection.Direction)
- * setText(String, Direction)} for details on potential effects on alignment.
- * <p>
- * Implementation details:
- * <ul>
- * <li>If the widget's element is a <div>, sets its dir attribute
- * according to the given direction.
- * <li>Otherwise (i.e. the widget's element is a <span>), the direction
- * is set using a nested <span dir=...> element which holds the content
- * of the widget. This nested span may be followed by a zero-width Unicode
- * direction character (LRM or RLM). This manipulation is necessary to prevent
- * garbling in case the direction of the widget is opposite to the direction
- * of its context. See {@link com.google.gwt.i18n.shared.BidiFormatter} for
- * more details.
- * </ul>
- *
- * @param content the widget's new content
- * @param dir the content's direction
- * @param isHtml whether the content is HTML
- */
- protected void setTextOrHtml(String content, Direction dir, boolean isHtml) {
- textDir = dir;
-
- // Set the text and the direction.
- if (isElementInline) {
- isSpanWrapped = true;
- getElement().setInnerHTML(BidiFormatter.getInstanceForCurrentLocale(
- true /* alwaysSpan */).spanWrapWithKnownDir(dir, content, isHtml));
- } else {
- isSpanWrapped = false;
- BidiUtils.setDirectionOnElement(getElement(), dir);
- setInnerTextOrHtml(content, isHtml);
- }
-
- // Update the horizontal alignment if needed.
+ directionalTextHelper.setTextOrHtml(text, dir, false);
updateHorizontalAlignment();
}
-
- private void setInnerTextOrHtml(String content, boolean isHtml) {
- if (isHtml) {
- getElement().setInnerHTML(content);
- } else {
- getElement().setInnerText(content);
- }
- }
-
- /**
- * Sets the horizontal alignment of the widget according to the current
- * AutoHorizontalAlignment setting.
- */
- private void updateHorizontalAlignment() {
- HorizontalAlignmentConstant align;
- if (autoHorizontalAlignment == null) {
- align = null;
- } else if (autoHorizontalAlignment instanceof HorizontalAlignmentConstant) {
- align = (HorizontalAlignmentConstant) autoHorizontalAlignment;
- } else {
- /* autoHorizontalAlignment is a truly automatic policy, i.e. either
- ALIGN_CONTENT_START or ALIGN_CONTENT_END */
- align = autoHorizontalAlignment == ALIGN_CONTENT_START ?
- HorizontalAlignmentConstant.startOf(textDir) :
- HorizontalAlignmentConstant.endOf(textDir);
- }
-
- if (align != horzAlign) {
- horzAlign = align;
- getElement().getStyle().setProperty("textAlign", horzAlign == null ? ""
- : horzAlign.getTextAlignString());
- }
- }
}
diff --git a/user/src/com/google/gwt/user/client/ui/LabelBase.java b/user/src/com/google/gwt/user/client/ui/LabelBase.java
new file mode 100644
index 0000000..4f15d3f
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/LabelBase.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2010 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.client.ui;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.i18n.shared.DirectionEstimator;
+import com.google.gwt.i18n.shared.HasDirectionEstimator;
+
+/**
+ * Abstract base class for all text display widgets.
+ *
+ * <h3>Use in UiBinder Templates</h3>
+ *
+ * @param <T> the value type
+ */
+public class LabelBase<T> extends Widget implements HasWordWrap,
+ HasDirectionEstimator, HasAutoHorizontalAlignment {
+
+ /**
+ * The widget's DirectionalTextHelper object.
+ */
+ final DirectionalTextHelper directionalTextHelper;
+
+ /**
+ * The widget's auto horizontal alignment policy.
+ *
+ * @see HasAutoHorizontalAlignment
+ */
+ private AutoHorizontalAlignmentConstant autoHorizontalAlignment;
+
+ /**
+ * The widget's horizontal alignment.
+ */
+ private HorizontalAlignmentConstant horzAlign;
+
+ protected LabelBase(boolean inline) {
+ this(inline ? Document.get().createSpanElement()
+ : Document.get().createDivElement(), inline);
+ }
+
+ protected LabelBase(Element element) {
+ this(element, "span".equalsIgnoreCase(element.getTagName()));
+ }
+
+ private LabelBase(Element element, boolean isElementInline) {
+ assert (isElementInline ? "span" : "div").equalsIgnoreCase(element.getTagName());
+ setElement(element);
+ directionalTextHelper = new DirectionalTextHelper(getElement(),
+ isElementInline);
+ }
+
+ public AutoHorizontalAlignmentConstant getAutoHorizontalAlignment() {
+ return autoHorizontalAlignment;
+ }
+
+ public DirectionEstimator getDirectionEstimator() {
+ return directionalTextHelper.getDirectionEstimator();
+ }
+
+ public HorizontalAlignmentConstant getHorizontalAlignment() {
+ return horzAlign;
+ }
+
+ public boolean getWordWrap() {
+ return !getElement().getStyle().getProperty("whiteSpace").equals("nowrap");
+ }
+
+ public void setAutoHorizontalAlignment(
+ AutoHorizontalAlignmentConstant autoAlignment) {
+ autoHorizontalAlignment = autoAlignment;
+ updateHorizontalAlignment();
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * See note at {@link #setDirectionEstimator(DirectionEstimator)}.
+ */
+ public void setDirectionEstimator(boolean enabled) {
+ directionalTextHelper.setDirectionEstimator(enabled);
+ updateHorizontalAlignment();
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Note: DirectionEstimator should be set before the widget has any content;
+ * it's highly recommended to set it using a constructor. Reason: if the
+ * widget already has non-empty content, this will update its direction
+ * according to the new estimator's result. This may cause flicker, and thus
+ * should be avoided.
+ */
+ public void setDirectionEstimator(DirectionEstimator directionEstimator) {
+ directionalTextHelper.setDirectionEstimator(directionEstimator);
+ updateHorizontalAlignment();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>
+ * Note: A subsequent call to {@link #setAutoHorizontalAlignment} may override
+ * the horizontal alignment set by this method.
+ * <p>
+ * Note: For {@code null}, the horizontal alignment is cleared, allowing it to
+ * be determined by the standard HTML mechanisms such as inheritance and CSS
+ * rules.
+ *
+ * @see #setAutoHorizontalAlignment
+ */
+ public void setHorizontalAlignment(HorizontalAlignmentConstant align) {
+ setAutoHorizontalAlignment(align);
+ }
+
+ public void setWordWrap(boolean wrap) {
+ getElement().getStyle().setProperty("whiteSpace",
+ wrap ? "normal" : "nowrap");
+ }
+
+ /**
+ * Sets the horizontal alignment of the widget according to the current
+ * AutoHorizontalAlignment setting. Should be invoked whenever the horizontal
+ * alignment may be affected, i.e. on every modification of the content or its
+ * direction.
+ */
+ protected void updateHorizontalAlignment() {
+ HorizontalAlignmentConstant align;
+ if (autoHorizontalAlignment == null) {
+ align = null;
+ } else if (autoHorizontalAlignment instanceof HorizontalAlignmentConstant) {
+ align = (HorizontalAlignmentConstant) autoHorizontalAlignment;
+ } else {
+ /*
+ * autoHorizontalAlignment is a truly automatic policy, i.e. either
+ * ALIGN_CONTENT_START or ALIGN_CONTENT_END
+ */
+ align = autoHorizontalAlignment == ALIGN_CONTENT_START
+ ? HorizontalAlignmentConstant.startOf(directionalTextHelper.getTextDirection())
+ : HorizontalAlignmentConstant.endOf(directionalTextHelper.getTextDirection());
+ }
+
+ if (align != horzAlign) {
+ horzAlign = align;
+ getElement().getStyle().setProperty("textAlign",
+ horzAlign == null ? "" : horzAlign.getTextAlignString());
+ }
+ }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/NumberLabel.java b/user/src/com/google/gwt/user/client/ui/NumberLabel.java
new file mode 100644
index 0000000..ad398ca
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/NumberLabel.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2010 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.client.ui;
+
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.text.client.NumberFormatRenderer;
+
+/**
+ * Extends {@link ValueLabel} for convenience when dealing with numbers and
+ * {@link NumberFormat}, especially in
+ * {@link com.google.gwt.uibinder.client.UiBinder UiBinder} templates. (Note
+ * that this class does not accept renderers. To do so use {@link ValueLabel}
+ * directly.)
+ *
+ * <h3>Use in UiBinder Templates</h3> In
+ * {@link com.google.gwt.uibinder.client.UiBinder UiBinder} templates, the
+ * {@link NumberFormat} can be specified with one of these attributes:
+ * <dl>
+ * <dt>format</dt>
+ * <dd>a reference to a {@link NumberFormat} instance.</dd>
+ * <dt>predefinedFormat</dt>
+ * <dd>a predefined format (see below for the list of acceptable values).</dd>
+ * <dt>customFormat</dt>
+ * <dd>a number format pattern that can be passed to
+ * {@link NumberFormat#getFormat(String)}. See below for a way of specifying a
+ * currency code.</dd>
+ * </dl>
+ * The valid values for the {@code predefinedFormat} attributes are:
+ * <dl>
+ * <dt>DECIMAL</dt>
+ * <dd>the standard decimal format for the current locale, as given by
+ * {@link NumberFormat#getDecimalFormat()}.</dd>
+ * <dt>CURRENCY</dt>
+ * <dd>the standard currency format for the current locale, as given by
+ * {@link NumberFormat#getCurrencyFormat()}. See below for a way of specifying a
+ * currency code.</dd>
+ * <dt>PERCENT</dt>
+ * <dd>the standard percent format for the current locale, as given by
+ * {@link NumberFormat#getPercentFormat()}.</dd>
+ * <dt>SCIENTIFIC</dt>
+ * <dd>the standard scientific format for the current locale, as given by
+ * {@link NumberFormat#getScientificFormat()}.</dd>
+ * </dl>
+ * When using {@code predefinedFormat="CURRENCY"} or a {@code customFormat}, you
+ * can specify a currency code using either of the following attributes:
+ * <dl>
+ * <dt>currencyData</dt>
+ * <dd>a reference to a {@link com.google.gwt.i18n.client.CurrencyData
+ * CurrencyData} instance.</dd>
+ * <dt>currencyCode</dt>
+ * <dd>an ISO4217 currency code.</dd>
+ * </dl>
+ *
+ * @param <T> The exact type of number
+ */
+public class NumberLabel<T extends Number> extends ValueLabel<T> {
+
+ public NumberLabel() {
+ super(new NumberFormatRenderer());
+ }
+
+ public NumberLabel(NumberFormat format) {
+ super(new NumberFormatRenderer(format));
+ }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/SimpleCheckBox.java b/user/src/com/google/gwt/user/client/ui/SimpleCheckBox.java
index 4bc465c..4975554 100644
--- a/user/src/com/google/gwt/user/client/ui/SimpleCheckBox.java
+++ b/user/src/com/google/gwt/user/client/ui/SimpleCheckBox.java
@@ -18,6 +18,10 @@
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.InputElement;
+import com.google.gwt.editor.client.IsEditor;
+import com.google.gwt.editor.client.LeafValueEditor;
+import com.google.gwt.editor.client.adapters.TakesValueEditor;
+import com.google.gwt.user.client.TakesValue;
/**
* A simple checkbox widget, with no label.
@@ -28,7 +32,8 @@
* <li>.gwt-SimpleCheckBox-disabled { Applied when checkbox is disabled }</li>
* </ul>
*/
-public class SimpleCheckBox extends FocusWidget implements HasName {
+public class SimpleCheckBox extends FocusWidget implements HasName,
+ TakesValue<Boolean>, IsEditor<LeafValueEditor<Boolean>> {
/**
* Creates a SimpleCheckBox widget that wraps an existing <input
@@ -53,6 +58,8 @@
return checkBox;
}
+ private LeafValueEditor<Boolean> editor;
+
/**
* Creates a new simple checkbox.
*/
@@ -79,28 +86,66 @@
}
}
+ public LeafValueEditor<Boolean> asEditor() {
+ if (editor == null) {
+ editor = TakesValueEditor.of(this);
+ }
+ return editor;
+ }
+
+ /**
+ * Returns the value property of the input element that backs this widget.
+ * This is the value that will be associated with the check box name and
+ * submitted to the server if a {@link FormPanel} that holds it is submitted
+ * and the box is checked.
+ * <p>
+ * Don't confuse this with {@link #getValue}, which returns true or false if
+ * the widget is checked.
+ */
+ public String getFormValue() {
+ return getInputElement().getValue();
+ }
+
public String getName() {
return getInputElement().getName();
}
/**
* Determines whether this check box is currently checked.
+ * <p>
+ * Note that this <em>does not</em> return the value property of the checkbox
+ * input element wrapped by this widget. For access to that property, see
+ * {@link #getFormValue()}
*
- * @return <code>true</code> if the check box is checked
+ * @return <code>true</code> if the check box is checked, false otherwise.
+ * Will not return null
*/
- public boolean isChecked() {
+ public Boolean getValue() {
String propName = isAttached() ? "checked" : "defaultChecked";
return getInputElement().getPropertyBoolean(propName);
}
/**
+ * Determines whether this check box is currently checked.
+ *
+ * @return <code>true</code> if the check box is checked
+ * @deprecated Use {@link #getValue} instead
+ */
+ @Deprecated
+ public boolean isChecked() {
+ // Funny comparison b/c getValue could in theory return null
+ return getValue() == true;
+ }
+
+ /**
* Checks or unchecks this check box.
*
* @param checked <code>true</code> to check the check box
+ * @deprecated Use {@link #setValue(Boolean)} instead
*/
+ @Deprecated
public void setChecked(boolean checked) {
- getInputElement().setChecked(checked);
- getInputElement().setDefaultChecked(checked);
+ setValue(checked);
}
@Override
@@ -113,18 +158,50 @@
}
}
+ /**
+ * Set the value property on the input element that backs this widget. This is
+ * the value that will be associated with the check box's name and submitted
+ * to the server if a {@link FormPanel} that holds it is submitted and the box
+ * is checked.
+ * <p>
+ * Don't confuse this with {@link #setValue}, which actually checks and
+ * unchecks the box.
+ *
+ * @param value
+ */
+ public void setFormValue(String value) {
+ getInputElement().setAttribute("value", value);
+ }
+
public void setName(String name) {
getInputElement().setName(name);
}
/**
+ * Checks or unchecks the check box.
+ * <p>
+ * Note that this <em>does not</em> set the value property of the checkbox
+ * input element wrapped by this widget. For access to that property, see
+ * {@link #setFormValue(String)}
+ *
+ * @param value true to check, false to uncheck; null value implies false
+ */
+ public void setValue(Boolean value) {
+ if (value == null) {
+ value = Boolean.FALSE;
+ }
+
+ getInputElement().setChecked(value);
+ getInputElement().setDefaultChecked(value);
+ }
+
+ /**
* This method is called when a widget is detached from the browser's
- * document. Overridden because of IE bug that throws away checked state and
- * in order to clear the event listener off of the <code>inputElem</code>.
+ * document. Overridden because of IE bug that throws away checked state.
*/
@Override
protected void onUnload() {
- setChecked(isChecked());
+ setValue(getValue());
}
private InputElement getInputElement() {
diff --git a/user/src/com/google/gwt/user/client/ui/SuggestBox.java b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
index a291aec..919a5f5 100644
--- a/user/src/com/google/gwt/user/client/ui/SuggestBox.java
+++ b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
@@ -657,6 +657,7 @@
private boolean selectsFirstItem = true;
private SuggestOracle oracle;
private String currentText;
+ private LeafValueEditor<String> editor;
private final SuggestionDisplay display;
private final TextBoxBase box;
private final Callback callback = new Callback() {
@@ -814,7 +815,10 @@
* Returns a {@link TakesValueEditor} backed by the DateBox.
*/
public LeafValueEditor<String> asEditor() {
- return TakesValueEditor.of(this);
+ if (editor == null) {
+ editor = TakesValueEditor.of(this);
+ }
+ return editor;
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/TabPanel.java b/user/src/com/google/gwt/user/client/ui/TabPanel.java
index 1253cdf..fc609e9 100644
--- a/user/src/com/google/gwt/user/client/ui/TabPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/TabPanel.java
@@ -59,17 +59,12 @@
* {@example com.google.gwt.examples.TabPanelExample}
* </p>
*
- * @deprecated Use {@link TabLayoutPanel} instead, but understand that it is
- * not a drop in replacement for this class. It requires standards
- * mode, and is most easily used under a {@link RootLayoutPanel} (as
- * opposed to a {@link RootPanel}
- *
* @see TabLayoutPanel
*/
// Cannot do anything about tab panel implementing TabListener until next
// release
-@Deprecated
+@SuppressWarnings("deprecation")
public class TabPanel extends Composite implements TabListener,
SourcesTabEvents, HasWidgets, HasAnimation, IndexedPanel.ForIsWidget,
HasBeforeSelectionHandlers<Integer>, HasSelectionHandlers<Integer> {
diff --git a/user/src/com/google/gwt/user/client/ui/ToggleButton.java b/user/src/com/google/gwt/user/client/ui/ToggleButton.java
index 3ce977b..b337f3f 100644
--- a/user/src/com/google/gwt/user/client/ui/ToggleButton.java
+++ b/user/src/com/google/gwt/user/client/ui/ToggleButton.java
@@ -16,6 +16,9 @@
package com.google.gwt.user.client.ui;
+import com.google.gwt.editor.client.IsEditor;
+import com.google.gwt.editor.client.LeafValueEditor;
+import com.google.gwt.editor.client.adapters.TakesValueEditor;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
@@ -40,9 +43,11 @@
* <h3>Example</h3> {@example com.google.gwt.examples.ToggleButtonExample}
* </p>
*/
-public class ToggleButton extends CustomButton implements HasValue<Boolean> {
+public class ToggleButton extends CustomButton implements HasValue<Boolean>, IsEditor<LeafValueEditor<Boolean>> {
private static String STYLENAME_DEFAULT = "gwt-ToggleButton";
+ private LeafValueEditor<Boolean> editor;
+
{
setStyleName(STYLENAME_DEFAULT);
}
@@ -182,6 +187,13 @@
return addHandler(handler, ValueChangeEvent.getType());
}
+ public LeafValueEditor<Boolean> asEditor() {
+ if (editor == null) {
+ editor = TakesValueEditor.of(this);
+ }
+ return editor;
+ }
+
/**
* Determines whether this button is currently down.
*
diff --git a/user/src/com/google/gwt/user/client/ui/ValueBoxBase.java b/user/src/com/google/gwt/user/client/ui/ValueBoxBase.java
index d24f2a3..05d416e 100644
--- a/user/src/com/google/gwt/user/client/ui/ValueBoxBase.java
+++ b/user/src/com/google/gwt/user/client/ui/ValueBoxBase.java
@@ -45,7 +45,6 @@
*
* @param <T> the value type
*/
-@SuppressWarnings("deprecation")
public class ValueBoxBase<T> extends FocusWidget implements
HasChangeHandlers, HasName, HasDirectionEstimator,
HasValue<T>, AutoDirectionHandler.Target, IsEditor<ValueBoxEditor<T>> {
@@ -83,6 +82,7 @@
private final Parser<T> parser;
private final Renderer<T> renderer;
+ private ValueBoxEditor<T> editor;
private Event currentEvent;
private boolean valueChangeHandlerInitialized;
@@ -125,7 +125,10 @@
* Editor framework.
*/
public ValueBoxEditor<T> asEditor() {
- return ValueBoxEditor.of(this);
+ if (editor == null) {
+ editor = ValueBoxEditor.of(this);
+ }
+ return editor;
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/ValueLabel.java b/user/src/com/google/gwt/user/client/ui/ValueLabel.java
new file mode 100644
index 0000000..92e29db
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/ValueLabel.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2010 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.client.ui;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.editor.client.IsEditor;
+import com.google.gwt.editor.client.LeafValueEditor;
+import com.google.gwt.editor.client.adapters.TakesValueEditor;
+import com.google.gwt.text.shared.Parser;
+import com.google.gwt.text.shared.Renderer;
+import com.google.gwt.uibinder.client.UiConstructor;
+import com.google.gwt.user.client.TakesValue;
+
+import java.text.ParseException;
+
+/**
+ * A label displaying its value through a renderer.
+ *
+ * @param <T> the value type.
+ */
+public class ValueLabel<T> extends LabelBase<T> implements TakesValue<T>,
+ IsEditor<LeafValueEditor<T>> {
+
+ /**
+ * Creates a ValueLabel widget that wraps an existing <span> element.
+ * <p>
+ * The ValueLabel's value will be <code>null</code>, whether the element being
+ * wrapped has content or not. Use {@link #wrap(Element, Renderer, Parser)} to
+ * parse the initial element's content to initialize the ValueLabel's value.
+ * <p>
+ * This element must already be attached to the document. If the element is
+ * removed from the document, you must call
+ * {@link RootPanel#detachNow(Widget)}.
+ *
+ * @param element the element to be wrapped
+ * @param renderer the renderer used to render values into the element
+ */
+ public static <T> ValueLabel<T> wrap(Element element,
+ Renderer<? super T> renderer) {
+ // Assert that the element is attached.
+ assert Document.get().getBody().isOrHasChild(element);
+
+ ValueLabel<T> label = new ValueLabel<T>(element, renderer);
+
+ // Mark it attached and remember it for cleanup.
+ label.onAttach();
+ RootPanel.detachOnWindowClose(label);
+
+ return label;
+ }
+
+ /**
+ * Creates a ValueLabel widget that wraps an existing <span> element.
+ * <p>
+ * The ValueLabel's value will be initialized with the element's content,
+ * passed through the <code>parser</code>.
+ * <p>
+ * This element must already be attached to the document. If the element is
+ * removed from the document, you must call
+ * {@link RootPanel#detachNow(Widget)}.
+ *
+ * @param element the element to be wrapped
+ * @param renderer the renderer used to render values into the element
+ * @param parser the parser used to initialize the ValueLabel's value from the
+ * element's content
+ */
+ public static <T> ValueLabel<T> wrap(Element element,
+ Renderer<? super T> renderer, Parser<? extends T> parser)
+ throws ParseException {
+ ValueLabel<T> label = wrap(element, renderer);
+
+ label.setValue(parser.parse(element.getInnerText()));
+
+ // Mark it attached and remember it for cleanup.
+ label.onAttach();
+ RootPanel.detachOnWindowClose(label);
+
+ return label;
+ }
+
+ private final Renderer<? super T> renderer;
+ private T value;
+ private LeafValueEditor<T> editor;
+
+ /**
+ * Creates an empty value label.
+ *
+ * @param inline
+ * @param renderer
+ */
+ @UiConstructor
+ public ValueLabel(Renderer<? super T> renderer) {
+ super(true);
+ this.renderer = renderer;
+ }
+
+ /**
+ * This constructor may be used by subclasses to explicitly use an existing
+ * element. This element must be either a <span> or a <div>
+ * element.
+ *
+ * @param element the element to be used
+ */
+ protected ValueLabel(Element element, Renderer<? super T> renderer) {
+ super(element);
+ this.renderer = renderer;
+ }
+
+ public LeafValueEditor<T> asEditor() {
+ if (editor == null) {
+ editor = TakesValueEditor.of(this);
+ }
+ return editor;
+ }
+
+ public T getValue() {
+ return value;
+ }
+
+ public void setValue(T value) {
+ this.value = value;
+ directionalTextHelper.setTextOrHtml(renderer.render(value), false);
+ updateHorizontalAlignment();
+ }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/client/ui/ValueListBox.java b/user/src/com/google/gwt/user/client/ui/ValueListBox.java
index 24b8b93..4fffa9a 100644
--- a/user/src/com/google/gwt/user/client/ui/ValueListBox.java
+++ b/user/src/com/google/gwt/user/client/ui/ValueListBox.java
@@ -49,6 +49,7 @@
private final Renderer<T> renderer;
private final ProvidesKey<T> keyProvider;
+ private TakesValueEditor<T> editor;
private T value;
public ValueListBox(Renderer<T> renderer) {
@@ -81,7 +82,10 @@
* Returns a {@link TakesValueEditor} backed by the ValueListBox.
*/
public TakesValueEditor<T> asEditor() {
- return TakesValueEditor.of(this);
+ if (editor == null) {
+ editor = TakesValueEditor.of(this);
+ }
+ return editor;
}
public T getValue() {
diff --git a/user/src/com/google/gwt/user/client/ui/ValuePicker.java b/user/src/com/google/gwt/user/client/ui/ValuePicker.java
index 8003cec..45ced21 100644
--- a/user/src/com/google/gwt/user/client/ui/ValuePicker.java
+++ b/user/src/com/google/gwt/user/client/ui/ValuePicker.java
@@ -47,7 +47,7 @@
}
@Override
- public void render(T value, Object viewData, SafeHtmlBuilder sb) {
+ public void render(Context context, T value, SafeHtmlBuilder sb) {
sb.appendEscaped(renderer.render(value));
}
}
@@ -56,6 +56,7 @@
private final CellList<T> cellList;
private SingleSelectionModel<T> smodel = new SingleSelectionModel<T>();
+ private LeafValueEditor<T> editor;
public ValuePicker(CellList<T> cellList) {
this.cellList = cellList;
@@ -80,7 +81,10 @@
* Returns a {@link TakesValueEditor} backed by the ValuePicker.
*/
public LeafValueEditor<T> asEditor() {
- return TakesValueEditor.of(this);
+ if (editor == null) {
+ editor = TakesValueEditor.of(this);
+ }
+ return editor;
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/Widget.java b/user/src/com/google/gwt/user/client/ui/Widget.java
index e0138a0..18082ab 100644
--- a/user/src/com/google/gwt/user/client/ui/Widget.java
+++ b/user/src/com/google/gwt/user/client/ui/Widget.java
@@ -55,7 +55,6 @@
*/
int eventsToSink;
private boolean attached;
- @SuppressWarnings("deprecation")
private HandlerManager handlerManager;
private Object layoutData;
private Widget parent;
@@ -74,7 +73,6 @@
* @param handler the handler
* @return {@link HandlerRegistration} used to remove the handler
*/
- @SuppressWarnings("deprecation")
public final <H extends EventHandler> HandlerRegistration addDomHandler(
final H handler, DomEvent.Type<H> type) {
assert handler != null : "handler must not be null";
@@ -91,7 +89,6 @@
* @param handler the handler
* @return {@link HandlerRegistration} used to remove the handler
*/
- @SuppressWarnings("deprecation")
public final <H extends EventHandler> HandlerRegistration addHandler(
final H handler, GwtEvent.Type<H> type) {
return ensureHandlers().addHandler(type, handler);
@@ -101,7 +98,6 @@
return this;
}
- @SuppressWarnings("deprecation")
public void fireEvent(GwtEvent<?> event) {
if (handlerManager != null) {
handlerManager.fireEvent(event);
@@ -228,7 +224,6 @@
*
* @return the {@link HandlerManager} you want to use
*/
- @SuppressWarnings("deprecation")
protected com.google.gwt.event.shared.HandlerManager createHandlerManager() {
return new com.google.gwt.event.shared.HandlerManager(this);
}
@@ -272,7 +267,6 @@
* @param type the event type
* @return the number of registered handlers
*/
- @SuppressWarnings("deprecation")
protected int getHandlerCount(Type<?> type) {
return handlerManager == null ? 0 : handlerManager.getHandlerCount(type);
}
@@ -396,13 +390,11 @@
*
* @return the handler manager
* */
- @SuppressWarnings("deprecation")
com.google.gwt.event.shared.HandlerManager ensureHandlers() {
return handlerManager == null ? handlerManager = createHandlerManager()
: handlerManager;
}
- @SuppressWarnings("deprecation")
com.google.gwt.event.shared.HandlerManager getHandlerManager() {
return handlerManager;
}
diff --git a/user/src/com/google/gwt/user/datepicker/client/DateBox.java b/user/src/com/google/gwt/user/datepicker/client/DateBox.java
index c9ebf25..3d6b25b 100644
--- a/user/src/com/google/gwt/user/datepicker/client/DateBox.java
+++ b/user/src/com/google/gwt/user/datepicker/client/DateBox.java
@@ -249,6 +249,7 @@
private final PopupPanel popup;
private final TextBox box = new TextBox();
private final DatePicker picker;
+ private LeafValueEditor<Date> editor;
private Format format;
private boolean allowDPShow = true;
@@ -298,7 +299,10 @@
* Returns a {@link TakesValueEditor} backed by the DateBox.
*/
public LeafValueEditor<Date> asEditor() {
- return TakesValueEditor.of(this);
+ if (editor == null) {
+ editor = TakesValueEditor.of(this);
+ }
+ return editor;
}
/**
diff --git a/user/src/com/google/gwt/user/datepicker/client/DatePicker.java b/user/src/com/google/gwt/user/datepicker/client/DatePicker.java
index ddb55a4..439875a 100644
--- a/user/src/com/google/gwt/user/datepicker/client/DatePicker.java
+++ b/user/src/com/google/gwt/user/datepicker/client/DatePicker.java
@@ -253,6 +253,7 @@
private Date value;
private Date highlighted;
private StandardCss css = StandardCss.DEFAULT;
+ private LeafValueEditor<Date> editor;
/**
* Create a new date picker.
@@ -381,7 +382,10 @@
* Returns a {@link TakesValueEditor} backed by the DatePicker.
*/
public LeafValueEditor<Date> asEditor() {
- return TakesValueEditor.of(this);
+ if (editor == null) {
+ editor = TakesValueEditor.of(this);
+ }
+ return editor;
}
/**
diff --git a/user/src/com/google/gwt/view/client/CellPreviewEvent.java b/user/src/com/google/gwt/view/client/CellPreviewEvent.java
index d2fcc06..aa486a2 100644
--- a/user/src/com/google/gwt/view/client/CellPreviewEvent.java
+++ b/user/src/com/google/gwt/view/client/CellPreviewEvent.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.view.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
@@ -55,39 +56,17 @@
* @param source the source of the handlers
* @param nativeEvent the event to preview
* @param display the {@link HasData} source of the event
- * @param index the index of the value where the event occurred
+ * @param context the Cell {@link Context}
* @param value the value where the event occurred
* @param isCellEditing indicates whether or not the cell is being edited
* @param isSelectionHandled indicates whether or not selection is handled
* @return the {@link CellPreviewEvent} that was fired
*/
public static <T> CellPreviewEvent<T> fire(HasCellPreviewHandlers<T> source,
- NativeEvent nativeEvent, HasData<T> display, int index, T value,
+ NativeEvent nativeEvent, HasData<T> display, Context context, T value,
boolean isCellEditing, boolean isSelectionHandled) {
- return fire(source, nativeEvent, display, index, 0, value, isCellEditing,
- isSelectionHandled);
- }
-
- /**
- * Fires a cell preview event on all registered handlers in the handler
- * manager. If no such handlers exist, this implementation will do nothing.
- *
- * @param <T> the old value type
- * @param source the source of the handlers
- * @param nativeEvent the event to preview
- * @param display the {@link HasData} source of the event
- * @param index the index of the value where the event occurred
- * @param column the column index
- * @param value the value where the event occurred
- * @param isCellEditing indicates whether or not the cell is being edited
- * @param isSelectionHandled indicates whether or not selection is handled
- * @return the {@link CellPreviewEvent} that was fired
- */
- public static <T> CellPreviewEvent<T> fire(HasCellPreviewHandlers<T> source,
- NativeEvent nativeEvent, HasData<T> display, int index, int column,
- T value, boolean isCellEditing, boolean isSelectionHandled) {
CellPreviewEvent<T> event = new CellPreviewEvent<T>(nativeEvent, display,
- index, column, value, isCellEditing, isSelectionHandled);
+ context, value, isCellEditing, isSelectionHandled);
if (TYPE != null) {
source.fireEvent(event);
}
@@ -106,9 +85,8 @@
return TYPE;
}
- private final int column;
+ private final Context context;
private final HasData<T> display;
- private final int index;
private boolean isCanceled = false;
private final boolean isCellEditing;
private final boolean isSelectionHandled;
@@ -120,18 +98,17 @@
*
* @param nativeEvent the event to preview
* @param display the {@link HasData} source of the event
- * @param index the index of the value where the event occurred
+ * @param context the Cell {@link Context}
* @param value the value where the event occurred
* @param isCellEditing indicates whether or not the cell is being edited
* @param isSelectionHandled indicates whether or not selection is handled
*/
protected CellPreviewEvent(NativeEvent nativeEvent, HasData<T> display,
- int index, int column, T value, boolean isCellEditing,
+ Context context, T value, boolean isCellEditing,
boolean isSelectionHandled) {
this.nativeEvent = nativeEvent;
this.display = display;
- this.index = index;
- this.column = column;
+ this.context = context;
this.value = value;
this.isCellEditing = isCellEditing;
this.isSelectionHandled = isSelectionHandled;
@@ -152,7 +129,16 @@
* @return the column index, or 0 if there is only one column
*/
public int getColumn() {
- return column;
+ return context.getColumn();
+ }
+
+ /**
+ * Get the cell {@link Context}.
+ *
+ * @return the cell {@link Context}
+ */
+ public Context getContext() {
+ return context;
}
/**
@@ -166,7 +152,7 @@
* Get the index of the value where the event occurred.
*/
public int getIndex() {
- return index;
+ return context.getIndex();
}
/**
diff --git a/user/super/com/google/gwt/autobean/super/com/google/gwt/autobean/shared/ValueCodexHelper.java b/user/super/com/google/gwt/autobean/super/com/google/gwt/autobean/shared/ValueCodexHelper.java
new file mode 100644
index 0000000..42c87e3
--- /dev/null
+++ b/user/super/com/google/gwt/autobean/super/com/google/gwt/autobean/shared/ValueCodexHelper.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2010 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.autobean.shared;
+
+/**
+ * A no-op super-source version of ValueCodexHelper for web-mode compilations.
+ */
+class ValueCodexHelper {
+ /**
+ * Returns {@code false}.
+ */
+ static boolean canDecode(Class<?> clazz) {
+ return false;
+ }
+}
diff --git a/user/test/com/google/gwt/cell/client/AbstractCellTest.java b/user/test/com/google/gwt/cell/client/AbstractCellTest.java
index 1414369..5520e79 100644
--- a/user/test/com/google/gwt/cell/client/AbstractCellTest.java
+++ b/user/test/com/google/gwt/cell/client/AbstractCellTest.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.cell.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
@@ -27,7 +28,8 @@
Cell<String> cell = createCell();
String value = createCellValue();
Element parent = Document.get().createDivElement();
- cell.setValue(parent, value, null);
+ Context context = new Context(0, 0, null);
+ cell.setValue(context, parent, value);
assertEquals(getExpectedInnerHtml(), parent.getInnerHTML());
}
diff --git a/user/test/com/google/gwt/cell/client/ActionCellTest.java b/user/test/com/google/gwt/cell/client/ActionCellTest.java
index b8cdfa7..474375e 100644
--- a/user/test/com/google/gwt/cell/client/ActionCellTest.java
+++ b/user/test/com/google/gwt/cell/client/ActionCellTest.java
@@ -16,6 +16,7 @@
package com.google.gwt.cell.client;
import com.google.gwt.cell.client.ActionCell.Delegate;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
@@ -49,7 +50,8 @@
Element parent = Document.get().createDivElement();
NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false,
false, false, false);
- cell.onBrowserEvent(parent, "test", DEFAULT_KEY, event, null);
+ Context context = new Context(0, 0, DEFAULT_KEY);
+ cell.onBrowserEvent(context, parent, "test", event, null);
delegate.assertLastObject("test");
}
diff --git a/user/test/com/google/gwt/cell/client/CellTestBase.java b/user/test/com/google/gwt/cell/client/CellTestBase.java
index cdbee13..733b1e5 100644
--- a/user/test/com/google/gwt/cell/client/CellTestBase.java
+++ b/user/test/com/google/gwt/cell/client/CellTestBase.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.cell.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
@@ -41,7 +42,9 @@
static class MockCell<T> extends AbstractCell<T> {
private final boolean isSelectable;
+ private Context lastContext;
private T lastEventValue;
+ private Element lastParentElement;
private final T updateValue;
public MockCell(boolean isSelectable, T updateValue,
@@ -55,19 +58,30 @@
assertEquals(expected, lastEventValue);
}
+ public void assertLastParentElement(Element expected) {
+ assertEquals(expected, lastParentElement);
+ }
+
+
@Override
public boolean dependsOnSelection() {
return isSelectable;
}
+ public Context getLastContext() {
+ return lastContext;
+ }
+
@Override
public boolean handlesSelection() {
return isSelectable;
}
@Override
- public void onBrowserEvent(Element parent, T value, Object key,
+ public void onBrowserEvent(Context context, Element parent, T value,
NativeEvent event, ValueUpdater<T> valueUpdater) {
+ lastContext = context;
+ lastParentElement = parent;
lastEventValue = value;
if (valueUpdater != null) {
valueUpdater.update(updateValue);
@@ -75,7 +89,8 @@
}
@Override
- public void render(T value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, T value, SafeHtmlBuilder sb) {
+ lastContext = context;
if (value != null) {
sb.appendEscaped(String.valueOf(value));
}
@@ -139,7 +154,20 @@
Cell<T> cell = createCell();
T value = createCellValue();
SafeHtmlBuilder sb = new SafeHtmlBuilder();
- cell.render(value, null, sb);
+ Context context = new Context(0, 0, null);
+ cell.render(context, value, sb);
+ assertEquals(getExpectedInnerHtml(), sb.toSafeHtml().asString());
+ }
+
+ /**
+ * Test rendering the cell with a negative index is handled.
+ */
+ public void testRenderNegativeIndex() {
+ Cell<T> cell = createCell();
+ T value = createCellValue();
+ SafeHtmlBuilder sb = new SafeHtmlBuilder();
+ Context context = new Context(-1, -1, null);
+ cell.render(context, value, sb);
assertEquals(getExpectedInnerHtml(), sb.toSafeHtml().asString());
}
@@ -149,7 +177,8 @@
public void testRenderNull() {
Cell<T> cell = createCell();
SafeHtmlBuilder sb = new SafeHtmlBuilder();
- cell.render(null, null, sb);
+ Context context = new Context(0, 0, null);
+ cell.render(context, null, sb);
assertEquals(getExpectedInnerHtmlNull(), sb.toSafeHtml().asString());
}
@@ -225,7 +254,8 @@
public void onBrowserEvent(Event event) {
try {
DOM.setEventListener(parent, null);
- createCell().onBrowserEvent(parent, value, DEFAULT_KEY, event,
+ Context context = new Context(0, 0, DEFAULT_KEY);
+ createCell().onBrowserEvent(context, parent, value, event,
valueUpdater);
parent.removeFromParent();
} catch (Exception e) {
diff --git a/user/test/com/google/gwt/cell/client/CompositeCellTest.java b/user/test/com/google/gwt/cell/client/CompositeCellTest.java
index a56e6ef..a40461c 100644
--- a/user/test/com/google/gwt/cell/client/CompositeCellTest.java
+++ b/user/test/com/google/gwt/cell/client/CompositeCellTest.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.cell.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
@@ -109,7 +110,8 @@
// Add an event listener.
EventListener listener = new EventListener() {
public void onBrowserEvent(Event event) {
- cell.onBrowserEvent(parent, "test", DEFAULT_KEY, event, null);
+ Context context = new Context(3, 4, "key");
+ cell.onBrowserEvent(context, parent, "test", event, null);
}
};
DOM.sinkEvents(parent, Event.ONCLICK);
@@ -120,6 +122,11 @@
false, false, false);
Element.as(parent.getChild(1)).dispatchEvent(event);
innerCell.assertLastEventValue("test-1");
+ innerCell.assertLastParentElement(Element.as(parent.getChild(1)));
+ Context innerContext = innerCell.getLastContext();
+ assertEquals("key", innerContext.getKey());
+ assertEquals(3, innerContext.getIndex());
+ assertEquals(4, innerContext.getColumn());
// Remove the element and event listener.
DOM.setEventListener(parent, null);
@@ -130,7 +137,8 @@
Cell<String> cell = createCell();
Element parent = Document.get().createDivElement();
parent.setInnerHTML(getExpectedInnerHtml());
- cell.setValue(parent, "test", null);
+ Context context = new Context( 0, 0, null);
+ cell.setValue(context, parent, "test");
assertEquals(3, parent.getChildCount());
assertEquals("test-0", Element.as(parent.getChild(0)).getInnerHTML());
diff --git a/user/test/com/google/gwt/cell/client/EditTextCellTest.java b/user/test/com/google/gwt/cell/client/EditTextCellTest.java
index 8925a5d..c088c71 100644
--- a/user/test/com/google/gwt/cell/client/EditTextCellTest.java
+++ b/user/test/com/google/gwt/cell/client/EditTextCellTest.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.cell.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.cell.client.EditTextCell.ViewData;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
@@ -35,7 +36,8 @@
ViewData viewData = new ViewData("originalValue");
viewData.setText("newValue");
cell.setViewData(DEFAULT_KEY, viewData);
- cell.edit(parent, "originalValue", DEFAULT_KEY);
+ Context context = new Context(0, 0, DEFAULT_KEY);
+ cell.edit(context, parent, "originalValue");
// Verify the input element.
Element child = parent.getFirstChildElement();
@@ -130,7 +132,8 @@
viewData.setEditing(false);
cell.setViewData(DEFAULT_KEY, viewData);
SafeHtmlBuilder sb = new SafeHtmlBuilder();
- cell.render("originalValue", DEFAULT_KEY, sb);
+ Context context = new Context(0, 0, DEFAULT_KEY);
+ cell.render(context, "originalValue", sb);
assertEquals("newValue", sb.toSafeHtml().asString());
}
diff --git a/user/test/com/google/gwt/cell/client/EditableCellTestBase.java b/user/test/com/google/gwt/cell/client/EditableCellTestBase.java
index 1eddda7..f1c6230 100644
--- a/user/test/com/google/gwt/cell/client/EditableCellTestBase.java
+++ b/user/test/com/google/gwt/cell/client/EditableCellTestBase.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.cell.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
@@ -39,7 +40,8 @@
T value = createCellValue();
cell.setViewData(DEFAULT_KEY, createCellViewData());
SafeHtmlBuilder sb = new SafeHtmlBuilder();
- cell.render(value, DEFAULT_KEY, sb);
+ Context context = new Context(0, 0, DEFAULT_KEY);
+ cell.render(context, value, sb);
String expectedInnerHtmlViewData = getExpectedInnerHtmlViewData();
String asString = sb.toSafeHtml().asString();
assertEquals(expectedInnerHtmlViewData, asString);
@@ -96,7 +98,8 @@
public void onBrowserEvent(Event event) {
try {
DOM.setEventListener(parent, null);
- cell.onBrowserEvent(parent, value, DEFAULT_KEY, event, valueUpdater);
+ Context context = new Context(0, 0, DEFAULT_KEY);
+ cell.onBrowserEvent(context, parent, value, event, valueUpdater);
parent.removeFromParent();
} catch (Exception e) {
// We are in an event loop, so events may not propagate out to JUnit.
diff --git a/user/test/com/google/gwt/cell/client/IconCellDecoratorTest.java b/user/test/com/google/gwt/cell/client/IconCellDecoratorTest.java
index 79c656a..054b751 100644
--- a/user/test/com/google/gwt/cell/client/IconCellDecoratorTest.java
+++ b/user/test/com/google/gwt/cell/client/IconCellDecoratorTest.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.cell.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
@@ -62,7 +63,8 @@
// Render the cell.
SafeHtmlBuilder sb = new SafeHtmlBuilder();
- cell.render("helloworld", null, sb);
+ Context context = new Context(0, 0, null);
+ cell.render(context, "helloworld", sb);
// Compare the expected render string.
String expected = "<div style=\"position:relative;padding-left:64px;\">";
@@ -88,7 +90,8 @@
parent.setInnerHTML(getExpectedInnerHtml());
assertEquals("helloworld",
Element.as(parent.getFirstChildElement().getChild(1)).getInnerHTML());
- cell.setValue(parent, "test", null);
+ Context context = new Context(0, 0, null);
+ cell.setValue(context, parent, "test");
assertEquals("test",
Element.as(parent.getFirstChildElement().getChild(1)).getInnerHTML());
}
diff --git a/user/test/com/google/gwt/cell/client/ImageLoadingCellTest.java b/user/test/com/google/gwt/cell/client/ImageLoadingCellTest.java
index 8d0d606..87d7beb 100644
--- a/user/test/com/google/gwt/cell/client/ImageLoadingCellTest.java
+++ b/user/test/com/google/gwt/cell/client/ImageLoadingCellTest.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.cell.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.ImageElement;
@@ -30,7 +31,8 @@
Cell<String> cell = createCell();
String value = createCellValue();
SafeHtmlBuilder sb = new SafeHtmlBuilder();
- cell.render(value, null, sb);
+ Context context = new Context(0, 0, null);
+ cell.render(context, value, sb);
// Render the html.
Element elem = Document.get().createDivElement();
@@ -45,6 +47,26 @@
}
@Override
+ public void testRenderNegativeIndex() {
+ Cell<String> cell = createCell();
+ String value = createCellValue();
+ SafeHtmlBuilder sb = new SafeHtmlBuilder();
+ Context context = new Context(-1, -1, null);
+ cell.render(context, value, sb);
+
+ // Render the html.
+ Element elem = Document.get().createDivElement();
+ elem.setInnerHTML(sb.toSafeHtml().asString());
+
+ // Verify the image.
+ assertEquals(2, elem.getChildCount());
+ Element imgWrapper = elem.getChild(1).cast();
+ ImageElement img = imgWrapper.getFirstChildElement().cast();
+ assertEquals("img", img.getTagName().toLowerCase());
+ assertTrue(img.getSrc().toLowerCase().endsWith("test.png"));
+ }
+
+ @Override
protected Cell<String> createCell() {
return new ImageLoadingCell();
}
diff --git a/user/test/com/google/gwt/editor/client/adapters/ListEditorWrapperTest.java b/user/test/com/google/gwt/editor/client/adapters/ListEditorWrapperTest.java
index b787449..8c8c2a1 100644
--- a/user/test/com/google/gwt/editor/client/adapters/ListEditorWrapperTest.java
+++ b/user/test/com/google/gwt/editor/client/adapters/ListEditorWrapperTest.java
@@ -44,6 +44,9 @@
Object o1 = new Object();
wrapper.add(o1);
+ assertEquals(0, backing.size());
+ wrapper.flush();
+ assertEquals(1, backing.size());
assertSame(o1, backing.get(0));
FakeLeafValueEditor<Object> editor1 = wrapper.getEditors().get(0);
assertSame(o1, editor1.getValue());
@@ -52,6 +55,9 @@
Object o0 = new Object();
wrapper.add(0, o0);
+ assertEquals(1, backing.size());
+ wrapper.flush();
+ assertEquals(2, backing.size());
assertSame(o0, backing.get(0));
assertSame(o1, backing.get(1));
FakeLeafValueEditor<Object> editor0 = wrapper.getEditors().get(0);
@@ -112,6 +118,9 @@
assertSame(o2, e2.getValue());
wrapper.remove(1);
+ assertEquals(Arrays.asList(o0, o1, o2), backing);
+ assertEquals(Arrays.asList(e0, e2), wrapper.getEditors());
+ wrapper.flush();
assertEquals(Arrays.asList(o0, o2), backing);
assertEquals(Arrays.asList(e0, e2), wrapper.getEditors());
assertFalse(chain.isAttached(e1));
@@ -119,6 +128,8 @@
assertEquals(1, source.getLastKnownPosition(e2));
wrapper.set(1, o1);
+ assertEquals(Arrays.asList(o0, o2), backing);
+ wrapper.flush();
assertEquals(Arrays.asList(o0, o1), backing);
// Re-use existing editor
assertEquals(Arrays.asList(e0, e2), wrapper.getEditors());
diff --git a/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java b/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java
index c158123..61d7071 100644
--- a/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java
+++ b/user/test/com/google/gwt/requestfactory/RequestFactoryJreSuite.java
@@ -21,6 +21,7 @@
import com.google.gwt.requestfactory.server.LocatorJreTest;
import com.google.gwt.requestfactory.server.RequestFactoryInterfaceValidatorTest;
import com.google.gwt.requestfactory.server.RequestFactoryJreTest;
+import com.google.gwt.requestfactory.server.RequestFactoryUnicodeEscapingJreTest;
import com.google.gwt.requestfactory.shared.impl.SimpleEntityProxyIdTest;
import junit.framework.Test;
@@ -40,6 +41,7 @@
suite.addTestSuite(SimpleEntityProxyIdTest.class);
suite.addTestSuite(RequestFactoryInterfaceValidatorTest.class);
suite.addTestSuite(RequestFactoryModelTest.class);
+ suite.addTestSuite(RequestFactoryUnicodeEscapingJreTest.class);
return suite;
}
}
diff --git a/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java b/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java
index cbb5558..884d005 100644
--- a/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java
+++ b/user/test/com/google/gwt/requestfactory/RequestFactorySuite.java
@@ -20,6 +20,7 @@
import com.google.gwt.requestfactory.client.RequestFactoryExceptionHandlerTest;
import com.google.gwt.requestfactory.client.RequestFactoryPolymorphicTest;
import com.google.gwt.requestfactory.client.RequestFactoryTest;
+import com.google.gwt.requestfactory.client.RequestFactoryUnicodeEscapingTest;
import com.google.gwt.requestfactory.client.ui.EditorTest;
import com.google.gwt.requestfactory.shared.ComplexKeysTest;
import com.google.gwt.requestfactory.shared.LocatorTest;
@@ -40,6 +41,7 @@
suite.addTestSuite(RequestFactoryTest.class);
suite.addTestSuite(RequestFactoryExceptionHandlerTest.class);
suite.addTestSuite(RequestFactoryPolymorphicTest.class);
+ suite.addTestSuite(RequestFactoryUnicodeEscapingTest.class);
return suite;
}
}
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryExceptionHandlerTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryExceptionHandlerTest.java
index b05e36b..a8b9371 100644
--- a/user/test/com/google/gwt/requestfactory/client/RequestFactoryExceptionHandlerTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryExceptionHandlerTest.java
@@ -25,6 +25,8 @@
*/
public class RequestFactoryExceptionHandlerTest extends RequestFactoryTest {
+ private static final int DELAY_TEST_FINISH = 5000;
+
@Override
public String getModuleName() {
return "com.google.gwt.requestfactory.RequestFactoryExceptionHandlerTest";
@@ -32,7 +34,7 @@
@Override
public void testServerFailureCheckedException() {
- delayTestFinish(5000);
+ delayTestFinish(DELAY_TEST_FINISH);
SimpleFooRequest context = req.simpleFooRequest();
SimpleFooProxy rayFoo = context.create(SimpleFooProxy.class);
final Request<SimpleFooProxy> persistRay = context.persistAndReturnSelf().using(
@@ -46,7 +48,7 @@
@Override
public void testServerFailureRuntimeException() {
- delayTestFinish(5000);
+ delayTestFinish(DELAY_TEST_FINISH);
SimpleFooRequest context = req.simpleFooRequest();
SimpleFooProxy rayFoo = context.create(SimpleFooProxy.class);
final Request<SimpleFooProxy> persistRay = context.persistAndReturnSelf().using(
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
index b512857..5d0cb95 100644
--- a/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
+++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryTest.java
@@ -32,11 +32,16 @@
import com.google.gwt.requestfactory.shared.Violation;
import com.google.gwt.requestfactory.shared.impl.SimpleEntityProxyId;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Time;
+import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -172,7 +177,7 @@
}
}
- private static final int DELAY_TEST_FINISH = 5000;
+ private static final int DELAY_TEST_FINISH = 10 * 1000;
public <T extends EntityProxy> void assertContains(Collection<T> col, T value) {
EntityProxyId<?> lookFor = value.stableId();
@@ -517,6 +522,41 @@
});
}
+ /**
+ * Check default value, a newly-set value, and a null value.
+ */
+ public void testEnumProperty() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ simpleFooRequest().findSimpleFooById(999L).fire(
+ new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy response) {
+ assertEquals(SimpleEnum.FOO, response.getEnumField());
+ SimpleFooRequest ctx = simpleFooRequest();
+ response = ctx.edit(response);
+ response.setEnumField(SimpleEnum.BAR);
+ ctx.persistAndReturnSelf().using(response).fire(
+ new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy response) {
+ assertEquals(SimpleEnum.BAR, response.getEnumField());
+ SimpleFooRequest ctx = simpleFooRequest();
+ response = ctx.edit(response);
+ response.setEnumField(null);
+ ctx.persistAndReturnSelf().using(response).fire(
+ new Receiver<SimpleFooProxy>() {
+ @Override
+ public void onSuccess(SimpleFooProxy response) {
+ assertNull(response.getEnumField());
+ finishTestAndReset();
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+
public void testFetchEntity() {
delayTestFinish(DELAY_TEST_FINISH);
simpleFooRequest().findSimpleFooById(999L).fire(
@@ -581,7 +621,7 @@
}
public void testFindFindEdit() {
- delayTestFinish(5000);
+ delayTestFinish(DELAY_TEST_FINISH);
final SimpleFooEventHandler<SimpleFooProxy> handler = new SimpleFooEventHandler<SimpleFooProxy>();
EntityProxyChange.registerForProxyType(req.getEventBus(),
@@ -687,6 +727,7 @@
public void testHistoryToken() {
delayTestFinish(DELAY_TEST_FINISH);
+
SimpleBarRequest context = simpleBarRequest();
final SimpleBarProxy foo = context.create(SimpleBarProxy.class);
final EntityProxyId<SimpleBarProxy> futureId = foo.stableId();
@@ -726,10 +767,22 @@
});
}
+ public void testInstanceServiceRequest() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ req.instanceServiceRequest().add(5).fire(new Receiver<Integer>() {
+ @Override
+ public void onSuccess(Integer response) {
+ assertEquals(10, (int) response);
+ finishTestAndReset();
+ }
+ });
+ }
+
/**
* Make sure our stock RF logging service keeps receiving.
*/
public void testLoggingService() {
+ delayTestFinish(DELAY_TEST_FINISH);
String logRecordJson = new StringBuilder("{") //
.append("\"level\": \"ALL\", ") //
.append("\"loggerName\": \"logger\", ") //
@@ -1121,6 +1174,11 @@
});
}
+ /*
+ * TODO: all these tests should check the final values. It will be easy when
+ * we have better persistence than the singleton pattern.
+ */
+
/**
* Ensure that a relationship can be set up between two newly-created objects.
*/
@@ -1147,11 +1205,6 @@
}
/*
- * TODO: all these tests should check the final values. It will be easy when
- * we have better persistence than the singleton pattern.
- */
-
- /*
* Find Entity2 Create Entity, Persist Entity Relate Entity2 to Entity Persist
* Entity
*/
@@ -1383,6 +1436,11 @@
});
}
+ /*
+ * TODO: all these tests should check the final values. It will be easy when
+ * we have better persistence than the singleton pattern.
+ */
+
public void testPersistValueList() {
delayTestFinish(DELAY_TEST_FINISH);
simpleFooRequest().findSimpleFooById(999L).fire(
@@ -1446,11 +1504,6 @@
* TODO: all these tests should check the final values. It will be easy when
* we have better persistence than the singleton pattern.
*/
-
- /*
- * TODO: all these tests should check the final values. It will be easy when
- * we have better persistence than the singleton pattern.
- */
public void testPersistValueListRemove() {
delayTestFinish(DELAY_TEST_FINISH);
simpleFooRequest().findSimpleFooById(999L).fire(
@@ -1753,20 +1806,71 @@
});
}
+ public void testPrimitiveListBigDecimalAsParameter() {
+ delayTestFinish(DELAY_TEST_FINISH);
+
+ // Keep these values in sync with SimpleFoo.processBigIntegerList
+ final List<BigDecimal> testList = new ArrayList<BigDecimal>();
+ testList.add(BigDecimal.TEN);
+ testList.add(new BigDecimal("12345.6789") {
+ // This is an anonymous subtype
+ });
+ simpleFooRequest().processBigDecimalList(testList).fire(
+ new Receiver<List<BigDecimal>>() {
+ @Override
+ public void onSuccess(List<BigDecimal> response) {
+ // Check upcasted values only
+ assertEquals(testList, response);
+ finishTestAndReset();
+ }
+ });
+ }
+
+ public void testPrimitiveListBigIntegerAsParameter() {
+ delayTestFinish(DELAY_TEST_FINISH);
+
+ // Keep these values in sync with SimpleFoo.processBigIntegerList
+ final List<BigInteger> testList = new ArrayList<BigInteger>();
+ testList.add(BigInteger.TEN);
+ testList.add(new BigInteger("12345") {
+ // This is an anonymous subtype
+ });
+ simpleFooRequest().processBigIntegerList(testList).fire(
+ new Receiver<List<BigInteger>>() {
+ @Override
+ public void onSuccess(List<BigInteger> response) {
+ // Check upcasted values only
+ assertEquals(testList, response);
+ finishTestAndReset();
+ }
+ });
+ }
+
+ @SuppressWarnings("deprecation")
public void testPrimitiveListDateAsParameter() {
delayTestFinish(DELAY_TEST_FINISH);
- @SuppressWarnings("deprecation")
- final Date date = new Date(90, 0, 1);
- Request<Date> procReq = simpleFooRequest().processDateList(
- Arrays.asList(date));
- procReq.fire(new Receiver<Date>() {
- @Override
- public void onSuccess(Date response) {
- assertEquals(date, response);
- finishTestAndReset();
- }
- });
+ // Keep these values in sync with SimpleFoo.processDateList
+ Date date = new Date(90, 0, 1);
+ java.sql.Date sqlDate = new java.sql.Date(90, 0, 2);
+ Time sqlTime = new Time(1, 2, 3);
+ Timestamp sqlTimestamp = new Timestamp(12345L);
+ final List<Date> testList = Arrays.asList(date, sqlDate, sqlTime,
+ sqlTimestamp);
+ simpleFooRequest().processDateList(testList).fire(
+ new Receiver<List<Date>>() {
+ @Override
+ public void onSuccess(List<Date> response) {
+ // Check upcasted values only
+ assertEquals(testList.size(), response.size());
+ Iterator<Date> expected = testList.iterator();
+ Iterator<Date> actual = response.iterator();
+ while (expected.hasNext()) {
+ assertEquals(expected.next().getTime(), actual.next().getTime());
+ }
+ finishTestAndReset();
+ }
+ });
}
public void testPrimitiveListEnumAsParameter() {
@@ -1886,6 +1990,8 @@
}
public void testServerFailureCheckedException() {
+ delayTestFinish(DELAY_TEST_FINISH);
+
SimpleFooRequest context = simpleFooRequest();
SimpleFooProxy newFoo = context.create(SimpleFooProxy.class);
final Request<SimpleFooProxy> persistRequest = context.persistAndReturnSelf().using(
@@ -2035,26 +2141,6 @@
}
/**
- * We provide a simple UserInformation class to give GAE developers a hand,
- * and other developers a hint. Make sure RF doesn't break it (it relies on
- * server side upcasting, and a somewhat sleazey reflective lookup mechanism
- * in a static method on UserInformation).
- */
- public void testUserInfo() {
- req.userInformationRequest().getCurrentUserInformation("").fire(
- new Receiver<UserInformationProxy>() {
- @Override
- public void onSuccess(UserInformationProxy response) {
- response = checkSerialization(response);
- assertEquals("Dummy Email", response.getEmail());
- assertEquals("Dummy User", response.getName());
- assertEquals("", response.getLoginUrl());
- assertEquals("", response.getLogoutUrl());
- }
- });
- }
-
- /**
* Check if a graph of unpersisted objects can be echoed.
*/
public void testUnpersistedEchoComplexGraph() {
@@ -2194,6 +2280,28 @@
});
}
+ /**
+ * We provide a simple UserInformation class to give GAE developers a hand,
+ * and other developers a hint. Make sure RF doesn't break it (it relies on
+ * server side upcasting, and a somewhat sleazey reflective lookup mechanism
+ * in a static method on UserInformation).
+ */
+ public void testUserInfo() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ req.userInformationRequest().getCurrentUserInformation("").fire(
+ new Receiver<UserInformationProxy>() {
+ @Override
+ public void onSuccess(UserInformationProxy response) {
+ response = checkSerialization(response);
+ assertEquals("Dummy Email", response.getEmail());
+ assertEquals("Dummy User", response.getName());
+ assertEquals("", response.getLoginUrl());
+ assertEquals("", response.getLogoutUrl());
+ finishTestAndReset();
+ }
+ });
+ }
+
public void testValueObjectCreateSetRetrieveUpdate() {
delayTestFinish(DELAY_TEST_FINISH);
SimpleFooRequest req = simpleFooRequest();
@@ -2335,6 +2443,48 @@
checkEqualityAndHashcode(a, b);
}
+ /**
+ * Since a ValueProxy cannot be passed into RequestContext edit, a proxy
+ * returned from a service method should be mutable by default.
+ */
+ public void testValueObjectReturnedFromRequestIsImmutable() {
+ delayTestFinish(DELAY_TEST_FINISH);
+ simpleFooRequest().returnValueProxy().fire(
+ new Receiver<SimpleValueProxy>() {
+ @Override
+ public void onSuccess(SimpleValueProxy a) {
+ a = checkSerialization(a);
+ try {
+ a.setNumber(77);
+ fail();
+ } catch (IllegalStateException expected) {
+ }
+ try {
+ // Ensure Dates comply with ValueProxy mutation behaviors
+ a.getDate().setTime(1);
+ fail();
+ } catch (IllegalStateException expected) {
+ }
+ SimpleFooRequest ctx = simpleFooRequest();
+ final SimpleValueProxy toCheck = ctx.edit(a);
+ toCheck.setNumber(77);
+ toCheck.getDate().setTime(1);
+ ctx.returnValueProxy().fire(new Receiver<SimpleValueProxy>() {
+ @Override
+ public void onSuccess(SimpleValueProxy b) {
+ b = checkSerialization(b);
+ b = simpleFooRequest().edit(b);
+ // Now check that same value is equal across contexts
+ b.setNumber(77);
+ b.setDate(new Date(1));
+ checkEqualityAndHashcode(toCheck, b);
+ finishTestAndReset();
+ }
+ });
+ }
+ });
+ }
+
public void testValueObjectViolationsOnCreate() {
delayTestFinish(DELAY_TEST_FINISH);
SimpleFooRequest req = simpleFooRequest();
@@ -2395,48 +2545,6 @@
});
}
- /**
- * Since a ValueProxy cannot be passed into RequestContext edit, a proxy
- * returned from a service method should be mutable by default.
- */
- public void testValueObjectReturnedFromRequestIsImmutable() {
- delayTestFinish(DELAY_TEST_FINISH);
- simpleFooRequest().returnValueProxy().fire(
- new Receiver<SimpleValueProxy>() {
- @Override
- public void onSuccess(SimpleValueProxy a) {
- a = checkSerialization(a);
- try {
- a.setNumber(77);
- fail();
- } catch (IllegalStateException expected) {
- }
- try {
- // Ensure Dates comply with ValueProxy mutation behaviors
- a.getDate().setTime(1);
- fail();
- } catch (IllegalStateException expected) {
- }
- SimpleFooRequest ctx = simpleFooRequest();
- final SimpleValueProxy toCheck = ctx.edit(a);
- toCheck.setNumber(77);
- toCheck.getDate().setTime(1);
- ctx.returnValueProxy().fire(new Receiver<SimpleValueProxy>() {
- @Override
- public void onSuccess(SimpleValueProxy b) {
- b = checkSerialization(b);
- b = simpleFooRequest().edit(b);
- // Now check that same value is equal across contexts
- b.setNumber(77);
- b.setDate(new Date(1));
- checkEqualityAndHashcode(toCheck, b);
- finishTestAndReset();
- }
- });
- }
- });
- }
-
public void testViolationAbsent() {
delayTestFinish(DELAY_TEST_FINISH);
diff --git a/user/test/com/google/gwt/requestfactory/client/RequestFactoryUnicodeEscapingTest.java b/user/test/com/google/gwt/requestfactory/client/RequestFactoryUnicodeEscapingTest.java
new file mode 100644
index 0000000..44de4ed
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/client/RequestFactoryUnicodeEscapingTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2010 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.requestfactory.client;
+
+import com.google.gwt.requestfactory.shared.Receiver;
+import com.google.gwt.requestfactory.shared.ServerFailure;
+import com.google.gwt.user.client.rpc.UnicodeEscapingService.InvalidCharacterException;
+import com.google.gwt.user.client.rpc.UnicodeEscapingTest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Runs through a portion of the Basic Multilingual Plane.
+ */
+public class RequestFactoryUnicodeEscapingTest extends RequestFactoryTestBase {
+ private static final int TEST_FINISH_DELAY_MS = 5000;
+ private final UnicodeEscapingTest test = new UnicodeEscapingTest() {
+
+ @Override
+ protected void clientToServerVerifyRange(int start, final int end,
+ final int size, final int step) throws InvalidCharacterException {
+ current = start;
+ int blockEnd = Math.min(end, current + size);
+ req.unicodeTestRequest().verifyStringContainingCharacterRange(current,
+ blockEnd, getStringContainingCharacterRange(start, blockEnd)).fire(
+ new Receiver<Void>() {
+ List<ServerFailure> fails = new ArrayList<ServerFailure>();
+
+ @Override
+ public void onFailure(ServerFailure error) {
+ fails.add(error);
+ onSuccess(null);
+ }
+
+ @Override
+ public void onSuccess(Void response) {
+ current += step;
+ if (current < end) {
+ delayTestFinish(TEST_FINISH_DELAY_MS);
+ int blockEnd = Math.min(end, current + size);
+ req.unicodeTestRequest().verifyStringContainingCharacterRange(
+ current, blockEnd,
+ getStringContainingCharacterRange(current, blockEnd)).fire(
+ this);
+ } else if (!fails.isEmpty()) {
+ StringBuilder msg = new StringBuilder();
+ for (ServerFailure error : fails) {
+ msg.append(error.getMessage()).append("\n");
+ }
+ throw new RuntimeException(msg.toString());
+ } else {
+ finishTest();
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void serverToClientVerify(int start, final int end,
+ final int size, final int step) {
+ current = start;
+ req.unicodeTestRequest().getStringContainingCharacterRange(start,
+ Math.min(end, current + size)).fire(new Receiver<String>() {
+ List<ServerFailure> fails = new ArrayList<ServerFailure>();
+
+ @Override
+ public void onFailure(ServerFailure error) {
+ fails.add(error);
+ nextBatch();
+ }
+
+ @Override
+ public void onSuccess(String response) {
+ try {
+ verifyStringContainingCharacterRange(current,
+ Math.min(end, current + size), response);
+ } catch (InvalidCharacterException e) {
+ fails.add(new ServerFailure(e.getMessage(), null, null));
+ }
+ nextBatch();
+ }
+
+ private void nextBatch() {
+ current += step;
+ if (current < end) {
+ delayTestFinish(TEST_FINISH_DELAY_MS);
+ req.unicodeTestRequest().getStringContainingCharacterRange(current,
+ Math.min(end, current + size)).fire(this);
+ } else if (!fails.isEmpty()) {
+ StringBuilder msg = new StringBuilder();
+ for (ServerFailure t : fails) {
+ msg.append(t.getMessage()).append("\n");
+ }
+ throw new RuntimeException(msg.toString());
+ } else {
+ finishTest();
+ }
+ }
+ });
+ }
+ };
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.requestfactory.RequestFactorySuite";
+ }
+
+ public void testClientToServerBMPHigh() throws InvalidCharacterException {
+ test.testClientToServerBMPHigh();
+ }
+
+ public void testClientToServerBMPLow() throws InvalidCharacterException {
+ test.testClientToServerBMPLow();
+ }
+
+ public void testClientToServerNonBMP() throws InvalidCharacterException {
+ test.testClientToServerNonBMP();
+ }
+
+ public void testServerToClientBMP() {
+ test.testServerToClientBMP();
+ }
+
+ public void testServerToClientNonBMP() {
+ test.testServerToClientNonBMP();
+ }
+
+}
diff --git a/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java b/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java
index 3e160e5..ce68390 100644
--- a/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java
+++ b/user/test/com/google/gwt/requestfactory/rebind/model/RequestFactoryModelTest.java
@@ -28,12 +28,14 @@
import com.google.gwt.requestfactory.server.TestContextImpl;
import com.google.gwt.requestfactory.shared.EntityProxy;
import com.google.gwt.requestfactory.shared.InstanceRequest;
+import com.google.gwt.requestfactory.shared.Locator;
import com.google.gwt.requestfactory.shared.ProxyFor;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.requestfactory.shared.Request;
import com.google.gwt.requestfactory.shared.RequestContext;
import com.google.gwt.requestfactory.shared.RequestFactory;
import com.google.gwt.requestfactory.shared.Service;
+import com.google.gwt.requestfactory.shared.ServiceLocator;
import com.google.gwt.requestfactory.shared.ValueProxy;
import junit.framework.TestCase;
@@ -269,8 +271,10 @@
new EmptyMockJavaResource(Iterable.class),
new EmptyMockJavaResource(EntityProxy.class),
new EmptyMockJavaResource(InstanceRequest.class),
+ new EmptyMockJavaResource(Locator.class),
new EmptyMockJavaResource(RequestFactory.class),
new EmptyMockJavaResource(Receiver.class),
+ new EmptyMockJavaResource(ServiceLocator.class),
new EmptyMockJavaResource(ValueProxy.class),
new RealJavaResource(Request.class),
diff --git a/user/test/com/google/gwt/requestfactory/server/InstanceService.java b/user/test/com/google/gwt/requestfactory/server/InstanceService.java
new file mode 100644
index 0000000..9d9c940
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/server/InstanceService.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010 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.requestfactory.server;
+
+/**
+ * A service API that doesn't have static methods and that can't be
+ * default-instantiated.
+ */
+public interface InstanceService {
+ Integer add(int value);
+}
diff --git a/user/test/com/google/gwt/requestfactory/server/InstanceServiceImpl.java b/user/test/com/google/gwt/requestfactory/server/InstanceServiceImpl.java
new file mode 100644
index 0000000..e2dd226
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/server/InstanceServiceImpl.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010 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.requestfactory.server;
+
+/**
+ * A service API that doesn't have static methods and that can't be
+ * default-instantiated.
+ */
+public class InstanceServiceImpl implements InstanceService {
+ private final int base;
+
+ public InstanceServiceImpl(int base) {
+ this.base = base;
+ }
+
+ public Integer add(int value) {
+ return base + value;
+ }
+}
diff --git a/user/test/com/google/gwt/requestfactory/server/InstanceServiceLocator.java b/user/test/com/google/gwt/requestfactory/server/InstanceServiceLocator.java
new file mode 100644
index 0000000..e5a5b9e
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/server/InstanceServiceLocator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2010 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.requestfactory.server;
+
+import com.google.gwt.requestfactory.shared.ServiceLocator;
+
+/**
+ * Demonstrates instance-based service objects.
+ */
+public class InstanceServiceLocator implements ServiceLocator {
+
+ public Object getInstance(Class<?> clazz) {
+ assert InstanceService.class.equals(clazz);
+ return clazz.cast(new InstanceServiceImpl(5));
+ }
+}
diff --git a/user/test/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidatorTest.java b/user/test/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidatorTest.java
index eb87261..1c6c003 100644
--- a/user/test/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidatorTest.java
+++ b/user/test/com/google/gwt/requestfactory/server/RequestFactoryInterfaceValidatorTest.java
@@ -19,12 +19,13 @@
import com.google.gwt.requestfactory.shared.EntityProxy;
import com.google.gwt.requestfactory.shared.InstanceRequest;
import com.google.gwt.requestfactory.shared.Locator;
-import com.google.gwt.requestfactory.shared.LocatorFor;
import com.google.gwt.requestfactory.shared.ProxyFor;
+import com.google.gwt.requestfactory.shared.ProxyForName;
import com.google.gwt.requestfactory.shared.Request;
import com.google.gwt.requestfactory.shared.RequestContext;
import com.google.gwt.requestfactory.shared.RequestFactory;
import com.google.gwt.requestfactory.shared.Service;
+import com.google.gwt.requestfactory.shared.ServiceName;
import com.google.gwt.requestfactory.shared.SimpleRequestFactory;
import com.google.gwt.requestfactory.shared.ValueProxy;
import com.google.gwt.requestfactory.shared.impl.FindRequest;
@@ -86,6 +87,10 @@
int foo(int a) {
return 0;
}
+
+ java.sql.Date getSqlDate() {
+ return null;
+ }
}
@ProxyFor(Domain.class)
@@ -110,11 +115,17 @@
return 0;
}
}
+
@ProxyFor(DomainWithOverloads.class)
interface DomainWithOverloadsProxy extends EntityProxy {
void foo();
}
+ @ProxyFor(Domain.class)
+ interface DomainWithSqlDateProxy extends EntityProxy {
+ java.sql.Date getSqlDate();
+ }
+
class Foo {
}
@@ -180,8 +191,7 @@
}
}
- @ProxyFor(LocatorEntity.class)
- @LocatorFor(LocatorEntityLocator.class)
+ @ProxyFor(value = LocatorEntity.class, locator = LocatorEntityLocator.class)
interface LocatorEntityProxy extends EntityProxy {
}
@@ -228,6 +238,13 @@
Request<Integer> doesNotExist(int a);
}
+ @ProxyFor(Domain.class)
+ @ProxyForName("Domain")
+ @Service(Domain.class)
+ @ServiceName("Domain")
+ interface TooManyAnnotations extends RequestContext {
+ }
+
static class UnexpectedIdAndVersionDomain {
Random getId() {
return null;
@@ -263,6 +280,14 @@
};
/**
+ * Test that subclasses of {@code java.util.Date} are not transportable.
+ */
+ public void testDateSubclass() {
+ v.validateEntityProxy(DomainWithSqlDateProxy.class.getName());
+ assertTrue(v.isPoisoned());
+ }
+
+ /**
* Test the {@link FindRequest} context used to implement find().
*/
public void testFindRequestContext() {
@@ -349,6 +374,11 @@
assertFalse(v.isPoisoned());
}
+ public void testTooManyAnnotations() {
+ v.validateRequestContext(TooManyAnnotations.class.getName());
+ assertTrue(v.isPoisoned());
+ }
+
public void testUnexpectedIdAndVersion() {
v.validateEntityProxy(UnexpectedIdAndVersionProxy.class.getName());
assertTrue(v.isPoisoned());
diff --git a/user/test/com/google/gwt/requestfactory/server/RequestFactoryUnicodeEscapingJreTest.java b/user/test/com/google/gwt/requestfactory/server/RequestFactoryUnicodeEscapingJreTest.java
new file mode 100644
index 0000000..06a4d50
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/server/RequestFactoryUnicodeEscapingJreTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010 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.requestfactory.server;
+
+import com.google.gwt.requestfactory.client.RequestFactoryUnicodeEscapingTest;
+import com.google.gwt.requestfactory.shared.SimpleRequestFactory;
+
+/**
+ * A JRE implementation of {@link RequestFactoryUnicodeEscapingTest}.
+ */
+public class RequestFactoryUnicodeEscapingJreTest extends
+ RequestFactoryUnicodeEscapingTest {
+ @Override
+ public String getModuleName() {
+ return null;
+ }
+
+ @Override
+ protected SimpleRequestFactory createFactory() {
+ return RequestFactoryJreTest.createInProcess(SimpleRequestFactory.class);
+ }
+}
diff --git a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
index 4a1bfb7..1ac5987 100644
--- a/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
+++ b/user/test/com/google/gwt/requestfactory/server/SimpleFoo.java
@@ -19,11 +19,14 @@
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.sql.Time;
+import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -157,12 +160,72 @@
return foo;
}
+ /**
+ * Check client-side upcasting to BigDecimal and return a list of BigDecimals
+ * that should be upcast.
+ */
+ public static List<BigDecimal> processBigDecimalList(List<BigDecimal> values) {
+ List<BigDecimal> toReturn = new ArrayList<BigDecimal>();
+ toReturn.add(BigDecimal.TEN);
+ toReturn.add(new BigDecimal("12345.6789") {
+ // This is an anonymous subtype
+ });
+ if (!toReturn.equals(values)) {
+ throw new IllegalArgumentException(toReturn + " != " + values);
+ }
+ return toReturn;
+ }
+
+ /**
+ * Check client-side upcasting to BigInteger and return a list of BigIntegers
+ * that should be upcast.
+ */
+ public static List<BigInteger> processBigIntegerList(List<BigInteger> values) {
+ List<BigInteger> toReturn = new ArrayList<BigInteger>();
+ toReturn.add(BigInteger.TEN);
+ toReturn.add(new BigInteger("12345") {
+ // This is an anonymous subtype
+ });
+ if (!toReturn.equals(values)) {
+ throw new IllegalArgumentException(toReturn + " != " + values);
+ }
+ return toReturn;
+ }
+
public static Boolean processBooleanList(List<Boolean> values) {
return values.get(0);
}
- public static Date processDateList(List<Date> values) {
- return values.get(0);
+ /**
+ * Check client-side upcasting to Date and return a list of Dates that should
+ * be upcast.
+ */
+ @SuppressWarnings("deprecation")
+ public static List<Date> processDateList(List<Date> values) {
+ // Keep these values in sync with SimpleFoo.processDateList
+ Date date = new Date(90, 0, 1);
+ java.sql.Date sqlDate = new java.sql.Date(90, 0, 2);
+ Time sqlTime = new Time(1, 2, 3);
+ Timestamp sqlTimestamp = new Timestamp(12345L);
+ List<Date> toReturn = Arrays.asList(date, sqlDate, sqlTime, sqlTimestamp);
+
+ if (toReturn.size() != values.size()) {
+ throw new IllegalArgumentException("size");
+ }
+
+ Iterator<Date> expected = toReturn.iterator();
+ Iterator<Date> actual = values.iterator();
+ while (expected.hasNext()) {
+ Date expectedDate = expected.next();
+ long expectedTime = expectedDate.getTime();
+ long actualTime = actual.next().getTime();
+ if (expectedTime != actualTime) {
+ throw new IllegalArgumentException(expectedDate.getClass().getName()
+ + " " + expectedTime + " != " + actualTime);
+ }
+ }
+
+ return toReturn;
}
public static SimpleEnum processEnumList(List<SimpleEnum> values) {
@@ -278,7 +341,7 @@
public static String returnNullString() {
return null;
}
-
+
public static SimpleFoo returnSimpleFooSubclass() {
return new SimpleFoo() {
};
diff --git a/user/test/com/google/gwt/requestfactory/shared/BaseFooProxy.java b/user/test/com/google/gwt/requestfactory/shared/BaseFooProxy.java
index a628bf3..2e98883 100644
--- a/user/test/com/google/gwt/requestfactory/shared/BaseFooProxy.java
+++ b/user/test/com/google/gwt/requestfactory/shared/BaseFooProxy.java
@@ -97,6 +97,8 @@
void setDoubleField(Double d);
+ void setEnumField(SimpleEnum value);
+
void setFloatField(Float f);
void setIntId(Integer intId);
diff --git a/user/test/com/google/gwt/requestfactory/shared/InstanceServiceRequest.java b/user/test/com/google/gwt/requestfactory/shared/InstanceServiceRequest.java
new file mode 100644
index 0000000..79fef75
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/shared/InstanceServiceRequest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010 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.requestfactory.shared;
+
+import com.google.gwt.requestfactory.server.InstanceService;
+import com.google.gwt.requestfactory.server.InstanceServiceLocator;
+
+/**
+ * Used to test the ServiceLocator extension hook.
+ */
+@Service(value = InstanceService.class, locator = InstanceServiceLocator.class)
+public interface InstanceServiceRequest extends RequestContext {
+ Request<Integer> add(int value);
+}
diff --git a/user/test/com/google/gwt/requestfactory/shared/LocatorTest.java b/user/test/com/google/gwt/requestfactory/shared/LocatorTest.java
index fc550e8..095f65b 100644
--- a/user/test/com/google/gwt/requestfactory/shared/LocatorTest.java
+++ b/user/test/com/google/gwt/requestfactory/shared/LocatorTest.java
@@ -82,14 +82,13 @@
static final Domain INSTANCE = new Domain();
}
- @ProxyFor(Domain.class)
- @LocatorFor(DomainLocator.class)
+ @ProxyFor(value = Domain.class, locator = DomainLocator.class)
interface DomainProxy extends EntityProxy {
EntityProxyId<DomainProxy> stableId();
};
private static final String ID = "DomainId";
- private static final int TEST_DELAY = 500;
+ private static final int TEST_DELAY = 5000;
private Factory factory;
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
index cd174be..bbb4c6b 100644
--- a/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
+++ b/user/test/com/google/gwt/requestfactory/shared/SimpleFooRequest.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.requestfactory.shared;
+import java.math.BigDecimal;
+import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.Set;
@@ -61,9 +63,13 @@
InstanceRequest<SimpleFooProxy, SimpleFooProxy> persistCascadingAndReturnSelf();
+ Request<List<BigInteger>> processBigIntegerList(List<BigInteger> values);
+
+ Request<List<BigDecimal>> processBigDecimalList(List<BigDecimal> values);
+
Request<Boolean> processBooleanList(List<Boolean> values);
- Request<Date> processDateList(List<Date> values);
+ Request<List<Date>> processDateList(List<Date> values);
Request<SimpleEnum> processEnumList(List<SimpleEnum> values);
diff --git a/user/test/com/google/gwt/requestfactory/shared/SimpleRequestFactory.java b/user/test/com/google/gwt/requestfactory/shared/SimpleRequestFactory.java
index 082f3a1..7def869 100644
--- a/user/test/com/google/gwt/requestfactory/shared/SimpleRequestFactory.java
+++ b/user/test/com/google/gwt/requestfactory/shared/SimpleRequestFactory.java
@@ -20,8 +20,12 @@
* UserInformation and Logging services.
*/
public interface SimpleRequestFactory extends BasicRequestFactory {
+
+ InstanceServiceRequest instanceServiceRequest();
SimpleBarRequest simpleBarRequest();
SimpleFooRequest simpleFooRequest();
+
+ UnicodeTestRequest unicodeTestRequest();
}
diff --git a/user/test/com/google/gwt/requestfactory/shared/UnicodeTestRequest.java b/user/test/com/google/gwt/requestfactory/shared/UnicodeTestRequest.java
new file mode 100644
index 0000000..fe9e38e
--- /dev/null
+++ b/user/test/com/google/gwt/requestfactory/shared/UnicodeTestRequest.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2010 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.requestfactory.shared;
+
+import com.google.gwt.user.client.rpc.UnicodeEscapingTest;
+
+/**
+ * Provides access to the static test methods in {@link UnicodeEscapingTes}.
+ */
+@Service(UnicodeEscapingTest.class)
+public interface UnicodeTestRequest extends RequestContext {
+ Request<String> getStringContainingCharacterRange(int start, int end);
+
+ Request<Void> verifyStringContainingCharacterRange(int start, int end,
+ String str);
+}
diff --git a/user/test/com/google/gwt/text/TextSuite.java b/user/test/com/google/gwt/text/TextSuite.java
index cfe30d3..d14d55f 100644
--- a/user/test/com/google/gwt/text/TextSuite.java
+++ b/user/test/com/google/gwt/text/TextSuite.java
@@ -20,6 +20,7 @@
import com.google.gwt.text.client.DoubleParserTest;
import com.google.gwt.text.client.IntegerParserTest;
import com.google.gwt.text.client.LongParserTest;
+import com.google.gwt.text.client.NumberFormatRendererTest;
import junit.framework.Test;
@@ -34,6 +35,7 @@
suite.addTestSuite(DoubleParserTest.class);
suite.addTestSuite(IntegerParserTest.class);
suite.addTestSuite(LongParserTest.class);
+ suite.addTestSuite(NumberFormatRendererTest.class);
return suite;
}
}
diff --git a/user/test/com/google/gwt/text/client/DoubleParserTest.java b/user/test/com/google/gwt/text/client/DoubleParserTest.java
index d14414d..a2f8391 100644
--- a/user/test/com/google/gwt/text/client/DoubleParserTest.java
+++ b/user/test/com/google/gwt/text/client/DoubleParserTest.java
@@ -30,7 +30,7 @@
}
public void testOuroborus() throws ParseException {
- assertEquals("123", DoubleRenderer.instance().render(DoubleParser.instance().parse("123")));
+ assertEquals("123.5", DoubleRenderer.instance().render(DoubleParser.instance().parse("123.5")));
}
public void testNull() throws ParseException {
diff --git a/user/test/com/google/gwt/text/client/NumberFormatRendererTest.java b/user/test/com/google/gwt/text/client/NumberFormatRendererTest.java
new file mode 100644
index 0000000..f57c016
--- /dev/null
+++ b/user/test/com/google/gwt/text/client/NumberFormatRendererTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2010 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.text.client;
+
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Eponymous unit test.
+ */
+public class NumberFormatRendererTest extends GWTTestCase {
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.text.TextSuite";
+ }
+
+ public void testDefault() {
+ assertEquals(NumberFormat.getDecimalFormat().format(Math.PI),
+ new NumberFormatRenderer().render(Math.PI));
+ }
+
+ public void testScientific() {
+ assertEquals(
+ NumberFormat.getScientificFormat().format(Math.PI),
+ new NumberFormatRenderer(NumberFormat.getScientificFormat()).render(Math.PI));
+ }
+
+ public void testNull() {
+ assertEquals("", new NumberFormatRenderer().render(null));
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java b/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java
index bdceca6..5436f36 100644
--- a/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java
+++ b/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java
@@ -26,6 +26,7 @@
import com.google.gwt.uibinder.attributeparsers.TextAlignConstantParserTest;
import com.google.gwt.uibinder.attributeparsers.VerticalAlignmentConstantParserTest;
import com.google.gwt.uibinder.elementparsers.AbsolutePanelParserTest;
+import com.google.gwt.uibinder.elementparsers.DateLabelParserTest;
import com.google.gwt.uibinder.elementparsers.DialogBoxParserTest;
import com.google.gwt.uibinder.elementparsers.DisclosurePanelParserTest;
import com.google.gwt.uibinder.elementparsers.DockLayoutPanelParserTest;
@@ -36,6 +37,7 @@
import com.google.gwt.uibinder.elementparsers.ListBoxParserTest;
import com.google.gwt.uibinder.elementparsers.MenuBarParserTest;
import com.google.gwt.uibinder.elementparsers.MenuItemParserTest;
+import com.google.gwt.uibinder.elementparsers.NumberLabelParserTest;
import com.google.gwt.uibinder.elementparsers.StackLayoutPanelParserTest;
import com.google.gwt.uibinder.elementparsers.StackPanelParserTest;
import com.google.gwt.uibinder.elementparsers.TabLayoutPanelParserTest;
@@ -88,6 +90,7 @@
// elementparsers
suite.addTestSuite(AbsolutePanelParserTest.class);
+ suite.addTestSuite(DateLabelParserTest.class);
suite.addTestSuite(DialogBoxParserTest.class);
suite.addTestSuite(DisclosurePanelParserTest.class);
suite.addTestSuite(DockLayoutPanelParserTest.class);
@@ -98,6 +101,7 @@
suite.addTestSuite(ListBoxParserTest.class);
suite.addTestSuite(MenuBarParserTest.class);
suite.addTestSuite(MenuItemParserTest.class);
+ suite.addTestSuite(NumberLabelParserTest.class);
suite.addTestSuite(StackLayoutPanelParserTest.class);
suite.addTestSuite(StackPanelParserTest.class);
suite.addTestSuite(TabLayoutPanelParserTest.class);
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/DateLabelParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/DateLabelParserTest.java
new file mode 100644
index 0000000..131f614
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/elementparsers/DateLabelParserTest.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2010 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.uibinder.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.impl.MockJavaResource;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.TimeZone;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
+import com.google.gwt.uibinder.rebind.FieldWriter;
+import com.google.gwt.user.client.ui.DateLabel;
+
+import junit.framework.TestCase;
+
+import org.xml.sax.SAXException;
+
+/**
+ * Eponymous unit test.
+ */
+public class DateLabelParserTest extends TestCase {
+ private static final String PARSED_TYPE = "com.google.gwt.user.client.ui.DateLabel";
+
+ private static final MockJavaResource DATELABEL_SUBCLASS_NO_CONSTRUCTOR = new MockJavaResource(
+ "my.MyDateLabel") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package my;\n");
+ code.append("import com.google.gwt.user.client.ui.DateLabel;\n");
+ code.append("public class MyDateLabel extends DateLabel {\n");
+ code.append("}\n");
+ return code;
+ }
+ };
+ private static final MockJavaResource DATELABEL_SUBCLASS_FORMAT_CONSTRUCTOR = new MockJavaResource(
+ "my.MyConstructedDateLabel") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package my;\n");
+ code.append("import com.google.gwt.user.client.ui.DateLabel;\n");
+ code.append("import com.google.gwt.i18n.client.DateTimeFormat;\n");
+ code.append("public class MyConstructedDateLabel extends DateLabel {\n");
+ code.append(" public MyConstructedDateLabel(DateTimeFormat f) { super(f); }");
+ code.append("}\n");
+ return code;
+ }
+ };
+ private static final MockJavaResource DATELABEL_SUBCLASS_FORMAT_AND_TZ_CONSTRUCTOR = new MockJavaResource(
+ "my.MyConstructedDateLabel2") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package my;\n");
+ code.append("import com.google.gwt.user.client.ui.DateLabel;\n");
+ code.append("import com.google.gwt.i18n.client.DateTimeFormat;\n");
+ code.append("import com.google.gwt.i18n.client.TimeZone;\n");
+ code.append("public class MyConstructedDateLabel2 extends DateLabel {\n");
+ code.append(" public MyConstructedDateLabel2(DateTimeFormat f, TimeZone tz) { super(f, tz); }");
+ code.append("}\n");
+ return code;
+ }
+ };
+ private static final MockJavaResource DATELABEL_SUBCLASS_TZ_CONSTRUCTOR = new MockJavaResource(
+ "my.MyConstructedDateLabel3") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package my;\n");
+ code.append("import com.google.gwt.user.client.ui.DateLabel;\n");
+ code.append("import com.google.gwt.i18n.client.TimeZone;\n");
+ code.append("public class MyConstructedDateLabel3 extends DateLabel {\n");
+ code.append(" public MyConstructedDateLabel3(TimeZone tz) { super(); }");
+ code.append("}\n");
+ return code;
+ }
+ };
+ private ElementParserTester tester;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ tester = new ElementParserTester(PARSED_TYPE, new DateLabelParser());
+ }
+
+ public void testHappyWithDefaultInstantiableSubclass()
+ throws UnableToCompleteException, SAXException {
+ tester = new ElementParserTester("my.MyDateLabel", new DateLabelParser(),
+ DATELABEL_SUBCLASS_NO_CONSTRUCTOR);
+ DateLabelParser parser = new DateLabelParser();
+ StringBuffer b = new StringBuffer();
+
+ b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+ b.append(" xmlns:my='urn:import:my'");
+ b.append(" xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+ b.append(" <my:MyDateLabel format='{someDateTimeFormat}' timezone='{someTimeZone}' /> ");
+ b.append("</ui:UiBinder>");
+
+ parser.parse(tester.getElem(b.toString(), "my:MyDateLabel"), "fieldName",
+ tester.parsedType, tester.writer);
+ FieldWriter w = tester.fieldManager.lookup("fieldName");
+ assertNull(w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testHappyWithSubclassWithDateTimeFormatConstructor()
+ throws UnableToCompleteException, SAXException {
+ DateLabelParser parser = new DateLabelParser();
+ tester = new ElementParserTester("my.MyConstructedDateLabel",
+ new DateLabelParser(), DATELABEL_SUBCLASS_FORMAT_CONSTRUCTOR);
+
+ StringBuffer b = new StringBuffer();
+
+ b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+ b.append(" xmlns:my='urn:import:my'");
+ b.append(" xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+ b.append(" <my:MyConstructedDateLabel format='{someDateTimeFormat}' timezone='{someTimeZone}' /> ");
+ b.append("</ui:UiBinder>");
+
+ parser.parse(tester.getElem(b.toString(), "my:MyConstructedDateLabel"),
+ "fieldName", tester.parsedType, tester.writer);
+ FieldWriter w = tester.fieldManager.lookup("fieldName");
+ assertEquals("new my.MyConstructedDateLabel(someDateTimeFormat)",
+ w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testHappyWithSubclassWithDateTimeFormatAndTimeZoneConstructor()
+ throws UnableToCompleteException, SAXException {
+ DateLabelParser parser = new DateLabelParser();
+ tester = new ElementParserTester("my.MyConstructedDateLabel2",
+ new DateLabelParser(), DATELABEL_SUBCLASS_FORMAT_AND_TZ_CONSTRUCTOR);
+
+ StringBuffer b = new StringBuffer();
+
+ b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+ b.append(" xmlns:my='urn:import:my'");
+ b.append(" xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+ b.append(" <my:MyConstructedDateLabel2 format='{someDateTimeFormat}' timezone='{someTimeZone}' /> ");
+ b.append("</ui:UiBinder>");
+
+ parser.parse(tester.getElem(b.toString(), "my:MyConstructedDateLabel2"),
+ "fieldName", tester.parsedType, tester.writer);
+ FieldWriter w = tester.fieldManager.lookup("fieldName");
+ assertEquals(
+ "new my.MyConstructedDateLabel2(someDateTimeFormat, someTimeZone)",
+ w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testHappyWithSubclassWithTimeZoneFormatConstructor()
+ throws UnableToCompleteException, SAXException {
+ DateLabelParser parser = new DateLabelParser();
+ tester = new ElementParserTester("my.MyConstructedDateLabel3",
+ new DateLabelParser(), DATELABEL_SUBCLASS_TZ_CONSTRUCTOR);
+
+ StringBuffer b = new StringBuffer();
+
+ b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+ b.append(" xmlns:my='urn:import:my'");
+ b.append(" xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+ b.append(" <my:MyConstructedDateLabel3 format='{someDateTimeFormat}' timezone='{someTimeZone}' /> ");
+ b.append("</ui:UiBinder>");
+
+ parser.parse(tester.getElem(b.toString(), "my:MyConstructedDateLabel3"),
+ "fieldName", tester.parsedType, tester.writer);
+ FieldWriter w = tester.fieldManager.lookup("fieldName");
+ assertNull(w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testHappyWithNoFormat() throws UnableToCompleteException,
+ SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:DateLabel>");
+ b.append("</g:DateLabel>");
+
+ FieldWriter w = tester.parse(b.toString());
+ assertNull(w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testHappyWithPredefinedFormat() throws UnableToCompleteException,
+ SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:DateLabel predefinedFormat='DATE_MEDIUM'>");
+ b.append("</g:DateLabel>");
+
+ FieldWriter w = tester.parse(b.toString());
+ assertEquals("new " + DateLabel.class.getCanonicalName() + "("
+ + DateTimeFormat.class.getCanonicalName() + ".getFormat("
+ + PredefinedFormat.class.getCanonicalName() + ".DATE_MEDIUM))",
+ w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testHappyWithTimezoneOffset() throws UnableToCompleteException,
+ SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:DateLabel customFormat='zzzz' timezoneOffset='-7200'>");
+ b.append("</g:DateLabel>");
+
+ FieldWriter w = tester.parse(b.toString());
+ assertEquals("new " + DateLabel.class.getCanonicalName() + "("
+ + DateTimeFormat.class.getCanonicalName() + ".getFormat(\"zzzz\"), "
+ + TimeZone.class.getCanonicalName() + ".createTimeZone(-7200))",
+ w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testChokeOnNonDateTimeFormat() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:DateLabel format='someString' >");
+ b.append("</g:DateLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue("Expect to hear about DateTimeFormat",
+ tester.logger.died.contains("DateTimeFormat"));
+ }
+ }
+
+ public void testChokeOnNonTimeZone() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:DateLabel format='{someDateTimeFormat}' timezone='someString' >");
+ b.append("</g:DateLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue("Expect to hear about TimeZone",
+ tester.logger.died.contains("TimeZone"));
+ }
+ }
+
+ public void testChokeOnUnknownPredefinedFormat() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:DateLabel predefinedFormat='someString' >");
+ b.append("</g:DateLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue("Expect to hear about PredefinedFormat",
+ tester.logger.died.contains("PredefinedFormat"));
+ }
+ }
+
+ public void testChokeOnMultipleFormats() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:DateLabel predefinedFormat='DATE_FULL' customFormat='MM/dd'>");
+ b.append("</g:DateLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue(
+ tester.logger.died,
+ tester.logger.died.contains(DateLabelParser.AT_MOST_ONE_SPECIFIED_FORMAT));
+ }
+ }
+
+ public void testChokeOnMultipleTimeZones() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:DateLabel format='{someDateTimeFormat}' timezone='{someTimeZone}' timezoneOffset='-7200'>");
+ b.append("</g:DateLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue(
+ tester.logger.died,
+ tester.logger.died.contains(DateLabelParser.AT_MOST_ONE_SPECIFIED_TIME_ZONE));
+ }
+ }
+
+ public void testChokeOnTimeZoneWithoutSpecifiedFormat() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:DateLabel timezoneOffset='-7200'>");
+ b.append("</g:DateLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue(
+ tester.logger.died,
+ tester.logger.died.contains(DateLabelParser.NO_TIMEZONE_WITHOUT_SPECIFIED_FORMAT));
+ }
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/NumberLabelParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/NumberLabelParserTest.java
new file mode 100644
index 0000000..41fff15
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/elementparsers/NumberLabelParserTest.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2010 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.uibinder.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.impl.MockJavaResource;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.uibinder.rebind.FieldWriter;
+import com.google.gwt.user.client.ui.NumberLabel;
+
+import junit.framework.TestCase;
+
+import org.xml.sax.SAXException;
+
+/**
+ * Eponymous unit test.
+ */
+public class NumberLabelParserTest extends TestCase {
+ private static final String PARSED_TYPE = "com.google.gwt.user.client.ui.NumberLabel";
+
+ private static final MockJavaResource NUMBERLABEL_SUBCLASS_NO_CONSTRUCTOR = new MockJavaResource(
+ "my.MyNumberLabel") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package my;\n");
+ code.append("import com.google.gwt.user.client.ui.NumberLabel;\n");
+ code.append("public class MyNumberLabel extends NumberLabel {\n");
+ code.append("}\n");
+ return code;
+ }
+ };
+ private static final MockJavaResource NUMBERLABEL_SUBCLASS_FORMAT_CONSTRUCTOR = new MockJavaResource(
+ "my.MyConstructedNumberLabel") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package my;\n");
+ code.append("import com.google.gwt.user.client.ui.NumberLabel;\n");
+ code.append("import com.google.gwt.i18n.client.NumberFormat;\n");
+ code.append("public class MyConstructedNumberLabel extends NumberLabel {\n");
+ code.append(" public MyConstructedNumberLabel(NumberFormat f) { super(f); }");
+ code.append("}\n");
+ return code;
+ }
+ };
+ private ElementParserTester tester;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ tester = new ElementParserTester(PARSED_TYPE, new NumberLabelParser());
+ }
+
+ public void testHappyWithDefaultInstantiableSubclass()
+ throws UnableToCompleteException, SAXException {
+ tester = new ElementParserTester("my.MyNumberLabel",
+ new NumberLabelParser(), NUMBERLABEL_SUBCLASS_NO_CONSTRUCTOR);
+ NumberLabelParser parser = new NumberLabelParser();
+ StringBuffer b = new StringBuffer();
+
+ b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+ b.append(" xmlns:my='urn:import:my'");
+ b.append(" xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+ b.append(" <my:MyNumberLabel format='{someDateTimeFormat}' currencyData='{someCurrencyData}' /> ");
+ b.append("</ui:UiBinder>");
+
+ parser.parse(tester.getElem(b.toString(), "my:MyNumberLabel"), "fieldName",
+ tester.parsedType, tester.writer);
+ FieldWriter w = tester.fieldManager.lookup("fieldName");
+ assertNull(w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testHappyWithSubclassWithNumberFormatConstructor()
+ throws UnableToCompleteException, SAXException {
+ NumberLabelParser parser = new NumberLabelParser();
+ tester = new ElementParserTester("my.MyConstructedNumberLabel",
+ new NumberLabelParser(), NUMBERLABEL_SUBCLASS_FORMAT_CONSTRUCTOR);
+
+ StringBuffer b = new StringBuffer();
+
+ b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+ b.append(" xmlns:my='urn:import:my'");
+ b.append(" xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+ b.append(" <my:MyConstructedNumberLabel format='{someDateTimeFormat}' /> ");
+ b.append("</ui:UiBinder>");
+
+ parser.parse(tester.getElem(b.toString(), "my:MyConstructedNumberLabel"),
+ "fieldName", tester.parsedType, tester.writer);
+ FieldWriter w = tester.fieldManager.lookup("fieldName");
+ assertEquals("new my.MyConstructedNumberLabel(someDateTimeFormat)",
+ w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testHappyWithNoFormat() throws UnableToCompleteException,
+ SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:NumberLabel>");
+ b.append("</g:NumberLabel>");
+
+ FieldWriter w = tester.parse(b.toString());
+ assertNull(w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testHappyWithCustomFormatAndCurrency()
+ throws UnableToCompleteException, SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:NumberLabel customFormat='#\u00A0\u00A4' currencyCode='EUR'>");
+ b.append("</g:NumberLabel>");
+
+ FieldWriter w = tester.parse(b.toString());
+ assertEquals("new " + NumberLabel.class.getCanonicalName() + "("
+ + NumberFormat.class.getCanonicalName() + ".getFormat(\"#\u00A0\u00A4\", \"EUR\"))",
+ w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testHappyWithCurrencyPredefinedFormat()
+ throws UnableToCompleteException, SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:NumberLabel predefinedFormat='CURRENCY'>");
+ b.append("</g:NumberLabel>");
+
+ FieldWriter w = tester.parse(b.toString());
+ assertEquals("new " + NumberLabel.class.getCanonicalName() + "("
+ + NumberFormat.class.getCanonicalName() + ".getCurrencyFormat())",
+ w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testHappyWithCurrencyPredefinedFormatAndCurrencCode()
+ throws UnableToCompleteException, SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:NumberLabel predefinedFormat='CURRENCY' currencyCode='EUR'>");
+ b.append("</g:NumberLabel>");
+
+ FieldWriter w = tester.parse(b.toString());
+ assertEquals("new " + NumberLabel.class.getCanonicalName() + "("
+ + NumberFormat.class.getCanonicalName() + ".getCurrencyFormat(\"EUR\"))",
+ w.getInitializer());
+
+ assertTrue(tester.writer.statements.isEmpty());
+ assertNull(tester.logger.died);
+ }
+
+ public void testChokeOnNonDateTimeFormat() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:NumberLabel format='someString' >");
+ b.append("</g:NumberLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue("Expect to hear about DateTimeFormat",
+ tester.logger.died.contains("DateTimeFormat"));
+ }
+ }
+
+ public void testChokeOnNonCurrencyData() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:NumberLabel predefinedFormat='CURRENCY' currencyData='someString' >");
+ b.append("</g:NumberLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue("Expect to hear about CurrencyData",
+ tester.logger.died.contains("CurrencyData"));
+ }
+ }
+
+ public void testChokeOnUnknownPredefinedFormat() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:NumberLabel predefinedFormat='someString' >");
+ b.append("</g:NumberLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue(tester.logger.died, tester.logger.died.contains(String.format(
+ NumberLabelParser.UNKNOWN_PREDEFINED_FORMAT, "someString")));
+ }
+ }
+
+ public void testChokeOnMultipleFormats() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:NumberLabel predefinedFormat='SCIENTIFIC' customFormat='#'>");
+ b.append("</g:NumberLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue(
+ tester.logger.died,
+ tester.logger.died.contains(NumberLabelParser.AT_MOST_ONE_SPECIFIED_FORMAT));
+ }
+ }
+
+ public void testChokeOnMultipleCurrencies() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:NumberLabel predefinedFormat='CURRENCY' currencyData='{someCurrencyData}' currencyCode='EUR'>");
+ b.append("</g:NumberLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue(
+ tester.logger.died,
+ tester.logger.died.contains(NumberLabelParser.AT_MOST_ONE_SPECIFIED_CURRENCY));
+ }
+ }
+
+ public void testChokeOnCurrencyWithoutSpecifiedFormat() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:NumberLabel currencyCode='EUR'>");
+ b.append("</g:NumberLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue(
+ tester.logger.died,
+ tester.logger.died.contains(NumberLabelParser.NO_CURRENCY_WITHOUT_SPECIFIED_FORMAT));
+ }
+ }
+
+ public void testChokeOnCurrencyWithPredefinedFormat() throws SAXException {
+ StringBuffer b = new StringBuffer();
+ b.append("<g:NumberLabel predefinedFormat='PERCENT' currencyCode='EUR'>");
+ b.append("</g:NumberLabel>");
+
+ try {
+ tester.parse(b.toString());
+ fail();
+ } catch (UnableToCompleteException e) {
+ assertTrue(
+ tester.logger.died,
+ tester.logger.died.contains(NumberLabelParser.NO_CURRENCY_WITH_PREDEFINED_FORMAT));
+ }
+ }
+}
diff --git a/user/test/com/google/gwt/uibinder/test/UiJavaResources.java b/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
index 91852ee..ad1280a 100644
--- a/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
+++ b/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
@@ -1,12 +1,12 @@
/*
* Copyright 2009 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
@@ -19,6 +19,7 @@
import com.google.gwt.dev.javac.impl.MockJavaResource;
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.collect.HashSet;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import java.util.Arrays;
import java.util.Set;
@@ -95,6 +96,53 @@
return code;
}
};
+ public static final MockJavaResource CURRENCY_DATA = new MockJavaResource(
+ "com.google.gwt.i18n.client.CurrencyData") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.i18n.client;\n");
+ code.append("public class CurrencyData {\n");
+ code.append("}\n");
+ return code;
+ }
+ };
+ public static final MockJavaResource DATE_LABEL = new MockJavaResource(
+ "com.google.gwt.user.client.ui.DateLabel") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.user.client.ui;\n");
+ code.append("import com.google.gwt.i18n.client.DateTimeFormat;\n");
+ code.append("import com.google.gwt.i18n.client.TimeZone;\n");
+ code.append("public class DateLabel extends ValueLabel {\n");
+ code.append(" public DateLabel() { super(null); } ");
+ code.append(" public DateLabel(DateTimeFormat format) { super(null); } ");
+ code.append(" public DateLabel(DateTimeFormat format, TimeZone timeZone) { super(null); } ");
+ code.append("}\n");
+ return code;
+ }
+ };
+ public static final MockJavaResource DATE_TIME_FORMAT = new MockJavaResource(
+ "com.google.gwt.i18n.client.DateTimeFormat") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.i18n.client;\n");
+ code.append("public class DateTimeFormat {\n");
+ code.append(" public static enum PredefinedFormat {\n");
+ PredefinedFormat[] values = PredefinedFormat.values();
+ for (int i = 0; i < values.length; i++) {
+ code.append(" ").append(values[i].name());
+ if (i < values.length - 1) {
+ code.append(",\n");
+ }
+ }
+ code.append(" }\n");
+ code.append("}\n");
+ return code;
+ }
+ };
public static final MockJavaResource DIALOG_BOX = new MockJavaResource(
"com.google.gwt.user.client.ui.DialogBox") {
@Override
@@ -352,6 +400,42 @@
return code;
}
};
+ public static final MockJavaResource NUMBER_LABEL = new MockJavaResource(
+ "com.google.gwt.user.client.ui.NumberLabel") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.user.client.ui;\n");
+ code.append("import com.google.gwt.i18n.client.NumberFormat;\n");
+ code.append("public class NumberLabel extends ValueLabel {\n");
+ code.append(" public NumberLabel() { super(null); } ");
+ code.append(" public NumberLabel(NumberFormat format) { super(null); } ");
+ code.append("}\n");
+ return code;
+ }
+ };
+ public static final MockJavaResource NUMBER_FORMAT = new MockJavaResource(
+ "com.google.gwt.i18n.client.NumberFormat") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.i18n.client;\n");
+ code.append("public class NumberFormat {\n");
+ code.append("}\n");
+ return code;
+ }
+ };
+ public static final MockJavaResource RENDERER = new MockJavaResource(
+ "com.google.gwt.text.shared.Renderer") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.text.shared;\n");
+ code.append("public class Renderer<T> {\n");
+ code.append("}\n");
+ return code;
+ }
+ };
public static final MockJavaResource SPLIT_LAYOUT_PANEL = new MockJavaResource(
"com.google.gwt.user.client.ui.SplitLayoutPanel") {
@Override
@@ -432,6 +516,17 @@
return code;
}
};
+ public static final MockJavaResource TIME_ZONE = new MockJavaResource(
+ "com.google.gwt.i18n.client.TimeZone") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.i18n.client;\n");
+ code.append("public class TimeZone {\n");
+ code.append("}\n");
+ return code;
+ }
+ };
public static final MockJavaResource UI_BINDER = new MockJavaResource(
"com.google.gwt.uibinder.client.UiBinder") {
@Override
@@ -467,6 +562,19 @@
return code;
}
};
+ public static final MockJavaResource VALUE_LABEL = new MockJavaResource(
+ "com.google.gwt.user.client.ui.ValueLabel") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.user.client.ui;\n");
+ code.append("import com.google.gwt.text.shared.Renderer;\n");
+ code.append("public class ValueLabel extends Widget {\n");
+ code.append(" public ValueLabel(Renderer renderer) {} ");
+ code.append("}\n");
+ return code;
+ }
+ };
public static final MockJavaResource WIDGET = new MockJavaResource(
"com.google.gwt.user.client.ui.Widget") {
@Override
@@ -491,6 +599,9 @@
rtn.add(CLICK_EVENT);
rtn.add(CLICK_HANDLER);
rtn.add(COMMAND);
+ rtn.add(CURRENCY_DATA);
+ rtn.add(DATE_LABEL);
+ rtn.add(DATE_TIME_FORMAT);
rtn.add(DIALOG_BOX);
rtn.add(DISCLOSURE_PANEL);
rtn.add(DOCK_LAYOUT_PANEL);
@@ -512,6 +623,9 @@
rtn.add(MENU_ITEM_SEPARATOR);
rtn.add(MOUSE_OVER_EVENT);
rtn.add(MOUSE_OVER_HANDLER);
+ rtn.add(NUMBER_LABEL);
+ rtn.add(NUMBER_FORMAT);
+ rtn.add(RENDERER);
rtn.add(SPLIT_LAYOUT_PANEL);
rtn.add(STACK_LAYOUT_PANEL);
rtn.add(STACK_PANEL);
@@ -519,9 +633,11 @@
rtn.add(TAB_LAYOUT_PANEL);
rtn.add(TAB_PANEL);
rtn.add(TEXT_BOX_BASE);
+ rtn.add(TIME_ZONE);
rtn.add(UI_OBJECT);
rtn.add(UI_BINDER);
rtn.add(UI_FACTORY);
+ rtn.add(VALUE_LABEL);
rtn.add(WIDGET);
return rtn;
}
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
index 7201ea0..74426a9 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
+++ b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
@@ -28,14 +28,17 @@
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.DateLabel;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.NamedFrame;
+import com.google.gwt.user.client.ui.NumberLabel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.StackPanel;
+import com.google.gwt.user.client.ui.ValueLabel;
import com.google.gwt.user.client.ui.Widget;
/**
@@ -469,6 +472,21 @@
assertNotNull("NamedFrame exists", p);
}
+ public void testDateLabel() {
+ DateLabel p = widgetUi.myDateLabel;
+ assertNotNull("DateLabel exists", p);
+ }
+
+ public void testNumberLabel() {
+ NumberLabel<Float> p = widgetUi.myNumberLabel;
+ assertNotNull("NumberLabel exists", p);
+ }
+
+ public void testValueLabel() {
+ ValueLabel<Double> p = widgetUi.myValueLabel;
+ assertNotNull("ValueLabel exists", p);
+ }
+
public void testStringAttributeIgnoresStaticSetter() {
// Assumes setPopupText() is overloaded such that there is a static
// setPopupText(Foo, String) method.
diff --git a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
index 766ce98..9cd127e 100644
--- a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
+++ b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
@@ -27,12 +27,15 @@
import com.google.gwt.resources.client.DataResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.resources.client.CssResource.Shared;
+import com.google.gwt.text.client.DoubleRenderer;
+import com.google.gwt.text.shared.Renderer;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.DateLabel;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
@@ -45,11 +48,13 @@
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.NamedFrame;
+import com.google.gwt.user.client.ui.NumberLabel;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.StackPanel;
import com.google.gwt.user.client.ui.ToggleButton;
import com.google.gwt.user.client.ui.Tree;
+import com.google.gwt.user.client.ui.ValueLabel;
import com.google.gwt.user.client.ui.Widget;
/**
@@ -171,6 +176,11 @@
@UiField Widget myAbsolutePanelItemB;
@UiField Widget myAbsolutePanelItemC;
@UiField NamedFrame myNamedFrame;
+ @UiField DateLabel myDateLabel;
+ @UiField NumberLabel<Float> myNumberLabel;
+ @UiField(provided = true) @SuppressWarnings("unchecked")
+ Renderer doubleRenderer = DoubleRenderer.instance();
+ @UiField ValueLabel<Double> myValueLabel;
public WidgetBasedUi() {
external.style().ensureInjected();
diff --git a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
index b4d3710..08a6b83 100644
--- a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
+++ b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
@@ -72,6 +72,10 @@
for a resource to provide arbitrary objects to arbitrary attributes (look for FooLabel)
</ui:with>
+<ui:with field='doubleRenderer' type='com.google.gwt.text.shared.Renderer'>
+ Used to test ValueLabel's @UiConstructor
+</ui:with>
+
<ui:import field='com.google.gwt.uibinder.test.client.Constants.CONST_FOO'>
Tests the static import of a single constant into the local namespace.
</ui:import>
@@ -83,6 +87,7 @@
<ui:import field='com.google.gwt.uibinder.test.client.Constants.MyEnum.*'>
Tests the static import of an enum into the local namespace.
</ui:import>
+
<!--
Tests creating a CssResource from an external file.
-->
@@ -303,7 +308,8 @@
<ui:attribute name="text" description="radio button name"/>
</demo:PointlessRadioButtonSubclass>
- <gwt:HorizontalPanel ui:field="myHorizontalPanel" horizontalAlignment="ALIGN_LEFT" verticalAlignment="ALIGN_MIDDLE">
+ <gwt:HorizontalPanel ui:field="myHorizontalPanel"
+ horizontalAlignment="ALIGN_LEFT" verticalAlignment="ALIGN_MIDDLE">
<gwt:Cell><gwt:HTMLPanel>
<p> ... a StackPanel ... </p>
@@ -640,6 +646,12 @@
<gwt:NamedFrame ui:field='myNamedFrame' name='myName'/>
+ <gwt:DateLabel ui:field='myDateLabel' predefinedFormat='DATE_FULL' />
+
+ <gwt:NumberLabel ui:field='myNumberLabel' predefinedFormat='SCIENTIFIC' />
+
+ <gwt:ValueLabel ui:field='myValueLabel' renderer='{doubleRenderer}' />
+
</gwt:HTMLPanel>
</gwt:Dock>
</gwt:DockPanel>
diff --git a/user/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java
index 200e004..02b6946 100644
--- a/user/test/com/google/gwt/user/UISuite.java
+++ b/user/test/com/google/gwt/user/UISuite.java
@@ -45,6 +45,7 @@
import com.google.gwt.user.client.ui.DefaultSuggestionDisplayTest;
import com.google.gwt.user.client.ui.DelegatingKeyboardListenerCollectionTest;
import com.google.gwt.user.client.ui.DialogBoxTest;
+import com.google.gwt.user.client.ui.DirectionalTextHelperTest;
import com.google.gwt.user.client.ui.DisclosurePanelTest;
import com.google.gwt.user.client.ui.DockLayoutPanelRtlTest;
import com.google.gwt.user.client.ui.DockLayoutPanelTest;
@@ -147,6 +148,7 @@
suite.addTestSuite(DefaultSuggestionDisplayTest.class);
suite.addTestSuite(DelegatingKeyboardListenerCollectionTest.class);
suite.addTestSuite(DialogBoxTest.class);
+ suite.addTestSuite(DirectionalTextHelperTest.class);
suite.addTestSuite(DisclosurePanelTest.class);
suite.addTestSuite(DockLayoutPanelRtlTest.class);
suite.addTestSuite(DockLayoutPanelTest.class);
@@ -220,4 +222,3 @@
return suite;
}
}
-
diff --git a/user/test/com/google/gwt/user/cellview/client/AbstractCellTreeTestBase.java b/user/test/com/google/gwt/user/cellview/client/AbstractCellTreeTestBase.java
index 8dbc539..574c596 100644
--- a/user/test/com/google/gwt/user/cellview/client/AbstractCellTreeTestBase.java
+++ b/user/test/com/google/gwt/user/cellview/client/AbstractCellTreeTestBase.java
@@ -1,12 +1,12 @@
/*
* Copyright 2010 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
@@ -15,6 +15,7 @@
*/
package com.google.gwt.user.cellview.client;
+import com.google.gwt.user.cellview.client.AbstractHasDataTestBase.IndexCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.Scheduler;
@@ -56,8 +57,7 @@
/**
* The root data provider.
*/
- private final ListDataProvider<String> rootDataProvider =
- createDataProvider("");
+ private final ListDataProvider<String> rootDataProvider = createDataProvider("");
public <T> NodeInfo<?> getNodeInfo(T value) {
if (value == ROOT_VALUE) {
@@ -93,7 +93,7 @@
/**
* Create a data provider that extends the prefix by one letter.
- *
+ *
* @param prefix the prefix string
* @return a data provider
*/
@@ -163,7 +163,7 @@
/**
* Construct a new {@link AbstractCellTreeTestBase}.
- *
+ *
* @param singlePathOnly true if the tree only supports a single open path
*/
public AbstractCellTreeTestBase(boolean singlePathOnly) {
@@ -199,14 +199,16 @@
public void testRenderWithKeyProvider() {
// Create a cell that verifies the render args.
final List<String> rendered = new ArrayList<String>();
- final Cell<String> cell = new TextCell() {
+ final IndexCell<String> cell = new IndexCell<String>() {
@Override
- public void render(String data, Object key, SafeHtmlBuilder sb) {
- int call = rendered.size();
+ public void render(Context context, String data, SafeHtmlBuilder sb) {
+ super.render(context, data, sb);
+ int call = rendered.size();
rendered.add(data);
assertTrue("render() called more than thrice", rendered.size() < 4);
assertEquals(call + "value", data);
+ Object key = context.getKey();
assertTrue(key instanceof Integer);
assertEquals(call, key);
}
@@ -241,11 +243,12 @@
public void execute() {
assertEquals("Cell#render() should be called exactly thrice", 3,
rendered.size());
+ cell.assertLastRenderIndex(2);
finishTest();
}
});
}
-
+
/**
* Test that opening a sibling node works.
*/
@@ -565,7 +568,7 @@
/**
* Create an {@link AbstractCellTree} to test.
- *
+ *
* @param <T> the data type of the root value
* @param model the {@link TreeViewModel} that backs the tree
* @param rootValue the root value
@@ -588,7 +591,7 @@
/**
* Test the state of a {@link TreeNode}.
- *
+ *
* @param node the node to test
* @param parent the expected parent
* @param index the expected index within the parent
diff --git a/user/test/com/google/gwt/user/cellview/client/AbstractHasDataTestBase.java b/user/test/com/google/gwt/user/cellview/client/AbstractHasDataTestBase.java
index e3427bf..d56a3f5 100644
--- a/user/test/com/google/gwt/user/cellview/client/AbstractHasDataTestBase.java
+++ b/user/test/com/google/gwt/user/cellview/client/AbstractHasDataTestBase.java
@@ -1,12 +1,12 @@
/*
* Copyright 2010 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
@@ -15,9 +15,16 @@
*/
package com.google.gwt.user.cellview.client;
+import com.google.gwt.cell.client.AbstractCell;
+import com.google.gwt.cell.client.Cell;
+import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.cell.client.ValueUpdater;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.regexp.shared.MatchResult;
import com.google.gwt.regexp.shared.RegExp;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.client.Window;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.Range;
@@ -30,13 +37,69 @@
*/
public abstract class AbstractHasDataTestBase extends GWTTestCase {
+ /**
+ * A mock cell that tests the index specified in each method.
+ *
+ * @param <C> the cell type
+ */
+ protected static class IndexCell<C> extends AbstractCell<C> {
+ private int lastBrowserEventIndex = -1;
+ private int lastEditingIndex = -1;
+ private int lastRenderIndex = -1;
+ private int lastResetFocusIndex = -1;
+
+ public IndexCell(String... consumedEvents) {
+ super(consumedEvents);
+ }
+
+ public void assertLastBrowserEventIndex(int expected) {
+ assertEquals(expected, lastBrowserEventIndex);
+ }
+
+ public void assertLastEditingIndex(int expected) {
+ assertEquals(expected, lastEditingIndex);
+ }
+
+ public void assertLastRenderIndex(int expected) {
+ assertEquals(expected, lastRenderIndex);
+ }
+
+ public void assertLastResetFocusIndex(int expected) {
+ assertEquals(expected, lastResetFocusIndex);
+ }
+
+ @Override
+ public boolean isEditing(Context context, Element parent, C value) {
+ this.lastEditingIndex = context.getIndex();
+ return false;
+ }
+
+ @Override
+ public void onBrowserEvent(Context context, Element parent, C value,
+ NativeEvent event, ValueUpdater<C> valueUpdater) {
+ this.lastBrowserEventIndex = context.getIndex();
+ }
+
+ @Override
+ public void render(Context context, C value, SafeHtmlBuilder sb) {
+ this.lastRenderIndex = context.getIndex();
+ sb.appendEscaped("index " + this.lastRenderIndex);
+ }
+
+ @Override
+ public boolean resetFocus(Context context, Element parent, C value) {
+ this.lastResetFocusIndex = context.getIndex();
+ return false;
+ }
+ }
+
@Override
public String getModuleName() {
return "com.google.gwt.user.cellview.CellView";
}
public void testGetVisibleItem() {
- AbstractHasData<String> display = createAbstractHasData();
+ AbstractHasData<String> display = createAbstractHasData(new TextCell());
ListDataProvider<String> provider = new ListDataProvider<String>(
createData(0, 13));
provider.addDataDisplay(display);
@@ -65,7 +128,7 @@
}
public void testGetVisibleItems() {
- AbstractHasData<String> display = createAbstractHasData();
+ AbstractHasData<String> display = createAbstractHasData(new TextCell());
ListDataProvider<String> provider = new ListDataProvider<String>();
provider.addDataDisplay(display);
display.setVisibleRange(10, 3);
@@ -82,8 +145,21 @@
assertEquals("test 12", items.get(2));
}
+ public void testResetFocus() {
+ IndexCell<String> cell = new IndexCell<String>();
+ AbstractHasData<String> display = createAbstractHasData(cell);
+ display.setRowData(createData(0, 10));
+ display.getPresenter().flush();
+
+ cell.assertLastResetFocusIndex(-1);
+ display.getPresenter().setKeyboardSelectedRow(5, false, false);
+ display.resetFocusOnCell();
+ cell.assertLastResetFocusIndex(5);
+ }
+
public void testSetRowData() {
- AbstractHasData<String> display = createAbstractHasData();
+ IndexCell<String> cell = new IndexCell<String>();
+ AbstractHasData<String> display = createAbstractHasData(cell);
// Set exact data.
List<String> values = createData(0, 62);
@@ -110,6 +186,13 @@
assertTrue(display.isRowCountExact());
assertEquals(values, display.getVisibleItems());
assertEquals(new Range(0, 62), display.getVisibleRange());
+ display.getPresenter().flush();
+
+ // Render one row and verify the index.
+ display.setRowData(5, createData(100, 1));
+ display.getPresenter().flush();
+ assertEquals("test 100", display.getVisibleItem(5));
+ cell.assertLastRenderIndex(5);
}
public void testSetTabIndex() {
@@ -123,7 +206,7 @@
}
}
- AbstractHasData<String> display = createAbstractHasData();
+ AbstractHasData<String> display = createAbstractHasData(new TextCell());
ListDataProvider<String> provider = new ListDataProvider<String>(
createData(0, 10));
provider.addDataDisplay(display);
@@ -147,14 +230,16 @@
/**
* Create an {@link AbstractHasData} to test.
- *
+ *
+ * @param cell the cell to use
* @return the widget to test
*/
- protected abstract AbstractHasData<String> createAbstractHasData();
+ protected abstract AbstractHasData<String> createAbstractHasData(
+ Cell<String> cell);
/**
* Create a list of data for testing.
- *
+ *
* @param start the start index
* @param length the length
* @return a list of data
diff --git a/user/test/com/google/gwt/user/cellview/client/CellListTest.java b/user/test/com/google/gwt/user/cellview/client/CellListTest.java
index de16617..cc42e22 100644
--- a/user/test/com/google/gwt/user/cellview/client/CellListTest.java
+++ b/user/test/com/google/gwt/user/cellview/client/CellListTest.java
@@ -1,12 +1,12 @@
/*
* Copyright 2010 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
@@ -17,7 +17,11 @@
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.TextCell;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.view.client.ProvidesKey;
import java.util.ArrayList;
@@ -29,13 +33,30 @@
public class CellListTest extends AbstractHasDataTestBase {
public void testGetRowElement() {
- CellList<String> list = createAbstractHasData();
+ CellList<String> list = createAbstractHasData(new TextCell());
list.setRowData(0, createData(0, 10));
// Ensure that calling getRowElement() flushes all pending changes.
assertNotNull(list.getRowElement(9));
}
+ public void testCellEvent() {
+ IndexCell<String> cell = new IndexCell<String>("click");
+ CellList<String> list = createAbstractHasData(cell);
+ RootPanel.get().add(list);
+ list.setRowData(createData(0, 10));
+ list.getPresenter().flush();
+
+ // Trigger an event at index 5.
+ NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false,
+ false, false, false);
+ list.getRowElement(5).dispatchEvent(event);
+ cell.assertLastBrowserEventIndex(5);
+ cell.assertLastEditingIndex(5);
+
+ RootPanel.get().remove(list);
+ }
+
/**
* Test that the correct values are sent to the Cell to be rendered.
*/
@@ -44,12 +65,13 @@
final List<String> rendered = new ArrayList<String>();
final Cell<String> cell = new TextCell() {
@Override
- public void render(String data, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, SafeHtml data, SafeHtmlBuilder sb) {
int call = rendered.size();
- rendered.add(data);
+ rendered.add(data.asString());
assertTrue("render() called more than ten times", rendered.size() < 11);
- assertEquals("test " + call, data);
+ Object key = context.getKey();
+ assertEquals("test " + call, data.asString());
assertTrue(key instanceof Integer);
assertEquals(call, key);
}
@@ -68,7 +90,7 @@
}
@Override
- protected CellList<String> createAbstractHasData() {
- return new CellList<String>(new TextCell());
+ protected CellList<String> createAbstractHasData(Cell<String> cell) {
+ return new CellList<String>(cell);
}
}
diff --git a/user/test/com/google/gwt/user/cellview/client/CellTableTest.java b/user/test/com/google/gwt/user/cellview/client/CellTableTest.java
index d47d9c4..535bcd8 100644
--- a/user/test/com/google/gwt/user/cellview/client/CellTableTest.java
+++ b/user/test/com/google/gwt/user/cellview/client/CellTableTest.java
@@ -15,8 +15,11 @@
*/
package com.google.gwt.user.cellview.client;
+import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableElement;
import com.google.gwt.dom.client.TableRowElement;
@@ -26,6 +29,7 @@
import com.google.gwt.user.cellview.client.CellTable.Style;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
+import com.google.gwt.user.client.ui.RootPanel;
import java.util.ArrayList;
import java.util.List;
@@ -64,7 +68,7 @@
}
public void testCellAlignment() {
- CellTable<String> table = createAbstractHasData();
+ CellTable<String> table = createAbstractHasData(new TextCell());
Column<String, String> column = new Column<String, String>(new TextCell()) {
@Override
public String getValue(String object) {
@@ -117,8 +121,25 @@
assertTrue("bottom".equals(vAlign));
}
+ public void testCellEvent() {
+ IndexCell<String> cell = new IndexCell<String>("click");
+ CellTable<String> table = createAbstractHasData(cell);
+ RootPanel.get().add(table);
+ table.setRowData(createData(0, 10));
+ table.getPresenter().flush();
+
+ // Trigger an event at index 5.
+ NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false,
+ false, false, false);
+ table.getRowElement(5).getCells().getItem(0).dispatchEvent(event);
+ cell.assertLastBrowserEventIndex(5);
+ cell.assertLastEditingIndex(5);
+
+ RootPanel.get().remove(table);
+ }
+
public void testGetRowElement() {
- CellTable<String> table = createAbstractHasData();
+ CellTable<String> table = createAbstractHasData(new TextCell());
table.setRowData(0, createData(0, 10));
// Ensure that calling getRowElement() flushes all pending changes.
@@ -238,9 +259,9 @@
}
@Override
- protected CellTable<String> createAbstractHasData() {
+ protected CellTable<String> createAbstractHasData(Cell<String> cell) {
CellTable<String> table = new CellTable<String>();
- table.addColumn(new Column<String, String>(new TextCell()) {
+ table.addColumn(new Column<String, String>(cell) {
@Override
public String getValue(String object) {
return object;
diff --git a/user/test/com/google/gwt/user/cellview/client/ColumnTest.java b/user/test/com/google/gwt/user/cellview/client/ColumnTest.java
index c96a0a7..6190c90 100644
--- a/user/test/com/google/gwt/user/cellview/client/ColumnTest.java
+++ b/user/test/com/google/gwt/user/cellview/client/ColumnTest.java
@@ -19,6 +19,7 @@
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.cell.client.ValueUpdater;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
@@ -38,12 +39,12 @@
AbstractEditableCell<String, String> {
@Override
- public boolean isEditing(Element parent, String value, Object key) {
+ public boolean isEditing(Context context, Element parent, String value) {
return false;
}
@Override
- public void render(String value, Object key, SafeHtmlBuilder sb) {
+ public void render(Context context, String value, SafeHtmlBuilder sb) {
sb.appendEscaped(value);
}
}
@@ -101,7 +102,7 @@
false, false, false, false);
final MockEditableCell cell = new MockEditableCell() {
@Override
- public void onBrowserEvent(Element parent, String value, Object key,
+ public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, final ValueUpdater<String> valueUpdater) {
setViewData("test", "newViewData");
new Timer() {
@@ -126,7 +127,8 @@
// Fire the event to the cell.
delayTestFinish(5000);
cell.setViewData("test", "oldViewData");
- column.onBrowserEvent(theElem, 3, "test", theEvent, null);
+ Context context = new Context(3, 0, null);
+ column.onBrowserEvent(context, theElem, "test", theEvent);
}
public void testGetCell() {
@@ -141,7 +143,7 @@
false, false, false, false);
final MockEditableCell cell = new MockEditableCell() {
@Override
- public void onBrowserEvent(Element parent, String value, Object key,
+ public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
assertEquals(theElem, parent);
assertEquals("test", value);
@@ -164,7 +166,8 @@
column.setFieldUpdater(fieldUpdater);
cell.setViewData("test", "oldViewData");
- column.onBrowserEvent(theElem, 3, "test", theEvent, null);
+ Context context = new Context(3, 0, null);
+ column.onBrowserEvent(context, theElem, "test", theEvent);
fieldUpdater.assertUpdateCalled(true);
fieldUpdater.assertIndex(3);
@@ -178,7 +181,7 @@
false, false, false, false);
final MockEditableCell cell = new MockEditableCell() {
@Override
- public void onBrowserEvent(Element parent, String value, Object key,
+ public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
assertEquals(theElem, parent);
assertEquals("test", value);
@@ -191,7 +194,8 @@
Column<String, String> column = new IdentityColumn<String>(cell);
cell.setViewData("test", "oldViewData");
- column.onBrowserEvent(theElem, 3, "test", theEvent, null);
+ Context context = new Context(3, 0, null);
+ column.onBrowserEvent(context, theElem, "test", theEvent);
}
public void testRender() {
@@ -199,7 +203,8 @@
Column<String, String> column = new IdentityColumn<String>(cell);
SafeHtmlBuilder sb = new SafeHtmlBuilder();
- column.render("test", null, sb);
+ Context context = new Context(0, 0, null);
+ column.render(context, "test", sb);
assertEquals("test", sb.toSafeHtml().asString());
}
}
diff --git a/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTest.java b/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTest.java
index 1303260..0a8c7fa 100644
--- a/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/UnicodeEscapingTest.java
@@ -108,7 +108,7 @@
}
/** start of current block being tested. */
- private int current;
+ protected int current;
@Override
public String getModuleName() {
@@ -234,7 +234,7 @@
NON_BMP_TEST_INCREMENT);
}
- private void clientToServerVerifyRange(final int start, final int end,
+ protected void clientToServerVerifyRange(final int start, final int end,
final int size, final int step) throws InvalidCharacterException {
current = start;
int blockEnd = Math.min(end, current + size);
@@ -274,7 +274,7 @@
});
}
- private void serverToClientVerify(final int start, final int end,
+ protected void serverToClientVerify(final int start, final int end,
final int size, final int step) {
current = start;
getService().getStringContainingCharacterRange(start,
diff --git a/user/test/com/google/gwt/user/client/ui/DirectionalTextHelperTest.java b/user/test/com/google/gwt/user/client/ui/DirectionalTextHelperTest.java
new file mode 100644
index 0000000..a5e9561
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/DirectionalTextHelperTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2010 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.client.ui;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.i18n.client.BidiUtils;
+import com.google.gwt.i18n.client.HasDirection.Direction;
+import com.google.gwt.i18n.client.LocaleInfo;
+import com.google.gwt.i18n.shared.AnyRtlDirectionEstimator;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests {@link DirectionalTextHelper}.
+ */
+public class DirectionalTextHelperTest extends GWTTestCase {
+
+ private final String EN_TEXT = "abc";
+ private final String IW_TEXT = "\u05e0\u05e1\u05e2";
+ private final String EN_HTML = "<b style=\"color: red\">" + EN_TEXT + "</b>";
+ private final String IW_HTML = "<b style=\"color: red\">" + IW_TEXT + "</b>";
+ private Element element;
+ private DirectionalTextHelper directionalTextHelper;
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.User";
+ }
+
+ // setDirection is deprecated; this only assures backwards compatibility.
+ public void testSetDirection() {
+ element = Document.get().createSpanElement();
+ directionalTextHelper = new DirectionalTextHelper(element,
+ /* is inline? */ true);
+
+ directionalTextHelper.setDirection(Direction.RTL);
+ assertDirection("element's direction is incorrect after setDirection",
+ Direction.RTL);
+
+ directionalTextHelper.setTextOrHtml(EN_TEXT, Direction.LTR, false);
+ assertDirection("target's direction is incorrect after setText with a" +
+ "specific direction", Direction.LTR);
+
+ directionalTextHelper.setTextOrHtml(EN_TEXT, false);
+ assertDirection("target's direction wasn't reverted to the direction set" +
+ "by last setDirection when calling setText with no direction argument" +
+ "and without a directionEstimator", Direction.RTL);
+
+ // We also specifically assert that the direction of the topmost element
+ // matches the last setDirection. (this is needed only for inline elements).
+ assertEquals("element's direction does not match the direction set by " +
+ "last setDirection when calling setText with no direction argument " +
+ "and without a directionEstimator", Direction.RTL,
+ BidiUtils.getDirectionOnElement(element));
+ }
+
+ public void testSetDirectionEstimator() {
+ element = Document.get().createSpanElement();
+ BidiUtils.setDirectionOnElement(element, Direction.LTR);
+ directionalTextHelper = new DirectionalTextHelper(element,
+ /* is inline? */ true);
+ directionalTextHelper.setDirectionEstimator(true);
+
+ // If the element is span-wrapped, a redundant refresh occurred.
+ assertFalse("setDirectionEstimator(true) refreshed appearance before text" +
+ "had been received", isSpanWrapped());
+
+ directionalTextHelper.setDirectionEstimator(false);
+ directionalTextHelper.setTextOrHtml(IW_TEXT, false);
+ assertDirection("Original element's direction (LTR) was modified with no" +
+ "apparent reason", Direction.LTR);
+
+ directionalTextHelper.setDirectionEstimator(true);
+ assertDirection("Direction was not refreshed on " +
+ "setDirectionEstimator(true) after receiving text with no explicit " +
+ "direction", Direction.RTL);
+
+ directionalTextHelper.setTextOrHtml(IW_TEXT, Direction.LTR, false);
+ directionalTextHelper.setDirectionEstimator(
+ AnyRtlDirectionEstimator.get());
+ assertDirection("Direction was refreshed on setDirectionEstimator after " +
+ "receiving text with explicit direction", Direction.LTR);
+
+ directionalTextHelper.setTextOrHtml(IW_TEXT, false);
+ directionalTextHelper.setDirectionEstimator(false);
+ assertDirection("Direction was not reset to the initial element direction" +
+ " on turning off direction estimation when last call to setTextOrHtml" +
+ " did not declare explicit direction.", Direction.LTR);
+ }
+
+ public void testSetDirectionEstimatorAndSetHtml() {
+ testSetTextOrHtml(true);
+ }
+
+ public void testSetDirectionEstimatorAndSetText() {
+ testSetTextOrHtml(false);
+ }
+
+ /**
+ * Asserts that both the {@link HasDirectionalText#getTextDirection} and the
+ * physical dir attribute match the expected direction.
+ *
+ * @param message Assertion message
+ * @param expected Expected direction
+ */
+ private void assertDirection(String message, Direction expected) {
+ assertTrue("dir attribute mismatch: " + message,
+ expected == getElementDirection() ||
+ /* For inline elements, empty dir attribute is acceptable if LTR is
+ * expected and the locale is not RTL. */
+ isSpanWrapped() && getElementDirection() == Direction.DEFAULT &&
+ (expected == Direction.RTL) == LocaleInfo.getCurrentLocale().isRTL());
+
+ assertEquals("textDir mismatch: " + message, expected,
+ directionalTextHelper.getTextDirection());
+ }
+
+ private Direction getElementDirection() {
+ Element elem = isSpanWrapped() ? element.getFirstChildElement() : element;
+ return BidiUtils.getDirectionOnElement(elem);
+ }
+
+ // This will not work generally. It assumes that the widget's content isn't
+ // consist of a span tag.
+ private boolean isSpanWrapped() {
+ Element inner = element.getFirstChildElement();
+ return inner != null && inner.getTagName().equalsIgnoreCase("span");
+ }
+
+ private void testSetTextOrHtml(boolean isHtml) {
+ String enContent = isHtml ? EN_HTML : EN_TEXT;
+ String iwContent = isHtml ? IW_HTML : IW_TEXT;
+ for (int i = 0; i < 2; i++) {
+ boolean isDiv = i == 0;
+ String id = isDiv ? "div widget: " : "span widget: ";
+ element = isDiv ? Document.get().createDivElement() :
+ Document.get().createSpanElement();
+ directionalTextHelper = new DirectionalTextHelper(element,
+ /* is inline? */ !isDiv);
+
+ directionalTextHelper.setTextOrHtml(enContent, isHtml);
+ assertDirection(id + "widget's direction is not DEFAULT upon " +
+ "standard initialization", Direction.DEFAULT);
+
+ directionalTextHelper.setTextOrHtml(iwContent, Direction.RTL, isHtml);
+ assertDirection(id + "widget's direction is not RTL after it was" +
+ " explicitly set to RTL", Direction.RTL);
+
+ directionalTextHelper.setTextOrHtml(enContent, isHtml);
+ assertDirection(id + "widget's direction was not specified, and no" +
+ " estimator specified, thus should return to initial value (DEFAULT)",
+ Direction.DEFAULT);
+
+ // Toggling on direction estimation from now on.
+ directionalTextHelper.setDirectionEstimator(true);
+
+ assertDirection(id + "widget's direction wasn't instantly updated" +
+ " to LTR on switching direction estimation on", Direction.LTR);
+
+ directionalTextHelper.setTextOrHtml(iwContent, isHtml);
+ assertDirection(id + "widget's direction wasn't estimated as RTL",
+ Direction.RTL);
+
+ directionalTextHelper.setTextOrHtml(iwContent, Direction.LTR, isHtml);
+ assertDirection(id + "widget's direction is not LTR after it was" +
+ " explicitly set to LTR (direction estimation is on)", Direction.LTR);
+
+ directionalTextHelper.setTextOrHtml(iwContent, Direction.DEFAULT, isHtml);
+ assertDirection(id + "widget's direction is not DEFAULT after it" +
+ " was explicitly set to DEFAULT (direction estimation is on)",
+ Direction.DEFAULT);
+
+ // TODO(jlabanca): Need a cross-browser way to test innerHTML.
+ // assertEquals(id + "retreived html is incorrect", iwContent,
+ // directionalTextHelper.getTextOrHtml(true).toLowerCase());
+ assertEquals(id + "retreived text is incorrect", IW_TEXT,
+ directionalTextHelper.getTextOrHtml(false).toLowerCase());
+ }
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/HTMLTest.java b/user/test/com/google/gwt/user/client/ui/HTMLTest.java
index ee84fc1..a483950 100644
--- a/user/test/com/google/gwt/user/client/ui/HTMLTest.java
+++ b/user/test/com/google/gwt/user/client/ui/HTMLTest.java
@@ -15,10 +15,7 @@
*/
package com.google.gwt.user.client.ui;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.i18n.client.BidiUtils;
import com.google.gwt.i18n.client.HasDirection.Direction;
-import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
/**
@@ -28,9 +25,6 @@
public class HTMLTest extends LabelTest {
private static final String html = "<b>hello</b><i>world</i>";
- private final String EN_HTML = "<b style=\"color: red\">" + EN_TEXT + "</b>";
- private final String IW_HTML = "<b style=\"color: red\">" + IW_TEXT + "</b>";
- private HTML label;
@Override
public String getModuleName() {
@@ -58,43 +52,6 @@
assertEquals(Direction.RTL, htmlElementRTL.getTextDirection());
}
- // setDirection is deprecated; this only assures backwards compatibility.
- public void testSetDirection() {
- for (int i = 0; i < 2; i++) {
- String id = i == 0 ? "div label: " : "span label: ";
- label = HTML.wrap(i == 0 ? createAttachedDivElement() :
- createAttachedSpanElement());
- label.setDirection(Direction.RTL);
- assertLabelDirection(id + "label's direction is incorrect after " +
- "setDirection", Direction.RTL);
-
- label.setText(EN_TEXT, Direction.LTR);
- assertLabelDirection(id + "label's direction is incorrect after " +
- "setText with a specific direction", Direction.LTR);
-
- label.setText(EN_TEXT);
- assertLabelDirection(id + "label's direction wasn't reverted to the " +
- "direction set by last setDirection when calling setText with no " +
- "direction argument and without a directionEstimator", Direction.RTL);
- if (i == 1) {
- // For span element, we also specifically assert that the direction of
- // the topmost element matches the last setDirection.
- assertEquals(id + "element's direction does not match the direction " +
- "set by last setDirection when calling setText with no direction " +
- "argument and without a directionEstimator", Direction.RTL,
- BidiUtils.getDirectionOnElement(label.getElement()));
- }
- }
- }
-
- public void testSetDirectionEstimatorAndSetHtml() {
- testSetDirectionEstimatorAndSetTextOrHtml(true);
- }
-
- public void testSetDirectionEstimatorAndSetText() {
- testSetDirectionEstimatorAndSetTextOrHtml(false);
- }
-
public void testSetSafeHtml() {
HTML htmlElement = new HTML("<b>foo</b>");
htmlElement.setHTML(SafeHtmlUtils.fromSafeConstant(html));
@@ -111,98 +68,4 @@
assertEquals(Direction.LTR, htmlElement.getDirection());
}
- /**
- * Asserts that both the {@link Label#getTextDirection} and the physical dir
- * attribute match the expected direction.
- *
- * @param message Assertion message
- * @param expected Expected direction
- */
- private void assertLabelDirection(String message, Direction expected) {
- assertTrue("attribute mismatch: " + message,
- expected == getLabelDirection() ||
- /* For inline elements, empty dir attribute is acceptable if LTR is
- * expected and the locale is not RTL. */
- isSpanWrapped() && getLabelDirection() == Direction.DEFAULT &&
- expected == Direction.LTR && !LocaleInfo.getCurrentLocale().isRTL());
-
- assertEquals("textDir mismatch: " + message, expected,
- label.getTextDirection());
- }
-
- private Direction getLabelDirection() {
- Element element = isSpanWrapped() ?
- label.getElement().getFirstChildElement() : label.getElement();
-
- return BidiUtils.getDirectionOnElement(element);
- }
-
- // This will not work generally. It assumes that the label's content isn't
- // consist of a span tag.
- private boolean isSpanWrapped() {
- Element inner = label.getElement().getFirstChildElement();
- return inner != null && inner.getTagName().equalsIgnoreCase("span");
- }
-
- private void setLabelTextOrHtml(String content, boolean isHtml) {
- if (isHtml) {
- label.setHTML(content);
- } else {
- label.setText(content);
- }
- }
-
- private void setLabelTextOrHtml(String content, Direction dir, boolean isHtml) {
- if (isHtml) {
- label.setHTML(content, dir);
- } else {
- label.setText(content, dir);
- }
- }
-
- private void testSetDirectionEstimatorAndSetTextOrHtml(boolean isHtml) {
- String enContent = isHtml ? EN_HTML : EN_TEXT;
- String iwContent = isHtml ? IW_HTML : IW_TEXT;
- for (int i = 0; i < 2; i++) {
- String id = i == 0 ? "div label: " : "span label: ";
- label = HTML.wrap(i == 0 ? createAttachedDivElement() :
- createAttachedSpanElement());
-
- setLabelTextOrHtml(enContent, isHtml);
- assertLabelDirection(id + "label's direction is not DEFAULT upon " +
- "standard initialization", Direction.DEFAULT);
-
- setLabelTextOrHtml(iwContent, Direction.RTL, isHtml);
- assertLabelDirection(id + "label's direction is not RTL after it was" +
- " explicitly set to RTL", Direction.RTL);
-
- setLabelTextOrHtml(enContent, isHtml);
- assertLabelDirection(id + "label's direction was not specified, and no" +
- " estimator specified, thus should return to initial value (DEFAULT)",
- Direction.DEFAULT);
-
- label.setDirectionEstimator(true);
- assertLabelDirection(id + "label's direction wasn't instantly updated" +
- " to LTR on switching direction estimation on", Direction.LTR);
-
- setLabelTextOrHtml(iwContent, isHtml);
- assertLabelDirection(id + "label's direction wasn't estimated as RTL",
- Direction.RTL);
-
- setLabelTextOrHtml(iwContent, Direction.LTR, isHtml);
- assertLabelDirection(id + "label's direction is not LTR after it was" +
- " explicitly set to LTR (direction estimation is on)", Direction.LTR);
-
- setLabelTextOrHtml(iwContent, Direction.DEFAULT, isHtml);
- assertLabelDirection(id + "label's direction is not DEFAULT after it" +
- " was explicitly set to DEFAULT (direction estimation is on)",
- Direction.DEFAULT);
-
- // TODO(jlabanca): Need a cross-browser way to test innerHTML.
- // assertEquals(id + "retreived html is incorrect", iwContent,
- // label.getHTML().toLowerCase());
- assertEquals(id + "retreived text is incorrect", IW_TEXT,
- label.getText().toLowerCase());
- }
- }
}
diff --git a/user/test/com/google/gwt/user/client/ui/LabelTest.java b/user/test/com/google/gwt/user/client/ui/LabelTest.java
index 00a949d..d43d87e 100644
--- a/user/test/com/google/gwt/user/client/ui/LabelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/LabelTest.java
@@ -22,7 +22,6 @@
import com.google.gwt.i18n.client.BidiUtils;
import com.google.gwt.i18n.client.HasDirection.Direction;
import com.google.gwt.junit.client.GWTTestCase;
-import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.client.ui.HasHorizontalAlignment.AutoHorizontalAlignmentConstant;
import com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant;
@@ -92,7 +91,7 @@
// Initialize the div with a specific direction, to verify it remembers its
// original direction on turning direction estimator off.
BidiUtils.setDirectionOnElement(elem, Direction.LTR);
- label = Label.wrap(createAttachedDivElement());
+ label = Label.wrap(elem);
label.setAutoHorizontalAlignment(
HasAutoHorizontalAlignment.ALIGN_CONTENT_END);
@@ -118,23 +117,28 @@
HasAutoHorizontalAlignment.ALIGN_CONTENT_START);
label.setDirectionEstimator(false);
- assertAlign("direction was supposed to be reset to the original " +
- "ALIGN_LEFT after turning off direction estimator, and automatic " +
- "horizontal alignment was to ALIGN_CONTENT_START",
+ assertAlign("horizontal alignment was supposed to be reset to the " +
+ "original ALIGN_LEFT after turning off direction estimator, and " +
+ "automatic horizontal alignment was to ALIGN_CONTENT_START",
HasHorizontalAlignment.ALIGN_LEFT,
HasAutoHorizontalAlignment.ALIGN_CONTENT_START);
}
- @SuppressWarnings("deprecation")
- public void testSetSafeHtml() {
- Label label = new Label("foo");
- label.setHTML(SafeHtmlUtils.fromSafeConstant(html1));
-
- assertEquals(html1, label.getTextOrHtml(true).toLowerCase());
-
- label.setHTML(SafeHtmlUtils.fromSafeConstant(html2), Direction.LTR);
-
- assertEquals(html2, label.getTextOrHtml(true).toLowerCase());
+ public void testSetDirection() {
+ Label label = new Label(createAttachedSpanElement());
+ label.setDirectionEstimator(true);
+ label.setText(IW_TEXT);
+
+ // Should be span wrapped.
+ assertTrue(label.getElement().getInnerHTML().toLowerCase().contains("span"));
+
+ // Should not be span wrapped.
+ label.setDirection(Direction.RTL);
+ assertEquals(Direction.RTL, label.getDirection());
+ assertFalse(label.getElement().getInnerHTML().toLowerCase().contains("span"));
+
+ // Should not be span wrapped.
+ label.setDirection(Direction.LTR);
assertEquals(Direction.LTR, label.getDirection());
}
diff --git a/user/test/com/google/gwt/view/client/DefaultSelectionEventManagerTest.java b/user/test/com/google/gwt/view/client/DefaultSelectionEventManagerTest.java
index 7ab159c..c1cec44 100644
--- a/user/test/com/google/gwt/view/client/DefaultSelectionEventManagerTest.java
+++ b/user/test/com/google/gwt/view/client/DefaultSelectionEventManagerTest.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.view.client;
+import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.junit.client.GWTTestCase;
@@ -215,7 +216,7 @@
NativeEvent nativeEvent = Document.get().createClickEvent(0, 0, 0, 0, 0,
false, false, false, false);
CellPreviewEvent<String> event = new CellPreviewEvent<String>(nativeEvent,
- display, 1, 0, "test 1", false, false);
+ display, new Context(1, 0, null), "test 1", false, false);
manager.handleSelectionEvent(event, null, model);
assertEquals("test 1", model.getSelectedObject());
@@ -226,16 +227,16 @@
// Ctrl+Select the same value.
nativeEvent = Document.get().createClickEvent(0, 0, 0, 0, 0, true, false,
false, true);
- event = new CellPreviewEvent<String>(nativeEvent, display, 1, 0, "test 1",
- false, false);
+ event = new CellPreviewEvent<String>(nativeEvent, display, new Context(1,
+ 0, null), "test 1", false, false);
manager.handleSelectionEvent(event, null, model);
assertNull(model.getSelectedObject());
// Spacebar a different value.
nativeEvent = Document.get().createKeyUpEvent(false, false, false, false,
32);
- event = new CellPreviewEvent<String>(nativeEvent, display, 2, 0, "test 2",
- false, false);
+ event = new CellPreviewEvent<String>(nativeEvent, display, new Context(2,
+ 0, null), "test 2", false, false);
manager.handleSelectionEvent(event, null, model);
assertEquals("test 2", model.getSelectedObject());
@@ -253,13 +254,13 @@
NativeEvent nativeEvent = Document.get().createClickEvent(0, 0, 0, 0, 0,
false, false, false, false);
CellPreviewEvent<String> event = new CellPreviewEvent<String>(nativeEvent,
- display, 1, 0, "test 1", false, false);
+ display, new Context(1, 0, null), "test 1", false, false);
manager.handleSelectionEvent(event, SelectAction.DESELECT, model);
assertEquals("test 0", model.getSelectedObject());
// Deselect the same value.
- event = new CellPreviewEvent<String>(nativeEvent, display, 0, 0, "test 0",
- false, false);
+ event = new CellPreviewEvent<String>(nativeEvent, display, new Context(0,
+ 0, null), "test 0", false, false);
manager.handleSelectionEvent(event, SelectAction.DESELECT, model);
assertNull(model.getSelectedObject());
}
@@ -272,7 +273,7 @@
NativeEvent nativeEvent = Document.get().createClickEvent(0, 0, 0, 0, 0,
false, false, false, false);
CellPreviewEvent<String> event = new CellPreviewEvent<String>(nativeEvent,
- display, 3, 0, "test 3", false, false);
+ display, new Context(3, 0, null), "test 3", false, false);
manager.handleSelectionEvent(event, SelectAction.IGNORE, model);
assertEquals("test 0", model.getSelectedObject());
}
@@ -286,13 +287,13 @@
NativeEvent nativeEvent = Document.get().createClickEvent(0, 0, 0, 0, 0,
false, false, false, false);
CellPreviewEvent<String> event = new CellPreviewEvent<String>(nativeEvent,
- display, 0, 0, "test 0", false, false);
+ display, new Context(0, 0, null), "test 0", false, false);
manager.handleSelectionEvent(event, SelectAction.SELECT, model);
assertEquals("test 0", model.getSelectedObject());
// Select a different value.
- event = new CellPreviewEvent<String>(nativeEvent, display, 1, 0, "test 1",
- false, false);
+ event = new CellPreviewEvent<String>(nativeEvent, display, new Context(1,
+ 0, null), "test 1", false, false);
manager.handleSelectionEvent(event, SelectAction.SELECT, model);
assertEquals("test 1", model.getSelectedObject());
}
@@ -306,7 +307,7 @@
NativeEvent nativeEvent = Document.get().createClickEvent(0, 0, 0, 0, 0,
false, false, false, false);
CellPreviewEvent<String> event = new CellPreviewEvent<String>(nativeEvent,
- display, 1, 0, "test 1", false, false);
+ display, new Context(1, 0, null), "test 1", false, false);
manager.handleSelectionEvent(event, SelectAction.TOGGLE, model);
assertEquals("test 1", model.getSelectedObject());