Merge from 1.6 to trunk.
svn merge -r4911:4962 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
svn merge -r4963:4992 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4993 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
index a2d8be7..08d7f85 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -33,6 +33,7 @@
import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
import com.google.gwt.dev.util.arg.ArgHandlerSoyc;
import com.google.gwt.dev.util.arg.ArgHandlerWorkDirOptional;
+import com.google.gwt.util.tools.ToolBase;
import com.google.gwt.util.tools.Utility;
import java.io.File;
@@ -104,9 +105,8 @@
}
public static void main(String[] args) {
- System.err.println("WARNING: '" + GWTCompiler.class.getName()
- + "' is deprecated and will be removed in a future release.");
- System.err.println("Use '" + Compiler.class.getName() + "' instead.");
+ ToolBase.legacyWarn(GWTCompiler.class, Compiler.class);
+
/*
* NOTE: main always exits with a call to System.exit to terminate any
* non-daemon threads that were started in Generators. Typically, this is to
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index 425ca1e..1c7b3c9 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -27,6 +27,7 @@
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
import com.google.gwt.util.tools.ArgHandlerExtra;
+import com.google.gwt.util.tools.ToolBase;
import java.io.File;
@@ -128,9 +129,8 @@
}
public static void main(String[] args) {
- System.err.println("WARNING: '" + GWTShell.class.getName()
- + "' is deprecated and will be removed in a future release.");
- System.err.println("Use '" + HostedMode.class.getName() + "' instead.");
+ ToolBase.legacyWarn(GWTShell.class, HostedMode.class);
+
/*
* NOTE: main always exits with a call to System.exit to terminate any
* non-daemon threads that were started in Generators. Typically, this is to
diff --git a/dev/core/src/com/google/gwt/dev/HostedModeBase.java b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
index 9f983a3..f99d8dd 100644
--- a/dev/core/src/com/google/gwt/dev/HostedModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
@@ -326,6 +326,27 @@
}
}
+ public static String normalizeURL(String unknownUrlText, int port, String host) {
+ if (unknownUrlText.indexOf(":") != -1) {
+ // Assume it's a full url.
+ return unknownUrlText;
+ }
+
+ // Assume it's a trailing url path.
+ if (unknownUrlText.length() > 0 && unknownUrlText.charAt(0) == '/') {
+ unknownUrlText = unknownUrlText.substring(1);
+ }
+
+ if (port != 80) {
+ // CHECKSTYLE_OFF: Not really an assembled error message, so no space
+ // after ':'.
+ return "http://" + host + ":" + port + "/" + unknownUrlText;
+ // CHECKSTYLE_ON
+ } else {
+ return "http://" + host + "/" + unknownUrlText;
+ }
+ }
+
protected final HostedModeBaseOptions options;
/**
@@ -367,26 +388,7 @@
public abstract void launchStartupUrls(final TreeLogger logger);
public final String normalizeURL(String unknownUrlText) {
- if (unknownUrlText.indexOf(":") != -1) {
- // Assume it's a full url.
- return unknownUrlText;
- }
-
- // Assume it's a trailing url path.
- if (unknownUrlText.length() > 0 && unknownUrlText.charAt(0) == '/') {
- unknownUrlText = unknownUrlText.substring(1);
- }
-
- int port = getPort();
- String host = getHost();
- if (port != 80) {
- // CHECKSTYLE_OFF: Not really an assembled error message, so no space
- // after ':'.
- return "http://" + host + ":" + port + "/" + unknownUrlText;
- // CHECKSTYLE_ON
- } else {
- return "http://" + host + "/" + unknownUrlText;
- }
+ return normalizeURL(unknownUrlText, getPort(), getHost());
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/RunWebApp.java b/dev/core/src/com/google/gwt/dev/RunWebApp.java
new file mode 100644
index 0000000..a2c7ad9
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/RunWebApp.java
@@ -0,0 +1,144 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev;
+
+import com.google.gwt.core.ext.ServletContainer;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.HostedModeBase.OptionPort;
+import com.google.gwt.dev.HostedModeBase.OptionStartupURLs;
+import com.google.gwt.dev.shell.BrowserWidget;
+import com.google.gwt.dev.shell.jetty.JettyLauncher;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+import com.google.gwt.util.tools.ArgHandlerExtra;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * An experimental class for running web apps.
+ */
+public class RunWebApp {
+
+ interface RunWebAppOptions extends OptionStartupURLs, OptionPort {
+ }
+
+ static class RunWebAppOptionsImpl implements RunWebAppOptions {
+ private int port;
+ private final List<String> startupURLs = new ArrayList<String>();
+
+ public void addStartupURL(String url) {
+ startupURLs.add(url);
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public List<String> getStartupURLs() {
+ return Collections.unmodifiableList(startupURLs);
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+ }
+
+ private class ArgHandlerWar extends ArgHandlerExtra {
+ @Override
+ public boolean addExtraArg(String arg) {
+ warFile = new File(arg);
+ if (!warFile.exists()) {
+ System.err.println("Could not open war file '"
+ + warFile.getAbsolutePath() + "'");
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Specifies the name(s) of the module(s)";
+ }
+
+ @Override
+ public String[] getTagArgs() {
+ return new String[] {"module[s]"};
+ }
+
+ @Override
+ public boolean isRequired() {
+ return true;
+ }
+ }
+
+ private class ArgProcessor extends ArgProcessorBase {
+ public ArgProcessor(RunWebAppOptions options) {
+ registerHandler(new HostedMode.ArgHandlerStartupURLs(options));
+ registerHandler(new HostedModeBase.ArgHandlerPort(options));
+ registerHandler(new ArgHandlerWar());
+ }
+
+ @Override
+ protected String getName() {
+ return RunWebApp.class.getName();
+ }
+ }
+
+ public static void main(String[] args) {
+ try {
+ RunWebAppOptionsImpl options = new RunWebAppOptionsImpl();
+ RunWebApp runWebApp = new RunWebApp(options);
+ ArgProcessor argProcessor = runWebApp.new ArgProcessor(options);
+ if (argProcessor.processArgs(args)) {
+ runWebApp.run();
+ }
+ } catch (Exception e) {
+ System.err.println("Unable to start Jetty server");
+ e.printStackTrace();
+ }
+ }
+
+ protected File warFile;
+
+ private final RunWebAppOptions options;
+
+ public RunWebApp(RunWebAppOptions options) {
+ this.options = options;
+ }
+
+ protected void run() {
+ PrintWriterTreeLogger logger = new PrintWriterTreeLogger();
+ logger.setMaxDetail(TreeLogger.WARN);
+ int port = options.getPort();
+ try {
+ ServletContainer scl = new JettyLauncher().start(logger, port, warFile);
+ port = scl.getPort();
+ } catch (Exception e) {
+ System.err.println("Unable to start Jetty server");
+ e.printStackTrace();
+ return;
+ }
+ if (options.getStartupURLs().isEmpty()) {
+ options.addStartupURL("/");
+ }
+ for (String startupUrl : options.getStartupURLs()) {
+ startupUrl = HostedModeBase.normalizeURL(startupUrl, port, "localhost");
+ BrowserWidget.launchExternalBrowser(logger, startupUrl);
+ }
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/ServletValidator.java b/dev/core/src/com/google/gwt/dev/ServletValidator.java
index e5605be..24f021ef 100644
--- a/dev/core/src/com/google/gwt/dev/ServletValidator.java
+++ b/dev/core/src/com/google/gwt/dev/ServletValidator.java
@@ -16,12 +16,14 @@
package com.google.gwt.dev;
import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.shell.jetty.JettyNullLogger;
import org.mortbay.jetty.servlet.ServletHandler;
import org.mortbay.jetty.servlet.ServletHolder;
import org.mortbay.jetty.servlet.ServletMapping;
import org.mortbay.jetty.webapp.WebAppContext;
import org.mortbay.jetty.webapp.WebXmlConfiguration;
+import org.mortbay.log.Log;
import java.io.File;
import java.net.MalformedURLException;
@@ -38,6 +40,12 @@
*/
class ServletValidator {
+ static {
+ // Suppress spammy Jetty log initialization.
+ System.setProperty("org.mortbay.log.class", JettyNullLogger.class.getName());
+ Log.getLog();
+ }
+
public static ServletValidator create(TreeLogger logger, File webXml) {
try {
return create(logger, webXml.toURI().toURL());
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java b/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java
index a34680a..502ce0a 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java
@@ -179,10 +179,16 @@
errors.put(jsniRefString, refErrors);
}
} else if (!jsniRef.className().equals("null")) {
- GWTProblem.recordInCud(ProblemSeverities.Warning, meth, cud,
- "Referencing class '" + jsniRef.className()
- + ": unable to resolve class, expect subsequent failures",
- null);
+ /*
+ * TODO(scottb): re-enable this when we no longer get a bunch of
+ * false failures. Currently we can't resolve top level types (like
+ * boolean_Array_Rank_1_FieldSerializer), and we also don't resolve
+ * array and primitive refs, like @Z[]::class.
+ */
+ // GWTProblem.recordInCud(ProblemSeverities.Warning, meth, cud,
+ // "Referencing class '" + jsniRef.className()
+ // + ": unable to resolve class, expect subsequent failures",
+ // null);
}
}
@@ -282,6 +288,21 @@
char[][] compoundName = getCompoundName(jsniRef);
TypeBinding binding = cud.scope.getType(compoundName, compoundName.length);
+ /*
+ * TODO(scottb): we cannot currently resolve top-level types; here's some
+ * experimental code that will let us do this.
+ */
+ // ReferenceBinding binding = cud.scope.environment().askForType(
+ // compoundName);
+ // while (binding == null && compoundName.length > 1) {
+ // int newLen = compoundName.length - 1;
+ // char[][] next = new char[newLen][];
+ // System.arraycopy(compoundName, 0, next, 0, newLen - 1);
+ // next[newLen - 1] = CharOperation.concat(compoundName[newLen - 1],
+ // compoundName[newLen], '$');
+ // compoundName = next;
+ // binding = cud.scope.environment().askForType(compoundName);
+ // }
if (binding instanceof ProblemReferenceBinding) {
ProblemReferenceBinding prb = (ProblemReferenceBinding) binding;
if (prb.problemId() == ProblemReasons.NotVisible) {
diff --git a/dev/core/src/com/google/gwt/dev/shell/BrowserWidget.java b/dev/core/src/com/google/gwt/dev/shell/BrowserWidget.java
index 5a0ddcc..b1a018d 100644
--- a/dev/core/src/com/google/gwt/dev/shell/BrowserWidget.java
+++ b/dev/core/src/com/google/gwt/dev/shell/BrowserWidget.java
@@ -175,9 +175,7 @@
private static final String EXPECTED_GWT_ONLOAD_VERSION = "1.6";
public static void launchExternalBrowser(TreeLogger logger, String location) {
- // check GWT_EXTERNAL_BROWSER first, it overrides everything else
- LowLevel.init();
- String browserCmd = LowLevel.getEnv("GWT_EXTERNAL_BROWSER");
+ String browserCmd = System.getenv("GWT_EXTERNAL_BROWSER");
if (browserCmd != null) {
browserCmd += " " + location;
try {
diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
index 651239c..5cd8c0b 100644
--- a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
+++ b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
@@ -19,9 +19,15 @@
import com.google.gwt.core.ext.ServletContainerLauncher;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.TreeLogger.Type;
+import com.google.gwt.dev.util.InstalledHelpInfo;
+import org.mortbay.component.AbstractLifeCycle;
+import org.mortbay.jetty.AbstractConnector;
+import org.mortbay.jetty.Request;
+import org.mortbay.jetty.RequestLog;
+import org.mortbay.jetty.Response;
import org.mortbay.jetty.Server;
+import org.mortbay.jetty.handler.RequestLogHandler;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.webapp.WebAppClassLoader;
import org.mortbay.jetty.webapp.WebAppContext;
@@ -29,13 +35,73 @@
import org.mortbay.log.Logger;
import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
/**
- * A launcher for an embedded Jetty server.
+ * A {@link ServletContainerLauncher} for an embedded Jetty server.
*/
public class JettyLauncher extends ServletContainerLauncher {
/**
+ * Log jetty requests/responses to TreeLogger.
+ */
+ public static class JettyRequestLogger extends AbstractLifeCycle implements
+ RequestLog {
+
+ private final TreeLogger logger;
+
+ public JettyRequestLogger(TreeLogger logger) {
+ this.logger = logger;
+ }
+
+ /**
+ * Log an HTTP request/response to TreeLogger.
+ */
+ @SuppressWarnings("unchecked")
+ public void log(Request request, Response response) {
+ int status = response.getStatus();
+ if (status < 0) {
+ // Copied from NCSARequestLog
+ status = 404;
+ }
+ TreeLogger.Type logStatus, logHeaders;
+ if (status >= 500) {
+ logStatus = TreeLogger.ERROR;
+ logHeaders = TreeLogger.INFO;
+ } else if (status >= 400) {
+ logStatus = TreeLogger.WARN;
+ logHeaders = TreeLogger.INFO;
+ } else {
+ logStatus = TreeLogger.INFO;
+ logHeaders = TreeLogger.DEBUG;
+ }
+ String userString = request.getRemoteUser();
+ if (userString == null) {
+ userString = "";
+ } else {
+ userString += "@";
+ }
+ String bytesString = "";
+ if (response.getContentCount() > 0) {
+ bytesString = " " + response.getContentCount() + " bytes";
+ }
+ TreeLogger branch = logger.branch(logStatus, String.valueOf(status)
+ + " - " + request.getMethod() + ' ' + request.getUri() + " ("
+ + userString + request.getRemoteHost() + ')' + bytesString);
+ TreeLogger headers = branch.branch(logHeaders, "Request headers");
+ Enumeration<String> headerNames = request.getHeaderNames();
+ while (headerNames.hasMoreElements()) {
+ String hdr = headerNames.nextElement();
+ String hdrVal = request.getHeader(hdr);
+ headers.log(logHeaders, hdr + ": " + hdrVal);
+ }
+ // TODO(jat): add response headers
+ }
+ }
+
+ /**
* An adapter for the Jetty logging system to GWT's TreeLogger. This
* implementation class is only public to allow {@link Log} to instantiate it.
*
@@ -43,57 +109,26 @@
* {@link Log}'s static initializer to prevent the initial log message from
* going to stderr.
*/
- public static final class JettyTreeLogger implements Logger {
- private static Type nextBranchLevel;
- private static TreeLogger nextLogger;
-
- /**
- * Returns true if the default constructor can be called.
- */
- public static boolean isDefaultConstructionReady() {
- return nextLogger != null;
- }
-
- /**
- * Call to set initial state for default construction; must be called again
- * each time before a default instantiation occurs.
- */
- public static void setDefaultConstruction(TreeLogger logger,
- Type branchLevel) {
- if (logger == null || branchLevel == null) {
- throw new NullPointerException();
- }
- nextLogger = logger;
- nextBranchLevel = branchLevel;
- }
-
- private final Type branchLevel;
+ public static class JettyTreeLogger implements Logger {
private final TreeLogger logger;
- public JettyTreeLogger() {
- this(nextLogger, nextBranchLevel);
- nextLogger = null;
- nextBranchLevel = null;
- }
-
- public JettyTreeLogger(TreeLogger logger, Type branchLevel) {
- if (logger == null || branchLevel == null) {
+ public JettyTreeLogger(TreeLogger logger) {
+ if (logger == null) {
throw new NullPointerException();
}
- this.branchLevel = branchLevel;
this.logger = logger;
}
public void debug(String msg, Object arg0, Object arg1) {
- logger.log(TreeLogger.DEBUG, format(msg, arg0, arg1));
+ logger.log(TreeLogger.SPAM, format(msg, arg0, arg1));
}
public void debug(String msg, Throwable th) {
- logger.log(TreeLogger.DEBUG, msg, th);
+ logger.log(TreeLogger.SPAM, msg, th);
}
public Logger getLogger(String name) {
- return new JettyTreeLogger(logger.branch(branchLevel, name), branchLevel);
+ return this;
}
public void info(String msg, Object arg0, Object arg1) {
@@ -101,7 +136,7 @@
}
public boolean isDebugEnabled() {
- return logger.isLoggable(TreeLogger.DEBUG);
+ return logger.isLoggable(TreeLogger.SPAM);
}
public void setDebugEnabled(boolean enabled) {
@@ -133,8 +168,10 @@
}
}
- private static class JettyServletContainer extends ServletContainer {
-
+ /**
+ * The resulting {@link ServletContainer} this is launched.
+ */
+ protected static class JettyServletContainer extends ServletContainer {
private final int actualPort;
private final File appRootDir;
private final TreeLogger logger;
@@ -199,74 +236,197 @@
* Also provides special class filtering to isolate the web app from the GWT
* hosting environment.
*/
- private final class WebAppContextWithReload extends WebAppContext {
+ protected final class WebAppContextWithReload extends WebAppContext {
+
/**
- * Ensures that only Jetty and other server classes can be loaded into the
- * {@link WebAppClassLoader}. This forces the user to put any necessary
- * dependencies into WEB-INF/lib.
+ * Specialized {@link WebAppClassLoader} that allows outside resources to be
+ * brought in dynamically from the system path. A warning is issued when
+ * this occurs.
*/
- private final ClassLoader parentClassLoader = new ClassLoader(null) {
- private final ClassLoader delegateTo = Thread.currentThread().getContextClassLoader();
+ private class WebAppClassLoaderExtension extends WebAppClassLoader {
+
+ public WebAppClassLoaderExtension() throws IOException {
+ super(bootStrapOnlyClassLoader, WebAppContextWithReload.this);
+ }
+
+ @Override
+ public URL findResource(String name) {
+ // Always check this ClassLoader first.
+ URL found = super.findResource(name);
+ if (found != null) {
+ return found;
+ }
+
+ // See if the outside world has it.
+ found = systemClassLoader.getResource(name);
+ if (found == null) {
+ return null;
+ }
+
+ // Specifically for META-INF/services/javax.xml.parsers.SAXParserFactory
+ String checkName = name;
+ if (checkName.startsWith("META-INF/services/")) {
+ checkName = checkName.substring("META-INF/services/".length());
+ }
+
+ // For system/server path, just return it quietly.
+ if (isServerPath(checkName) || isSystemPath(checkName)) {
+ return found;
+ }
+
+ // Warn, add containing URL to our own ClassLoader, and retry the call.
+ String warnMessage = "Server resource '"
+ + name
+ + "' could not be found in the web app, but was found on the system classpath";
+ if (!addContainingClassPathEntry(warnMessage, found, name)) {
+ return null;
+ }
+ return super.findResource(name);
+ }
+
+ /**
+ * Override to additionally consider the most commonly available JSP and
+ * XML implementation as system resources. (In fact, Jasper is in gwt-dev
+ * via embedded Tomcat, so we always hit this case.)
+ */
+ @Override
+ public boolean isSystemPath(String name) {
+ name = name.replace('/', '.');
+ return super.isSystemPath(name)
+ || name.startsWith("org.apache.jasper.")
+ || name.startsWith("org.apache.xerces.");
+ }
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
- if (webAppClassLoader != null
- && (webAppClassLoader.isServerPath(name) || webAppClassLoader.isSystemPath(name))) {
- return delegateTo.loadClass(name);
+ try {
+ return super.findClass(name);
+ } catch (ClassNotFoundException e) {
}
- throw new ClassNotFoundException();
+
+ // For system/server path, just try the outside world quietly.
+ if (isServerPath(name) || isSystemPath(name)) {
+ return systemClassLoader.loadClass(name);
+ }
+
+ // See if the outside world has a URL for it.
+ String resourceName = name.replace('.', '/') + ".class";
+ URL found = systemClassLoader.getResource(resourceName);
+ if (found == null) {
+ return null;
+ }
+
+ // Warn, add containing URL to our own ClassLoader, and retry the call.
+ String warnMessage = "Server class '"
+ + name
+ + "' could not be found in the web app, but was found on the system classpath";
+ if (!addContainingClassPathEntry(warnMessage, found, resourceName)) {
+ throw new ClassNotFoundException(name);
+ }
+ return super.findClass(name);
}
+ private boolean addContainingClassPathEntry(String warnMessage,
+ URL resource, String resourceName) {
+ TreeLogger.Type logLevel = (System.getProperty(PROPERTY_NOWARN_WEBAPP_CLASSPATH) == null)
+ ? TreeLogger.WARN : TreeLogger.DEBUG;
+ TreeLogger branch = logger.branch(logLevel, warnMessage);
+ String classPathURL;
+ String foundStr = resource.toExternalForm();
+ if (resource.getProtocol().equals("file")) {
+ assert foundStr.endsWith(resourceName);
+ classPathURL = foundStr.substring(0, foundStr.length()
+ - resourceName.length());
+ } else if (resource.getProtocol().equals("jar")) {
+ assert foundStr.startsWith("jar:");
+ assert foundStr.endsWith("!/" + resourceName);
+ classPathURL = foundStr.substring(4, foundStr.length()
+ - (2 + resourceName.length()));
+ } else {
+ branch.log(TreeLogger.ERROR,
+ "Found resouce but unrecognized URL format: '" + foundStr + '\'');
+ return false;
+ }
+ branch = branch.branch(logLevel, "Adding classpath entry '"
+ + classPathURL + "' to the web app classpath for this session",
+ null, new InstalledHelpInfo("webAppClassPath.html"));
+ try {
+ addClassPath(classPathURL);
+ return true;
+ } catch (IOException e) {
+ branch.log(TreeLogger.ERROR, "Failed add container URL: '"
+ + classPathURL + '\'', e);
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Parent ClassLoader for the Jetty web app, which can only load JVM
+ * classes. We would just use <code>null</code> for the parent ClassLoader
+ * except this makes Jetty unhappy.
+ */
+ private final ClassLoader bootStrapOnlyClassLoader = new ClassLoader(null) {
};
- private WebAppClassLoader webAppClassLoader;
+ private final TreeLogger logger;
+
+ /**
+ * In the usual case of launching {@link com.google.gwt.dev.HostedMode},
+ * this will always by the system app ClassLoader.
+ */
+ private final ClassLoader systemClassLoader = Thread.currentThread().getContextClassLoader();
@SuppressWarnings("unchecked")
- private WebAppContextWithReload(String webApp, String contextPath) {
+ private WebAppContextWithReload(TreeLogger logger, String webApp,
+ String contextPath) {
super(webApp, contextPath);
+ this.logger = logger;
+
// Prevent file locking on Windows; pick up file changes.
getInitParams().put(
"org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false");
+
+ // Since the parent class loader is bootstrap-only, prefer it first.
+ setParentLoaderPriority(true);
}
@Override
protected void doStart() throws Exception {
- webAppClassLoader = new WebAppClassLoader(parentClassLoader, this);
- setClassLoader(webAppClassLoader);
+ setClassLoader(new WebAppClassLoaderExtension());
super.doStart();
}
@Override
protected void doStop() throws Exception {
super.doStop();
- webAppClassLoader = null;
setClassLoader(null);
}
}
+ /**
+ * System property to suppress warnings about loading web app classes from the
+ * system classpath.
+ */
+ private static final String PROPERTY_NOWARN_WEBAPP_CLASSPATH = "gwt.nowarn.webapp.classpath";
+
+ static {
+ // Suppress spammy Jetty log initialization.
+ System.setProperty("org.mortbay.log.class", JettyNullLogger.class.getName());
+ Log.getLog();
+ }
+
public ServletContainer start(TreeLogger logger, int port, File appRootDir)
throws Exception {
checkStartParams(logger, port, appRootDir);
- // The dance we do with Jetty's logging system -- disabled, log to console.
- if (false) {
- System.setProperty("VERBOSE", "true");
- JettyTreeLogger.setDefaultConstruction(logger, TreeLogger.INFO);
- System.setProperty("org.mortbay.log.class",
- JettyTreeLogger.class.getName());
- // Force initialization.
- Log.isDebugEnabled();
- if (JettyTreeLogger.isDefaultConstructionReady()) {
- // The log system was already initialized and did not use our
- // newly-constructed logger, set it explicitly now.
- Log.setLog(new JettyTreeLogger());
- }
- }
+ // Setup our own logger.
+ Log.setLog(new JettyTreeLogger(logger));
// Turn off XML validation.
System.setProperty("org.mortbay.xml.XmlParser.Validating", "false");
- SelectChannelConnector connector = new SelectChannelConnector();
+ AbstractConnector connector = getConnector();
connector.setPort(port);
// Don't share ports with an existing process.
@@ -279,10 +439,13 @@
server.addConnector(connector);
// Create a new web app in the war directory.
- WebAppContext wac = new WebAppContextWithReload(
+ WebAppContext wac = new WebAppContextWithReload(logger,
appRootDir.getAbsolutePath(), "/");
- server.setHandler(wac);
+ RequestLogHandler logHandler = new RequestLogHandler();
+ logHandler.setRequestLog(new JettyRequestLogger(logger));
+ logHandler.setHandler(wac);
+ server.setHandler(logHandler);
server.start();
server.setStopAtShutdown(true);
@@ -290,6 +453,10 @@
connector.getLocalPort(), appRootDir);
}
+ protected AbstractConnector getConnector() {
+ return new SelectChannelConnector();
+ }
+
private void checkStartParams(TreeLogger logger, int port, File appRootDir) {
if (logger == null) {
throw new NullPointerException("logger cannot be null");
diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyNullLogger.java b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyNullLogger.java
new file mode 100644
index 0000000..81418ad
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyNullLogger.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell.jetty;
+
+import org.mortbay.log.Logger;
+
+/**
+ * A Jetty {@link Logger} that suppresses all output.
+ */
+public class JettyNullLogger implements Logger {
+
+ public void debug(String msg, Throwable th) {
+ }
+
+ public void debug(String msg, Object arg0, Object arg1) {
+ }
+
+ public Logger getLogger(String name) {
+ return this;
+ }
+
+ public void info(String msg, Object arg0, Object arg1) {
+ }
+
+ public boolean isDebugEnabled() {
+ return false;
+ }
+
+ public void setDebugEnabled(boolean enabled) {
+ }
+
+ public void warn(String msg, Throwable th) {
+ }
+
+ public void warn(String msg, Object arg0, Object arg1) {
+ }
+}
diff --git a/dev/core/src/com/google/gwt/util/tools/ToolBase.java b/dev/core/src/com/google/gwt/util/tools/ToolBase.java
index b965bd3..5e0cc0b 100644
--- a/dev/core/src/com/google/gwt/util/tools/ToolBase.java
+++ b/dev/core/src/com/google/gwt/util/tools/ToolBase.java
@@ -48,6 +48,8 @@
*/
public abstract class ToolBase {
+ private static final String PROPERTY_NOWARN_LEGACY_TOOLS = "gwt.nowarn.legacy.tools";
+
static {
String installPath = Utility.getInstallPath();
try {
@@ -59,6 +61,16 @@
System.setProperty("swt.library.path", installPath + '/');
}
+ public static void legacyWarn(Class<?> legacy, Class<?> replacement) {
+ if (System.getProperty(PROPERTY_NOWARN_LEGACY_TOOLS) == null) {
+ System.err.println("WARNING: '" + legacy.getName()
+ + "' is deprecated and will be removed in a future release.");
+ System.err.println("Use '" + replacement.getName() + "' instead.");
+ System.err.println("(To disable this warning, pass -D"
+ + PROPERTY_NOWARN_LEGACY_TOOLS + " as a JVM arg.)");
+ }
+ }
+
/**
* Use a linked hash map to preserve the declaration order.
*/
diff --git a/distro-source/core/src/doc/helpInfo/webAppClassPath.html b/distro-source/core/src/doc/helpInfo/webAppClassPath.html
new file mode 100644
index 0000000..8932f64
--- /dev/null
+++ b/distro-source/core/src/doc/helpInfo/webAppClassPath.html
@@ -0,0 +1,39 @@
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>Web App Classpath Problem</title>
+</head>
+<body>
+
+<h1>Web App Classpath Problem</h1>
+
+<p>You were directed to this help topic because your server code needed a class or
+resource that was not found on the <i>web app classpath</i>, but <b>was</b> found
+on the <i>system classpath</i>. The <i>system classpath</i> is the classpath
+you specify when launching the Java VM to run hosted mode. The <i>web app
+classpath</i> is different — it consists of classes that live in your web
+application's <i>war directory</i>. All server classes and dependencies should
+to be placed in your war directory: libraries (jars) should be placed in
+<nobr><code>war/WEB-INF/lib/</code></nobr> and classes that don't live in
+jars should be placed in <nobr><code>war/WEB-INF/classes/</code></nobr>.
+
+<p>GWT hosted mode helpfully works around this problem by mapping these outside
+resources into your web app classpath. This warning reminds you that failing to
+address the issue can lead to problems when you actually deploy your web app to
+a real server.</p>
+
+<h2>Tips</h2>
+
+<ul>
+<li>The most common reason to encounter this problem with a new project is
+using RPC, which tries to load
+<nobr><code>com.google.gwt.user.client.rpc.RemoteService</code></nobr>. The
+solution to is copy <code>gwt-servlet.jar</code> from the GWT install directory
+into your web app's <nobr><code>war/WEB-INF/lib/</code></nobr> directory.</li>
+<li>If you have a good reason for not following the recommended configuration,
+you can suppress warning by setting the Java system property
+<nobr><code>gwt.nowarn.webapp.classpath</code></nobr>. Specify
+<nobr><code>-Dgwt.nowarn.webapp.classpath</code></nobr> as a JVM argument when
+launching hosted mode.
+</li>
+</ul>
diff --git a/distro-source/linux/build.xml b/distro-source/linux/build.xml
index 5fde893..201c2dd 100755
--- a/distro-source/linux/build.xml
+++ b/distro-source/linux/build.xml
@@ -12,7 +12,7 @@
<tarfileset file="${gwt.build.lib}/gwt-dev-oophm.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-user.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-servlet.jar" prefix="${project.distname}" />
- <tarfileset file="${gwt.build.lib}/gwt-benchmark-viewer.jar" prefix="${project.distname}" />
+ <tarfileset file="${gwt.build.lib}/gwt-benchmark-viewer.war" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-soyc-vis.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-api-checker.jar" prefix="${project.distname}" />
diff --git a/distro-source/linux/src/benchmarkViewer b/distro-source/linux/src/benchmarkViewer
index 7b308d7..d7759b4 100755
--- a/distro-source/linux/src/benchmarkViewer
+++ b/distro-source/linux/src/benchmarkViewer
@@ -1,3 +1,3 @@
#!/bin/sh
APPDIR=`dirname $0`;
-java -Dcom.google.gwt.junit.reportPath="$1" -cp "$APPDIR/gwt-user.jar:$APPDIR/gwt-dev-linux.jar:$APPDIR/gwt-benchmark-viewer.jar" com.google.gwt.dev.GWTShell -port auto com.google.gwt.benchmarks.viewer.ReportViewer/ReportViewer.html?gwt.hybrid;
+java -Dcom.google.gwt.junit.reportPath="$1" -cp "$APPDIR/gwt-dev-linux.jar" com.google.gwt.dev.RunWebApp -port auto $APPDIR/gwt-benchmark-viewer.war;
diff --git a/distro-source/mac/build.xml b/distro-source/mac/build.xml
index 4114eb6..8737abc 100755
--- a/distro-source/mac/build.xml
+++ b/distro-source/mac/build.xml
@@ -12,7 +12,7 @@
<tarfileset file="${gwt.build.lib}/gwt-dev-oophm.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-user.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-servlet.jar" prefix="${project.distname}" />
- <tarfileset file="${gwt.build.lib}/gwt-benchmark-viewer.jar" prefix="${project.distname}" />
+ <tarfileset file="${gwt.build.lib}/gwt-benchmark-viewer.war" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-soyc-vis.jar" prefix="${project.distname}" />
<tarfileset file="${gwt.build.lib}/gwt-api-checker.jar" prefix="${project.distname}" />
diff --git a/distro-source/mac/src/benchmarkViewer b/distro-source/mac/src/benchmarkViewer
index acf4b22..097bd1c 100755
--- a/distro-source/mac/src/benchmarkViewer
+++ b/distro-source/mac/src/benchmarkViewer
@@ -1,3 +1,3 @@
#!/bin/sh
APPDIR=`dirname $0`;
-java -Dcom.google.gwt.junit.reportPath="$1" -XstartOnFirstThread -cp "$APPDIR/gwt-user.jar:$APPDIR/gwt-dev-mac.jar:$APPDIR/gwt-benchmark-viewer.jar" com.google.gwt.dev.GWTShell -port auto com.google.gwt.benchmarks.viewer.ReportViewer/ReportViewer.html?gwt.hybrid;
+java -Dcom.google.gwt.junit.reportPath="$1" -XstartOnFirstThread -cp "$APPDIR/gwt-dev-mac.jar" com.google.gwt.dev.RunWebApp -port auto $APPDIR/gwt-benchmark-viewer.war;
diff --git a/distro-source/windows/build.xml b/distro-source/windows/build.xml
index 6110f07..0b858a6 100755
--- a/distro-source/windows/build.xml
+++ b/distro-source/windows/build.xml
@@ -12,7 +12,7 @@
<zipfileset file="${gwt.build.lib}/gwt-dev-oophm.jar" prefix="${project.distname}" />
<zipfileset file="${gwt.build.lib}/gwt-user.jar" prefix="${project.distname}" />
<zipfileset file="${gwt.build.lib}/gwt-servlet.jar" prefix="${project.distname}" />
- <zipfileset file="${gwt.build.lib}/gwt-benchmark-viewer.jar" prefix="${project.distname}" />
+ <zipfileset file="${gwt.build.lib}/gwt-benchmark-viewer.war" prefix="${project.distname}" />
<zipfileset file="${gwt.build.lib}/gwt-soyc-vis.jar" prefix="${project.distname}" />
<zipfileset file="${gwt.build.lib}/gwt-api-checker.jar" prefix="${project.distname}" />
diff --git a/distro-source/windows/src/benchmarkViewer.cmd b/distro-source/windows/src/benchmarkViewer.cmd
index bddc9d9..7bf3ee2 100755
--- a/distro-source/windows/src/benchmarkViewer.cmd
+++ b/distro-source/windows/src/benchmarkViewer.cmd
@@ -1 +1 @@
-@java -Dcom.google.gwt.junit.reportPath="%1" -cp "%~dp0/gwt-user.jar;%~dp0/gwt-dev-windows.jar;%~dp0/gwt-benchmark-viewer.jar" com.google.gwt.dev.GWTShell -port auto com.google.gwt.benchmarks.viewer.ReportViewer/ReportViewer.html?gwt.hybrid;
+@java -Dcom.google.gwt.junit.reportPath="%1" -cp "%~dp0/gwt-dev-windows.jar" com.google.gwt.dev.RunWebApp -port auto %~dp0/gwt-benchmark-viewer.war
\ No newline at end of file
diff --git a/doc/build.xml b/doc/build.xml
index 5bcc340..eaa0334 100644
--- a/doc/build.xml
+++ b/doc/build.xml
@@ -10,7 +10,7 @@
<property.ensure name="gwt.dev.jar" location="${gwt.build.lib}/gwt-dev-linux.jar" />
<property name="USER_PKGS"
- value="com.google.gwt.animation.client;com.google.gwt.benchmarks.client;com.google.gwt.core.client;com.google.gwt.core.ext;com.google.gwt.core.ext.soyc;com.google.gwt.core.ext.linker;com.google.gwt.core.ext.typeinfo;com.google.gwt.debug.client;com.google.gwt.dom.client;com.google.gwt.event.dom.client;com.google.gwt.event.logical.shared;com.google.gwt.event.shared;com.google.gwt.http.client;com.google.gwt.i18n.client;com.google.gwt.i18n.rebind.format;com.google.gwt.i18n.rebind.keygen;com.google.gwt.json.client;com.google.gwt.junit.client;com.google.gwt.benchmarks.client;com.google.gwt.user.client;com.google.gwt.user.client.rpc;com.google.gwt.user.client.ui;com.google.gwt.user.server.rpc;com.google.gwt.xml.client;com.google.gwt.user.datepicker.client"/>
+ value="com.google.gwt.animation.client;com.google.gwt.benchmarks.client;com.google.gwt.core.client;com.google.gwt.core.ext;com.google.gwt.core.ext.soyc;com.google.gwt.core.ext.linker;com.google.gwt.core.ext.typeinfo;com.google.gwt.debug.client;com.google.gwt.dom.client;com.google.gwt.event.dom.client;com.google.gwt.event.logical.shared;com.google.gwt.event.shared;com.google.gwt.http.client;com.google.gwt.i18n.client;com.google.gwt.i18n.rebind.format;com.google.gwt.i18n.rebind.keygen;com.google.gwt.json.client;com.google.gwt.junit.client;com.google.gwt.benchmarks.client;com.google.gwt.user.client;com.google.gwt.user.client.rpc;com.google.gwt.user.client.ui;com.google.gwt.user.datepicker.client;com.google.gwt.user.server.rpc;com.google.gwt.xml.client"/>
<property name="LANG_PKGS" value="java.lang;java.lang.annotation;java.util;java.io;java.sql" />
<!-- Individual classes to include when we don't want to
diff --git a/eclipse/tools/benchmark-viewer/.checkstyle b/eclipse/tools/benchmark-viewer/.checkstyle
new file mode 100644
index 0000000..1e5b59a
--- /dev/null
+++ b/eclipse/tools/benchmark-viewer/.checkstyle
@@ -0,0 +1,7 @@
+<?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/tools/benchmark-viewer/.project b/eclipse/tools/benchmark-viewer/.project
index 5e12fb6..65867f4 100644
--- a/eclipse/tools/benchmark-viewer/.project
+++ b/eclipse/tools/benchmark-viewer/.project
@@ -1,24 +1,30 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>benchmark-viewer</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
- <linkedResources>
- <link>
- <name>src</name>
- <type>2</type>
- <locationURI>GWT_ROOT/tools/benchmark-viewer/src</locationURI>
- </link>
- </linkedResources>
-</projectDescription>
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>benchmark-viewer</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/tools/benchmark-viewer</locationURI>
+ </link>
+ </linkedResources>
+</projectDescription>
diff --git a/tools/api-checker/config/gwt15_16userApi.conf b/tools/api-checker/config/gwt15_16userApi.conf
index 1df4179c..9a9e28d 100644
--- a/tools/api-checker/config/gwt15_16userApi.conf
+++ b/tools/api-checker/config/gwt15_16userApi.conf
@@ -106,3 +106,7 @@
com.google.gwt.i18n.client.LocaleInfo::getLocaleName() FINAL_ADDED
com.google.gwt.i18n.client.LocaleInfo::isRTL() FINAL_ADDED
+# The following 2 nested classes should never have been public to begin with.
+com.google.gwt.user.client.ui.UIObject.DebugIdImpl MISSING
+com.google.gwt.user.client.ui.UIObject.DebugIdImplEnabled MISSING
+
diff --git a/tools/benchmark-viewer/build.xml b/tools/benchmark-viewer/build.xml
index 398350f..d9d4481 100755
--- a/tools/benchmark-viewer/build.xml
+++ b/tools/benchmark-viewer/build.xml
@@ -1,80 +1,84 @@
<project name="benchmark-viewer" default="build" basedir=".">
- <!--
- TODO(tobyr)
+ <!--
+ TODO(tobyr)
- Once we have more than a single tool, this build should be re-examined
- to see if several of the targets should be lifted into common.ant.xml.
- The simple targets, like tests*, clean, and checkstyle are good
- candidates, while the other targets depend heavily on the actual
- makeup of the future tools.
- -->
+ Once we have more than a single tool, this build should be re-examined
+ to see if several of the targets should be lifted into common.ant.xml.
+ The simple targets, like tests*, clean, and checkstyle are good
+ candidates, while the other targets depend heavily on the actual
+ makeup of the future tools.
+ -->
- <property name="gwt.root" location="../.." />
+ <property name="gwt.root" location="../.." />
<property name="project.tail" value="tools/benchmark-viewer" />
<import file="${gwt.root}/common.ant.xml" />
- <property name="tools.build" value="${gwt.build.out}/${project.tail}" />
- <property name="tools.module" value="com.google.gwt.benchmarks.viewer.ReportViewer" />
- <property name="tools.module.path" value="com/google/gwt/benchmarks/viewer/public" />
-
- <!--
- Default hosted mode test cases
- -->
- <fileset id="default.hosted.tests" dir="${javac.junit.out}">
- <include name="**/*Test.class" />
- </fileset>
-
- <!--
- Default web mode test cases
- -->
- <fileset id="default.web.tests" dir="${javac.junit.out}">
- <include name="**/*Test.class" />
- </fileset>
-
- <!-- Platform shouldn't matter here, just picking one -->
+ <!-- Platform shouldn't matter here, just picking one -->
<property.ensure name="gwt.dev.jar" location="${gwt.build.lib}/gwt-dev-linux.jar" />
<property.ensure name="gwt.user.jar" location="${gwt.build.lib}/gwt-user.jar" />
+ <property.ensure name="gwt.servlet.jar" location="${gwt.build.lib}/gwt-servlet.jar" />
- <target name="compile" description="Compile all class files">
- <mkdir dir="${javac.out}" />
- <gwt.javac>
- <classpath>
- <pathelement location="${gwt.tools.lib}/tomcat/servlet-api-2.4.jar" />
- <pathelement location="${gwt.tools.lib}/junit/junit-3.8.1.jar" />
- <pathelement location="${gwt.tools.lib}/jfreechart/jfreechart-1.0.3.jar" />
- <pathelement location="${gwt.tools.lib}/jfreechart/jcommon-1.0.6.jar" />
- <pathelement location="${gwt.dev.jar}" />
- <pathelement location="${gwt.user.jar}" />
- </classpath>
- </gwt.javac>
+ <property name="war" location="${project.build}/war" />
+
+ <path id="project.class.path">
+ <pathelement location="war/WEB-INF/classes"/>
+ <pathelement location="${gwt.user.jar}"/>
+ <pathelement location="${gwt.dev.jar}"/>
+ <fileset dir="${war}/WEB-INF/lib" includes="**/*.jar"/>
+ </path>
+
+ <target name="wardir" description="Create the target war directory">
+ <copy todir="${war}">
+ <fileset dir="war" excludes="WEB-INF/classes/marker" />
+ </copy>
+ <mkdir dir="${war}/WEB-INF/lib" />
+ <copy todir="${war}/WEB-INF/lib" file="${gwt.servlet.jar}" />
+ <copy todir="${war}/WEB-INF/lib" file="${gwt.tools.lib}/jfreechart/jfreechart-1.0.3.jar" />
+ <copy todir="${war}/WEB-INF/lib" file="${gwt.tools.lib}/jfreechart/jcommon-1.0.6.jar" />
</target>
- <target name="compile.tests" description="Compiles the test code for this project">
- <mkdir dir="${javac.junit.out}" />
- <gwt.javac srcdir="test" destdir="${javac.junit.out}">
- <classpath>
- <pathelement location="${javac.out}" />
- <pathelement location="${gwt.tools.lib}/junit/junit-3.8.1.jar" />
- <pathelement location="${gwt.dev.staging.jar}" />
- </classpath>
+ <target name="javac" depends="wardir" description="Compile java source">
+ <mkdir dir="${war}/WEB-INF/classes"/>
+ <gwt.javac destdir="${war}/WEB-INF/classes">
+ <classpath refid="project.class.path"/>
</gwt.javac>
+ <copy todir="${war}/WEB-INF/classes">
+ <fileset dir="src" excludes="**/*.java"/>
+ </copy>
</target>
- <target name="build" depends="compile, gwtc" description="Build and package this project">
- <mkdir dir="${gwt.build.lib}" />
- <copy todir="${tools.build}/www-new/${tools.module.path}" flatten="true" >
- <fileset dir="${tools.build}/www/${tools.module}" />
- </copy>
-
- <gwt.jar>
- <fileset dir="src" excludes="**/package.html" />
- <fileset dir="${javac.out}" />
- <fileset dir="${tools.build}/www-new" />
- <zipfileset src="${gwt.tools.lib}/jfreechart/itext-1.4.6.jar"/>
- <zipfileset src="${gwt.tools.lib}/jfreechart/jcommon-1.0.6.jar"/>
- <zipfileset src="${gwt.tools.lib}/jfreechart/jfreechart-1.0.3.jar"/>
- </gwt.jar>
+ <target name="gwtc" depends="javac" description="GWT compile to JavaScript">
+ <outofdate>
+ <sourcefiles>
+ <fileset dir="src"/>
+ <path refid="project.class.path"/>
+ </sourcefiles>
+ <targetfiles path="${war}/reportViewer/reportViewer.nocache.js" />
+ <sequential>
+ <java failonerror="true" fork="true" classname="com.google.gwt.dev.Compiler">
+ <classpath>
+ <pathelement location="src"/>
+ <path refid="project.class.path"/>
+ </classpath>
+ <jvmarg value="-Xmx256M"/>
+ <arg value="-war"/>
+ <arg value="${war}"/>
+ <arg value="com.google.gwt.benchmarks.viewer.ReportViewer"/>
+ </java>
+ </sequential>
+ </outofdate>
+ </target>
+
+ <target name="war" depends="gwtc" description="Create a war file">
+ <zip destfile="${gwt.build.lib}/gwt-benchmark-viewer.war" basedir="${war}"/>
+ </target>
+
+ <target name="build" depends="war" description="Build this project" />
+
+ <target name="clean" description="Cleans this project">
+ <delete dir="${war}" failonerror="false" />
+ <delete file="${gwt.build.lib}/gwt-benchmark-viewer.war" failonerror="false" />
</target>
<target name="checkstyle" description="Static analysis of source">
@@ -83,55 +87,5 @@
</gwt.checkstyle>
</target>
- <target name="gwtc" description="Compile to JavaScript">
- <mkdir dir="${tools.build}/www" />
- <outofdate>
- <sourcefiles>
- <fileset dir="src" />
- <fileset file="${gwt.user.jar}" />
- <fileset file="${gwt.dev.jar}" />
- </sourcefiles>
- <targetfiles>
- <fileset dir="${tools.build}/www" />
- </targetfiles>
- <sequential>
- <java dir="${tools.build}" classname="com.google.gwt.dev.GWTCompiler" classpath="src:${gwt.user.jar}:${gwt.dev.jar}" fork="yes" failonerror="true">
- <jvmarg value="-Xmx256M"/>
- <arg value="-out" />
- <arg file="${tools.build}/www" />
- <arg value="${tools.module}" />
- </java>
- </sequential>
- </outofdate>
- </target>
-
- <target name="remoteweb-test" description="Run a remoteweb test at the given host and path">
- <echo message="Performing remote browser testing at rmi://${gwt.remote.browser}" />
- <gwt.junit test.args="-out www -web -remoteweb rmi://${gwt.remote.browser}" test.out="${junit.out}/${gwt.remote.browser}" test.cases="default.web.tests" />
- </target>
-
- <target name="test" depends="compile, compile.tests" description="Run hosted-mode, web-mode and remoteweb tests for this project.">
- <property.ensure name="distro.built" location="${gwt.dev.staging.jar}" message="GWT must be built before performing any tests. This can be fixed by running ant in the ${gwt.root} directory." />
-
- <!--
- Run hosted and web mode tests for the platform on which this build
- is executing
- -->
- <parallel threadcount="1">
- <gwt.junit test.out="${junit.out}/${build.host.platform}-hosted-mode" test.cases="default.hosted.tests" />
-
- <gwt.junit test.args="-out www -web" test.out="${junit.out}/${build.host.platform}-web-mode" test.cases="default.web.tests" />
-
- <!--
- Run remote browser testing for the comma delimited list of remote browsers
- -->
- <foreach list="${gwt.remote.browsers}" delimiter="," parallel="true" maxThreads="1" target="remoteweb-test" param="gwt.remote.browser" />
- </parallel>
- </target>
-
- <target name="clean" description="Cleans this project's intermediate and output files">
- <delete dir="${project.build}" />
- <delete file="${project.lib}" />
- </target>
+ <target name="test" depends="build" />
</project>
-
diff --git a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/ReportViewer.gwt.xml b/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/ReportViewer.gwt.xml
index 96ab3a2..0dd5d3e 100644
--- a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/ReportViewer.gwt.xml
+++ b/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/ReportViewer.gwt.xml
@@ -14,7 +14,7 @@
<!-- Deferred binding rules for browser selection. -->
<!-- -->
-<module>
+<module rename-to="reportViewer">
<inherits name="com.google.gwt.user.User"/>
<inherits name="com.google.gwt.http.HTTP"/>
@@ -23,7 +23,5 @@
<entry-point class="com.google.gwt.benchmarks.viewer.client.ReportViewer"/>
<servlet path='/test_reports' class='com.google.gwt.benchmarks.viewer.server.ReportServerImpl'/>
- <servlet path='/test_images' class='com.google.gwt.benchmarks.viewer.server.ReportImageServer'/>
-
- <stylesheet src="ReportViewer.css"/>
+ <servlet path='/test_images/*' class='com.google.gwt.benchmarks.viewer.server.ReportImageServer'/>
</module>
diff --git a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/client/ReportServer.java b/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/client/ReportServer.java
index 74f554b..07810ed 100644
--- a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/client/ReportServer.java
+++ b/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/client/ReportServer.java
@@ -16,6 +16,7 @@
package com.google.gwt.benchmarks.viewer.client;
import com.google.gwt.user.client.rpc.RemoteService;
+import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import java.util.List;
@@ -26,6 +27,7 @@
* @see com.google.gwt.junit.viewer.server.ReportServerImpl
* @see ReportViewer
*/
+@RemoteServiceRelativePath("test_reports")
public interface ReportServer extends RemoteService {
/**
@@ -34,12 +36,12 @@
* @param reportId The id of the report. Originates from the ReportSummary.
* @return the matching Report, or null if the Report could not be found.
*/
- public Report getReport(String reportId);
+ Report getReport(String reportId);
/**
* Returns a list of summaries of all the Benchmark reports.
*
* @return a non-null list of ReportSummary
*/
- public List<ReportSummary> getReportSummaries();
+ List<ReportSummary> getReportSummaries();
}
diff --git a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/client/ReportServerAsync.java b/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/client/ReportServerAsync.java
index 03d7bac..d128334 100644
--- a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/client/ReportServerAsync.java
+++ b/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/client/ReportServerAsync.java
@@ -26,7 +26,7 @@
*/
public interface ReportServerAsync {
- public void getReport(String reportId, AsyncCallback<Report> callback);
+ void getReport(String reportId, AsyncCallback<Report> callback);
- public void getReportSummaries(AsyncCallback<List<ReportSummary>> callback);
+ void getReportSummaries(AsyncCallback<List<ReportSummary>> callback);
}
diff --git a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/client/ReportViewer.java b/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/client/ReportViewer.java
index 3132754..d4e2bb3 100644
--- a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/client/ReportViewer.java
+++ b/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/client/ReportViewer.java
@@ -23,7 +23,6 @@
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.HistoryListener;
import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CellPanel;
import com.google.gwt.user.client.ui.ClickListener;
@@ -36,10 +35,10 @@
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.SourcesTableEvents;
+import com.google.gwt.user.client.ui.TableListener;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
-import com.google.gwt.user.client.ui.TableListener;
-import com.google.gwt.user.client.ui.SourcesTableEvents;
import java.util.ArrayList;
import java.util.Collections;
@@ -65,6 +64,7 @@
* from by setting the system property named in
* {@link com.google.gwt.benchmarks.client.Benchmark#REPORT_PATH}.
*/
+@SuppressWarnings("deprecation")
public class ReportViewer implements EntryPoint, HistoryListener {
private static class MutableBool {
@@ -79,17 +79,18 @@
private class SummariesTableListener implements TableListener {
public void onCellClicked(SourcesTableEvents sender, int row, int col) {
- ReportSummary summary = summaries.get(row - 1);
- String token = summary.getId();
- // Short circuit the history loop.
- selectReport(row, token);
- History.newItem(token);
+ if (row > 0) {
+ ReportSummary summary = summaries.get(row - 1);
+ String token = summary.getId();
+ // Short circuit the history loop.
+ selectReport(row, token);
+ History.newItem(token);
+ }
}
}
- private static final String baseUrl = GWT.getModuleBaseURL();
-
- private static final String imageServer = baseUrl + "test_images/";
+ private static final String imageServer = GWT.getModuleBaseURL()
+ + "test_images/";
HTML detailsLabel;
@@ -132,9 +133,7 @@
init();
// Asynchronously load the summaries
- ServiceDefTarget target = (ServiceDefTarget) GWT.create(ReportServer.class);
- target.setServiceEntryPoint(GWT.getModuleBaseURL() + "test_reports");
- reportServer = (ReportServerAsync) target;
+ reportServer = (ReportServerAsync) GWT.create(ReportServer.class);
reportServer.getReportSummaries(new AsyncCallback<List<ReportSummary>>() {
public void onFailure(Throwable caught) {
diff --git a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/public/ReportViewer.html b/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/public/ReportViewer.html
deleted file mode 100644
index 7842c32..0000000
--- a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/public/ReportViewer.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<html>
- <head>
- <title>ReportViewer</title>
- </head>
- <body>
- <script language="javascript" src="com.google.gwt.benchmarks.viewer.ReportViewer.nocache.js"></script>
- <iframe src="javascript:''" id='__gwt_historyFrame' style='width:0;height:0;border:0'></iframe>
- </body>
-</html>
diff --git a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/server/ReportImageServer.java b/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/server/ReportImageServer.java
index 07ca35d..3fbd66c 100644
--- a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/server/ReportImageServer.java
+++ b/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/server/ReportImageServer.java
@@ -35,7 +35,6 @@
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
-import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
@@ -96,7 +95,8 @@
try {
handleRequest(request, response);
} catch (Exception e) {
- if (e.getClass().getName().endsWith("ClientAbortException")) {
+ if (e.getClass().getName().endsWith(".ClientAbortException")
+ || e.getClass().getName().endsWith(".EofException")) {
// No big deal, the client browser terminated a download.
} else {
logException("An error occured while trying to create the chart.", e,
diff --git a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/public/ReportViewer.css b/tools/benchmark-viewer/war/ReportViewer.css
similarity index 100%
rename from tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/public/ReportViewer.css
rename to tools/benchmark-viewer/war/ReportViewer.css
diff --git a/tools/benchmark-viewer/war/ReportViewer.html b/tools/benchmark-viewer/war/ReportViewer.html
new file mode 100644
index 0000000..8c6f35a
--- /dev/null
+++ b/tools/benchmark-viewer/war/ReportViewer.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <link type="text/css" rel="stylesheet" href="ReportViewer.css">
+ <title>ReportViewer</title>
+ </head>
+ <body>
+ <script language="javascript" src="reportViewer/reportViewer.nocache.js"></script>
+ <iframe src="javascript:''" id='__gwt_historyFrame' style='width:0;height:0;border:0'></iframe>
+ </body>
+</html>
diff --git a/tools/benchmark-viewer/war/WEB-INF/classes/marker b/tools/benchmark-viewer/war/WEB-INF/classes/marker
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/benchmark-viewer/war/WEB-INF/classes/marker
diff --git a/tools/benchmark-viewer/war/WEB-INF/web.xml b/tools/benchmark-viewer/war/WEB-INF/web.xml
new file mode 100644
index 0000000..301ee6c
--- /dev/null
+++ b/tools/benchmark-viewer/war/WEB-INF/web.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app>
+
+ <!-- Default page to serve -->
+ <welcome-file-list>
+ <welcome-file>ReportViewer.html</welcome-file>
+ </welcome-file-list>
+
+ <!-- Servlets -->
+ <servlet>
+ <servlet-name>test_reports</servlet-name>
+ <servlet-class>com.google.gwt.benchmarks.viewer.server.ReportServerImpl</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>test_reports</servlet-name>
+ <url-pattern>/reportViewer/test_reports</url-pattern>
+ </servlet-mapping>
+
+ <servlet>
+ <servlet-name>test_images</servlet-name>
+ <servlet-class>com.google.gwt.benchmarks.viewer.server.ReportImageServer</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>test_images</servlet-name>
+ <url-pattern>/reportViewer/test_images/*</url-pattern>
+ </servlet-mapping>
+
+</web-app>
diff --git a/tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/public/gradient.gif b/tools/benchmark-viewer/war/gradient.gif
similarity index 100%
rename from tools/benchmark-viewer/src/com/google/gwt/benchmarks/viewer/public/gradient.gif
rename to tools/benchmark-viewer/war/gradient.gif
Binary files differ
diff --git a/user/src/com/google/gwt/debug/client/DebugInfo.java b/user/src/com/google/gwt/debug/client/DebugInfo.java
index c7405b4..94474b6 100644
--- a/user/src/com/google/gwt/debug/client/DebugInfo.java
+++ b/user/src/com/google/gwt/debug/client/DebugInfo.java
@@ -18,13 +18,15 @@
import com.google.gwt.core.client.GWT;
/**
- * This class provides a set of static methods related to Debugging.
+ * Provides low-level functionality to support the creation of testing and diagnostic frameworks.
+ *
+ * @see com.google.gwt.user.client.ui.UIObject#ensureDebugId(String)
*/
public class DebugInfo {
/**
* Implementation class for {@link DebugInfo}.
*/
- public static class DebugInfoImpl {
+ private static class DebugInfoImpl {
public boolean isDebugIdEnabled() {
return false;
}
@@ -33,7 +35,8 @@
/**
* Implementation class for {@link DebugInfo} used when debug IDs are enabled.
*/
- public static class DebugInfoImplEnabled extends DebugInfoImpl {
+ @SuppressWarnings("unused")
+ private static class DebugInfoImplEnabled extends DebugInfoImpl {
@Override
public boolean isDebugIdEnabled() {
return true;
diff --git a/user/src/com/google/gwt/debug/client/package-info.java b/user/src/com/google/gwt/debug/client/package-info.java
new file mode 100644
index 0000000..896e007
--- /dev/null
+++ b/user/src/com/google/gwt/debug/client/package-info.java
@@ -0,0 +1,49 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ * Provides low-level functionality to support the creation of testing and
+ * diagnostic frameworks.
+ *
+ * <p>
+ * To use the functionality in this package, your GWT module should inherit the
+ * module <code>com.google.gwt.debug.Debug</code>. The <code>Debug</code>
+ * module introduces the client property <code>gwt.enableDebugId</code>,
+ * which controls whether or not this debug code is enabled (and therefore
+ * included in the final compiled result). It is set to <code>true</code> by
+ * default, but a module being compiled for production would very likely want to
+ * set it to <code>false</code> to avoid unnecessary extra code in the final
+ * compiled output.
+ *
+ * <h3>Example</h3>
+ * A module using this package might look like the following:
+ *
+ * <pre>
+ * <module>
+ * <inherits name='com.google.gwt.user.User'/>
+ *
+ * <!-- Inheriting 'Debug' on the next line makes the features available. -->
+ * <inherits name='com.google.gwt.debug.Debug'/>
+ *
+ * <!-- Disable for production by uncommenting the next line -->
+ * <!-- <set-property name="gwt.enableDebugId" value="false"/> -->
+ *
+ * <entry-point class='your-entry-point-class'/>
+ * </module>
+ * </pre>
+ */
+@com.google.gwt.util.PreventSpuriousRebuilds
+package com.google.gwt.debug.client;
diff --git a/user/src/com/google/gwt/dom/client/DOMImpl.java b/user/src/com/google/gwt/dom/client/DOMImpl.java
index 738849d..dd0c07c 100644
--- a/user/src/com/google/gwt/dom/client/DOMImpl.java
+++ b/user/src/com/google/gwt/dom/client/DOMImpl.java
@@ -25,20 +25,20 @@
button.click();
}-*/;
- public native Element createElement(String tag) /*-{
- return $doc.createElement(tag);
+ public native Element createElement(Document doc, String tag) /*-{
+ return doc.createElement(tag);
}-*/;
public abstract NativeEvent createHtmlEvent(Document doc, String type, boolean canBubble,
boolean cancelable);
- public native InputElement createInputElement(String type) /*-{
- var e = $doc.createElement("INPUT");
+ public native InputElement createInputElement(Document doc, String type) /*-{
+ var e = doc.createElement("INPUT");
e.type = type;
return e;
}-*/;
- public abstract InputElement createInputRadioElement(String name);
+ public abstract InputElement createInputRadioElement(Document doc, String name);
public abstract NativeEvent createKeyEvent(Document doc, String type,
boolean canBubble, boolean cancelable, boolean ctrlKey, boolean altKey,
@@ -49,14 +49,14 @@
int screenY, int clientX, int clientY, boolean ctrlKey, boolean altKey,
boolean shiftKey, boolean metaKey, int button, Element relatedTarget);
- public ScriptElement createScriptElement(String source) {
- ScriptElement elem = (ScriptElement) createElement("script");
+ public ScriptElement createScriptElement(Document doc, String source) {
+ ScriptElement elem = (ScriptElement) createElement(doc, "script");
elem.setText(source);
return elem;
}
- public SelectElement createSelectElement(boolean multiple) {
- SelectElement select = (SelectElement) createElement("select");
+ public SelectElement createSelectElement(Document doc, boolean multiple) {
+ SelectElement select = (SelectElement) createElement(doc, "select");
if (multiple) {
select.setMultiple(true);
}
@@ -160,11 +160,15 @@
return top;
}-*/;
- public native int getBodyOffsetLeft() /*-{
+ public native String getAttribute(Element elem, String name) /*-{
+ return elem.getAttribute(name) || '';
+ }-*/;
+
+ public native int getBodyOffsetLeft(Document doc) /*-{
return 0;
}-*/;
- public native int getBodyOffsetTop() /*-{
+ public native int getBodyOffsetTop(Document doc) /*-{
return 0;
}-*/;
@@ -212,6 +216,14 @@
return parent;
}-*/;
+ public int getScrollLeft(Document doc) {
+ return doc.getViewportElement().getScrollLeft();
+ }
+
+ public int getScrollTop(Document doc) {
+ return doc.getViewportElement().getScrollTop();
+ }
+
public native String imgGetSrc(Element img) /*-{
return img.src;
}-*/;
@@ -286,10 +298,18 @@
}
// Add a new text node.
if (text != null) {
- elem.appendChild($doc.createTextNode(text));
+ elem.appendChild(elem.ownerDocument.createTextNode(text));
}
}-*/;
+ public void setScrollLeft(Document doc, int left) {
+ doc.getViewportElement().setScrollLeft(left);
+ }
+
+ public void setScrollTop(Document doc, int top) {
+ doc.getViewportElement().setScrollTop(top);
+ }
+
public native String toString(Element elem) /*-{
return elem.outerHTML;
}-*/;
diff --git a/user/src/com/google/gwt/dom/client/DOMImplIE6.java b/user/src/com/google/gwt/dom/client/DOMImplIE6.java
index f691ee5..d0c2f21 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplIE6.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplIE6.java
@@ -32,8 +32,8 @@
}-*/;
@Override
- public native InputElement createInputRadioElement(String name) /*-{
- return $doc.createElement("<INPUT type='RADIO' name='" + name + "'>");
+ public native InputElement createInputRadioElement(Document doc, String name) /*-{
+ return doc.createElement("<INPUT type='RADIO' name='" + name + "'>");
}-*/;
@Override
@@ -91,9 +91,9 @@
* but it should be harmless.
*/
@Override
- public native SelectElement createSelectElement(boolean multiple) /*-{
+ public native SelectElement createSelectElement(Document doc, boolean multiple) /*-{
var html = multiple ? "<SELECT MULTIPLE>" : "<SELECT>";
- return $doc.createElement(html);
+ return doc.createElement(html);
}-*/;
public native void dispatchEvent(Element target, NativeEvent evt) /*-{
@@ -135,40 +135,39 @@
}-*/;
@Override
- public native int getAbsoluteLeft(Element elem) /*-{
- // getBoundingClientRect() throws a JS exception if the elem is not attached
- // to the document, so we wrap it in a try/catch block
- try {
- return Math.floor((elem.getBoundingClientRect().left /
- this.@com.google.gwt.dom.client.DOMImplIE6::getZoomMultiple()()) +
- @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollLeft);
- } catch (e) {
- return 0;
- }
+ public int getAbsoluteLeft(Element elem) {
+ Document doc = elem.getOwnerDocument();
+ return (int) Math.floor(getBoundingClientRectLeft(elem)
+ / getZoomMultiple(doc) + doc.getScrollLeft());
+ }
+
+ @Override
+ public int getAbsoluteTop(Element elem) {
+ Document doc = elem.getOwnerDocument();
+ return (int) Math.floor(getBoundingClientRectTop(elem)
+ / getZoomMultiple(doc) + doc.getScrollTop());
+ }
+
+ /**
+ * IE returns a numeric type for some attributes that are really properties,
+ * such as offsetWidth. We need to coerce these to strings to prevent a
+ * runtime JS exception.
+ */
+ @Override
+ public native String getAttribute(Element elem, String name) /*-{
+ var attr = elem.getAttribute(name);
+ return attr == null? '' : attr + '';
}-*/;
@Override
- public native int getAbsoluteTop(Element elem) /*-{
- // getBoundingClientRect() throws a JS exception if the elem is not attached
- // to the document, so we wrap it in a try/catch block
- try {
- return Math.floor((elem.getBoundingClientRect().top /
- this.@com.google.gwt.dom.client.DOMImplIE6::getZoomMultiple()()) +
- @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollTop);
- } catch (e) {
- return 0;
- }
- }-*/;
+ public int getBodyOffsetLeft(Document doc) {
+ return getClientLeft(doc.getViewportElement());
+ }
@Override
- public native int getBodyOffsetLeft() /*-{
- return @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.clientLeft;
- }-*/;
-
- @Override
- public native int getBodyOffsetTop() /*-{
- return @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.clientTop;
- }-*/;
+ public int getBodyOffsetTop(Document doc) {
+ return getClientTop(doc.getViewportElement());
+ }
@Override
public native String getInnerText(Element elem) /*-{
@@ -224,6 +223,40 @@
elem.innerText = text || '';
}-*/;
+ private native int getBoundingClientRectLeft(Element elem) /*-{
+ // getBoundingClientRect() throws a JS exception if the elem is not attached
+ // to the document, so we wrap it in a try/catch block
+ try {
+ return elem.getBoundingClientRect().left;
+ } catch (e) {
+ return 0;
+ }
+ }-*/;
+
+ private native int getBoundingClientRectTop(Element elem) /*-{
+ // getBoundingClientRect() throws a JS exception if the elem is not attached
+ // to the document, so we wrap it in a try/catch block
+ try {
+ return elem.getBoundingClientRect().top;
+ } catch (e) {
+ return 0;
+ }
+ }-*/;
+
+ /**
+ * clientLeft is non-standard and not implemented on all browsers.
+ */
+ private native int getClientLeft(Element elem) /*-{
+ return elem.clientLeft;
+ }-*/;
+
+ /**
+ * clientTop is non-standard and not implemented on all browsers.
+ */
+ private native int getClientTop(Element elem) /*-{
+ return elem.clientTop;
+ }-*/;
+
/**
* Get the zoom multiple based on the current IE zoom level. A multiple of 2.0
* means that the user has zoomed in to 200%.
@@ -231,11 +264,12 @@
* @return the zoom multiple
*/
@SuppressWarnings("unused")
- private native double getZoomMultiple() /*-{
- if ($doc.compatMode == 'CSS1Compat') {
+ private double getZoomMultiple(Document doc) {
+ if (doc.getCompatMode().equals("CSS1Compat")) {
return 1;
} else {
- return $doc.body.parentElement.offsetWidth / $doc.body.offsetWidth;
+ return doc.getBody().getParentElement().getOffsetWidth() /
+ doc.getBody().getOffsetWidth();
}
- }-*/;
+ }
}
diff --git a/user/src/com/google/gwt/dom/client/DOMImplMozilla.java b/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
index 48b9c77..7465736 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
@@ -20,6 +20,7 @@
*/
class DOMImplMozilla extends DOMImplStandard {
+ @Override
public native void buttonClick(ButtonElement button) /*-{
var doc = button.ownerDocument;
if (doc != null) {
@@ -36,58 +37,26 @@
}-*/;
@Override
- public native int getAbsoluteLeft(Element elem) /*-{
- // Firefox 3 is actively throwing errors when getBoxObjectFor() is called,
- // so we use getBoundingClientRect() whenever possible (but it's not
- // supported on older versions). If changing this code, make sure to check
- // the museum entry for issue 1932.
- // (x) | 0 is used to coerce the value to an integer
- if (Element.prototype.getBoundingClientRect) {
- return (elem.getBoundingClientRect().left +
- @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollLeft) | 0;
- } else {
- // We cannot use DOMImpl here because offsetLeft/Top return erroneous
- // values when overflow is not visible. We have to difference screenX
- // here due to a change in getBoxObjectFor which causes inconsistencies
- // on whether the calculations are inside or outside of the element's
- // border.
- // If the element is in a scrollable div, getBoxObjectFor(elem) can return
- // a value that varies by 1 pixel.
- return $doc.getBoxObjectFor(elem).screenX -
- $doc.getBoxObjectFor($doc.documentElement).screenX;
- }
- }-*/;
+ public int getAbsoluteLeft(Element elem) {
+ return getAbsoluteLeftImpl(elem.getOwnerDocument().getViewportElement(),
+ elem);
+ }
@Override
- public native int getAbsoluteTop(Element elem) /*-{
- // Firefox 3 is actively throwing errors when getBoxObjectFor() is called,
- // so we use getBoundingClientRect() whenever possible (but it's not
- // supported on older versions). If changing this code, make sure to check
- // the museum entry for issue 1932.
- // (x) | 0 is used to coerce the value to an integer
- if (Element.prototype.getBoundingClientRect) {
- return (elem.getBoundingClientRect().top +
- @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollTop) | 0;
- } else {
- // We cannot use DOMImpl here because offsetLeft/Top return erroneous
- // values when overflow is not visible. We have to difference screenX
- // here due to a change in getBoxObjectFor which causes inconsistencies
- // on whether the calculations are inside or outside of the element's
- // border.
- return $doc.getBoxObjectFor(elem).screenY -
- $doc.getBoxObjectFor($doc.documentElement).screenY;
- }
- }-*/;
+ public int getAbsoluteTop(Element elem) {
+ return getAbsoluteTopImpl(elem.getOwnerDocument().getViewportElement(),
+ elem);
+ }
@Override
- public native int getBodyOffsetLeft() /*-{
- var style = $wnd.getComputedStyle($doc.documentElement, '');
+ public native int getBodyOffsetLeft(Document doc) /*-{
+ var style = $wnd.getComputedStyle(doc.documentElement, '');
return parseInt(style.marginLeft) + parseInt(style.borderLeftWidth);
}-*/;
@Override
- public native int getBodyOffsetTop() /*-{
- var style = $wnd.getComputedStyle($doc.documentElement, '');
+ public native int getBodyOffsetTop(Document doc) /*-{
+ var style = $wnd.getComputedStyle(doc.documentElement, '');
return parseInt(style.marginTop) + parseInt(style.borderTopWidth);
}-*/;
@@ -112,11 +81,54 @@
public native String toString(Element elem) /*-{
// Basic idea is to use the innerHTML property by copying the node into a
// div and getting the innerHTML
+ var doc = elem.ownerDocument;
var temp = elem.cloneNode(true);
- var tempDiv = $doc.createElement("DIV");
+ var tempDiv = doc.createElement("DIV");
tempDiv.appendChild(temp);
outer = tempDiv.innerHTML;
temp.innerHTML = "";
return outer;
}-*/;
+
+ private native int getAbsoluteLeftImpl(Element viewport, Element elem) /*-{
+ // Firefox 3 is actively throwing errors when getBoxObjectFor() is called,
+ // so we use getBoundingClientRect() whenever possible (but it's not
+ // supported on older versions). If changing this code, make sure to check
+ // the museum entry for issue 1932.
+ // (x) | 0 is used to coerce the value to an integer
+ if (Element.prototype.getBoundingClientRect) {
+ return (elem.getBoundingClientRect().left + viewport.scrollLeft) | 0;
+ } else {
+ // We cannot use DOMImpl here because offsetLeft/Top return erroneous
+ // values when overflow is not visible. We have to difference screenX
+ // here due to a change in getBoxObjectFor which causes inconsistencies
+ // on whether the calculations are inside or outside of the element's
+ // border.
+ // If the element is in a scrollable div, getBoxObjectFor(elem) can return
+ // a value that varies by 1 pixel.
+ var doc = elem.ownerDocument;
+ return doc.getBoxObjectFor(elem).screenX -
+ doc.getBoxObjectFor(doc.documentElement).screenX;
+ }
+ }-*/;
+
+ private native int getAbsoluteTopImpl(Element viewport, Element elem) /*-{
+ // Firefox 3 is actively throwing errors when getBoxObjectFor() is called,
+ // so we use getBoundingClientRect() whenever possible (but it's not
+ // supported on older versions). If changing this code, make sure to check
+ // the museum entry for issue 1932.
+ // (x) | 0 is used to coerce the value to an integer
+ if (Element.prototype.getBoundingClientRect) {
+ return (elem.getBoundingClientRect().top + viewport.scrollTop) | 0;
+ } else {
+ // We cannot use DOMImpl here because offsetLeft/Top return erroneous
+ // values when overflow is not visible. We have to difference screenX
+ // here due to a change in getBoxObjectFor which causes inconsistencies
+ // on whether the calculations are inside or outside of the element's
+ // border.
+ var doc = elem.ownerDocument;
+ return doc.getBoxObjectFor(elem).screenY -
+ doc.getBoxObjectFor(doc.documentElement).screenY;
+ }
+ }-*/;
}
diff --git a/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java b/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java
index b4e375b..64184a9 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java
@@ -26,11 +26,12 @@
@Override
public native int getAbsoluteLeft(Element elem) /*-{
- var style = $doc.defaultView.getComputedStyle(elem, null);
- var left = $doc.getBoxObjectFor(elem).x - Math.round(
+ var doc = elem.ownerDocument;
+ var style = doc.defaultView.getComputedStyle(elem, null);
+ var left = doc.getBoxObjectFor(elem).x - Math.round(
style.getPropertyCSSValue('border-left-width').getFloatValue(
CSSPrimitiveValue.CSS_PX));
-
+
var parent = elem.parentNode;
while (parent) {
// Sometimes get NAN.
@@ -46,8 +47,9 @@
@Override
public native int getAbsoluteTop(Element elem) /*-{
- var style = $doc.defaultView.getComputedStyle(elem, null);
- var top = $doc.getBoxObjectFor(elem).y - Math.round(
+ var doc = elem.ownerDocument;
+ var style = doc.defaultView.getComputedStyle(elem, null);
+ var top = doc.getBoxObjectFor(elem).y - Math.round(
style.getPropertyCSSValue('border-top-width').getFloatValue(
CSSPrimitiveValue.CSS_PX));
@@ -89,8 +91,7 @@
}
// Add a new text node.
if (text != null) {
- elem.appendChild($doc.createTextNode(text));
+ elem.appendChild(elem.ownerDocument.createTextNode(text));
}
}-*/;
-
}
diff --git a/user/src/com/google/gwt/dom/client/DOMImplSafari.java b/user/src/com/google/gwt/dom/client/DOMImplSafari.java
index 69a9223..ca512ac 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplSafari.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplSafari.java
@@ -41,45 +41,13 @@
* Safari 2 does not support {@link ScriptElement#setText(String)}.
*/
@Override
- public ScriptElement createScriptElement(String source) {
- ScriptElement elem = (ScriptElement) createElement("script");
+ public ScriptElement createScriptElement(Document doc, String source) {
+ ScriptElement elem = (ScriptElement) createElement(doc, "script");
elem.setInnerText(source);
return elem;
}
@Override
- public native int eventGetClientX(NativeEvent evt) /*-{
- // In Safari2: clientX is wrong and pageX is returned instead.
- // $wnd.devicePixelRatio identifies Safari 3 from Safari 2
- if ($wnd.devicePixelRatio) {
- return evt.clientX || 0;
- } else {
- // Subtract the margin and border of the HTML element in Safari 2
- // TODO: Remove this code when we drop Safari 2 support
- var style = document.defaultView.getComputedStyle($doc.getElementsByTagName('html')[0], '');
- return evt.pageX - $doc.body.scrollLeft
- - parseInt(style.getPropertyValue('margin-left'))
- - parseInt(style.getPropertyValue('border-left-width')) || 0;
- }
- }-*/;
-
- @Override
- public native int eventGetClientY(NativeEvent evt) /*-{
- // In Safari2: clientY is wrong and pageY is returned instead.
- // $wnd.devicePixelRatio identifies Safari 3 from Safari 2
- if ($wnd.devicePixelRatio) {
- return evt.clientY || 0;
- } else {
- // Subtract the margin and border of the HTML element in Safari 2
- // TODO: Remove this code when we drop Safari 2 support
- var style = document.defaultView.getComputedStyle($doc.getElementsByTagName('html')[0], '');
- return evt.pageY - $doc.body.scrollTop
- - parseInt(style.getPropertyValue('margin-top'))
- - parseInt(style.getPropertyValue('border-top-width')) || 0;
- }
- }-*/;
-
- @Override
public native int eventGetMouseWheelVelocityY(NativeEvent evt) /*-{
return Math.round(-evt.wheelDelta / 40) || 0;
}-*/;
@@ -93,6 +61,7 @@
}
var left = 0;
+ var doc = elem.ownerDocument;
var curr = elem.parentNode;
if (curr) {
// This intentionally excludes body which has a null offsetParent.
@@ -102,7 +71,7 @@
// In RTL mode, offsetLeft is relative to the left edge of the
// scrollable area when scrolled all the way to the right, so we need
// to add back that difference.
- if ($doc.defaultView.getComputedStyle(curr, '').getPropertyValue('direction') == 'rtl') {
+ if (doc.defaultView.getComputedStyle(curr, '').getPropertyValue('direction') == 'rtl') {
left += (curr.scrollWidth - curr.clientWidth);
}
@@ -117,7 +86,7 @@
// the borders of the parent manually.
var parent = elem.offsetParent;
if (parent && $wnd.devicePixelRatio) {
- left += parseInt($doc.defaultView.getComputedStyle(parent, '').getPropertyValue('border-left-width'));
+ left += parseInt(doc.defaultView.getComputedStyle(parent, '').getPropertyValue('border-left-width'));
}
// Safari bug: a top-level absolutely positioned element includes the
@@ -141,6 +110,7 @@
}
var top = 0;
+ var doc = elem.ownerDocument;
var curr = elem.parentNode;
if (curr) {
// This intentionally excludes body which has a null offsetParent.
@@ -157,7 +127,7 @@
// borders of the parent manually.
var parent = elem.offsetParent;
if (parent && $wnd.devicePixelRatio) {
- top += parseInt($doc.defaultView.getComputedStyle(parent, '').getPropertyValue('border-top-width'));
+ top += parseInt(doc.defaultView.getComputedStyle(parent, '').getPropertyValue('border-top-width'));
}
// Safari bug: a top-level absolutely positioned element includes the
@@ -173,6 +143,20 @@
}-*/;
@Override
+ public int getScrollLeft(Document doc) {
+ // Safari always applies document scrolling to the body element, even in
+ // strict mode.
+ return doc.getBody().getScrollLeft();
+ }
+
+ @Override
+ public int getScrollTop(Document doc) {
+ // Safari always applies document scrolling to the body element, even in
+ // strict mode.
+ return doc.getBody().getScrollTop();
+ }
+
+ @Override
public native boolean isOrHasChild(Element parent, Element child) /*-{
while (child) {
if (parent == child) {
@@ -215,4 +199,18 @@
public native void selectRemoveOption(SelectElement select, int index) /*-{
select.removeChild(select.children[index]);
}-*/;
+
+ @Override
+ public void setScrollLeft(Document doc, int left) {
+ // Safari always applies document scrolling to the body element, even in
+ // strict mode.
+ doc.getBody().setScrollLeft(left);
+ }
+
+ @Override
+ public void setScrollTop(Document doc, int top) {
+ // Safari always applies document scrolling to the body element, even in
+ // strict mode.
+ doc.getBody().setScrollTop(top);
+ }
}
diff --git a/user/src/com/google/gwt/dom/client/DOMImplStandard.java b/user/src/com/google/gwt/dom/client/DOMImplStandard.java
index 0536d46..c1cd284 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplStandard.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplStandard.java
@@ -32,8 +32,8 @@
}-*/;
@Override
- public native InputElement createInputRadioElement(String name) /*-{
- var elem = $doc.createElement("INPUT");
+ public native InputElement createInputRadioElement(Document doc, String name) /*-{
+ var elem = doc.createElement("INPUT");
elem.type = 'radio';
elem.name = name;
return elem;
diff --git a/user/src/com/google/gwt/dom/client/Document.java b/user/src/com/google/gwt/dom/client/Document.java
index 4c53f3a..209b1b9 100644
--- a/user/src/com/google/gwt/dom/client/Document.java
+++ b/user/src/com/google/gwt/dom/client/Document.java
@@ -41,7 +41,7 @@
* @return the newly created element
*/
public final AnchorElement createAnchorElement() {
- return (AnchorElement) DOMImpl.impl.createElement(AnchorElement.TAG);
+ return (AnchorElement) DOMImpl.impl.createElement(this, AnchorElement.TAG);
}
/**
@@ -50,7 +50,7 @@
* @return the newly created element
*/
public final AreaElement createAreaElement() {
- return (AreaElement) DOMImpl.impl.createElement(AreaElement.TAG);
+ return (AreaElement) DOMImpl.impl.createElement(this, AreaElement.TAG);
}
/**
@@ -59,7 +59,7 @@
* @return the newly created element
*/
public final BaseElement createBaseElement() {
- return (BaseElement) DOMImpl.impl.createElement(BaseElement.TAG);
+ return (BaseElement) DOMImpl.impl.createElement(this, BaseElement.TAG);
}
/**
@@ -68,7 +68,7 @@
* @return the newly created element
*/
public final QuoteElement createBlockQuoteElement() {
- return (QuoteElement) DOMImpl.impl.createElement(QuoteElement.TAG_BLOCKQUOTE);
+ return (QuoteElement) DOMImpl.impl.createElement(this, QuoteElement.TAG_BLOCKQUOTE);
}
/**
@@ -84,7 +84,7 @@
* @return the newly created element
*/
public final BRElement createBRElement() {
- return (BRElement) DOMImpl.impl.createElement(BRElement.TAG);
+ return (BRElement) DOMImpl.impl.createElement(this, BRElement.TAG);
}
/**
@@ -93,7 +93,7 @@
* @return the newly created element
*/
public final ButtonElement createButtonElement() {
- return (ButtonElement) DOMImpl.impl.createElement(ButtonElement.TAG);
+ return (ButtonElement) DOMImpl.impl.createElement(this, ButtonElement.TAG);
}
/**
@@ -102,7 +102,7 @@
* @return the newly created element
*/
public final TableCaptionElement createCaptionElement() {
- return (TableCaptionElement) DOMImpl.impl.createElement(TableCaptionElement.TAG);
+ return (TableCaptionElement) DOMImpl.impl.createElement(this, TableCaptionElement.TAG);
}
/**
@@ -118,7 +118,7 @@
* @return the newly created element
*/
public final InputElement createCheckInputElement() {
- return DOMImpl.impl.createInputElement("checkbox");
+ return DOMImpl.impl.createInputElement(this, "checkbox");
}
/**
@@ -156,7 +156,7 @@
* @return the newly created element
*/
public final TableColElement createColElement() {
- return (TableColElement) DOMImpl.impl.createElement(TableColElement.TAG_COL);
+ return (TableColElement) DOMImpl.impl.createElement(this, TableColElement.TAG_COL);
}
/**
@@ -165,7 +165,7 @@
* @return the newly created element
*/
public final TableColElement createColGroupElement() {
- return (TableColElement) DOMImpl.impl.createElement(TableColElement.TAG_COLGROUP);
+ return (TableColElement) DOMImpl.impl.createElement(this, TableColElement.TAG_COLGROUP);
}
/**
@@ -220,7 +220,7 @@
* @return the newly created element
*/
public final ModElement createDelElement() {
- return (ModElement) DOMImpl.impl.createElement(ModElement.TAG_DEL);
+ return (ModElement) DOMImpl.impl.createElement(this, ModElement.TAG_DEL);
}
/**
@@ -229,7 +229,7 @@
* @return the newly created element
*/
public final DivElement createDivElement() {
- return (DivElement) DOMImpl.impl.createElement(DivElement.TAG);
+ return (DivElement) DOMImpl.impl.createElement(this, DivElement.TAG);
}
/**
@@ -238,7 +238,7 @@
* @return the newly created element
*/
public final DListElement createDLElement() {
- return (DListElement) DOMImpl.impl.createElement(DListElement.TAG);
+ return (DListElement) DOMImpl.impl.createElement(this, DListElement.TAG);
}
/**
@@ -248,7 +248,7 @@
* @return the newly created element
*/
public final Element createElement(String tagName) {
- return DOMImpl.impl.createElement(tagName);
+ return DOMImpl.impl.createElement(this, tagName);
}
/**
@@ -266,7 +266,7 @@
* @return the newly created element
*/
public final FieldSetElement createFieldSetElement() {
- return (FieldSetElement) DOMImpl.impl.createElement(FieldSetElement.TAG);
+ return (FieldSetElement) DOMImpl.impl.createElement(this, FieldSetElement.TAG);
}
/**
@@ -275,7 +275,7 @@
* @return the newly created element
*/
public final InputElement createFileInputElement() {
- return DOMImpl.impl.createInputElement("file");
+ return DOMImpl.impl.createInputElement(this, "file");
}
/**
@@ -293,7 +293,7 @@
* @return the newly created element
*/
public final FormElement createFormElement() {
- return (FormElement) DOMImpl.impl.createElement(FormElement.TAG);
+ return (FormElement) DOMImpl.impl.createElement(this, FormElement.TAG);
}
/**
@@ -302,7 +302,7 @@
* @return the newly created element
*/
public final FrameElement createFrameElement() {
- return (FrameElement) DOMImpl.impl.createElement(FrameElement.TAG);
+ return (FrameElement) DOMImpl.impl.createElement(this, FrameElement.TAG);
}
/**
@@ -311,7 +311,7 @@
* @return the newly created element
*/
public final FrameSetElement createFrameSetElement() {
- return (FrameSetElement) DOMImpl.impl.createElement(FrameSetElement.TAG);
+ return (FrameSetElement) DOMImpl.impl.createElement(this, FrameSetElement.TAG);
}
/**
@@ -320,7 +320,7 @@
* @return the newly created element
*/
public final HeadElement createHeadElement() {
- return (HeadElement) DOMImpl.impl.createElement(HeadElement.TAG);
+ return (HeadElement) DOMImpl.impl.createElement(this, HeadElement.TAG);
}
/**
@@ -331,7 +331,7 @@
*/
public final HeadingElement createHElement(int n) {
assert (n >= 1) && (n <= 6);
- return (HeadingElement) DOMImpl.impl.createElement("h" + n);
+ return (HeadingElement) DOMImpl.impl.createElement(this, "h" + n);
}
/**
@@ -340,7 +340,7 @@
* @return the newly created element
*/
public final InputElement createHiddenInputElement() {
- return DOMImpl.impl.createInputElement("hidden");
+ return DOMImpl.impl.createInputElement(this, "hidden");
}
/**
@@ -349,7 +349,7 @@
* @return the newly created element
*/
public final HRElement createHRElement() {
- return (HRElement) DOMImpl.impl.createElement(HRElement.TAG);
+ return (HRElement) DOMImpl.impl.createElement(this, HRElement.TAG);
}
/**
@@ -383,7 +383,7 @@
* @return the newly created element
*/
public final IFrameElement createIFrameElement() {
- return (IFrameElement) DOMImpl.impl.createElement(IFrameElement.TAG);
+ return (IFrameElement) DOMImpl.impl.createElement(this, IFrameElement.TAG);
}
/**
@@ -392,7 +392,7 @@
* @return the newly created element
*/
public final ImageElement createImageElement() {
- return (ImageElement) DOMImpl.impl.createElement(ImageElement.TAG);
+ return (ImageElement) DOMImpl.impl.createElement(this, ImageElement.TAG);
}
/**
@@ -401,7 +401,7 @@
* @return the newly created element
*/
public final InputElement createImageInputElement() {
- return DOMImpl.impl.createInputElement("image");
+ return DOMImpl.impl.createInputElement(this, "image");
}
/**
@@ -410,7 +410,7 @@
* @return the newly created element
*/
public final ModElement createInsElement() {
- return (ModElement) DOMImpl.impl.createElement(ModElement.TAG_INS);
+ return (ModElement) DOMImpl.impl.createElement(this, ModElement.TAG_INS);
}
/**
@@ -504,7 +504,7 @@
* @return the newly created element
*/
public final LabelElement createLabelElement() {
- return (LabelElement) DOMImpl.impl.createElement(LabelElement.TAG);
+ return (LabelElement) DOMImpl.impl.createElement(this, LabelElement.TAG);
}
/**
@@ -513,7 +513,7 @@
* @return the newly created element
*/
public final LegendElement createLegendElement() {
- return (LegendElement) DOMImpl.impl.createElement(LegendElement.TAG);
+ return (LegendElement) DOMImpl.impl.createElement(this, LegendElement.TAG);
}
/**
@@ -522,7 +522,7 @@
* @return the newly created element
*/
public final LIElement createLIElement() {
- return (LIElement) DOMImpl.impl.createElement(LIElement.TAG);
+ return (LIElement) DOMImpl.impl.createElement(this, LIElement.TAG);
}
/**
@@ -531,7 +531,7 @@
* @return the newly created element
*/
public final LinkElement createLinkElement() {
- return (LinkElement) DOMImpl.impl.createElement(LinkElement.TAG);
+ return (LinkElement) DOMImpl.impl.createElement(this, LinkElement.TAG);
}
/**
@@ -549,7 +549,7 @@
* @return the newly created element
*/
public final MapElement createMapElement() {
- return (MapElement) DOMImpl.impl.createElement(MapElement.TAG);
+ return (MapElement) DOMImpl.impl.createElement(this, MapElement.TAG);
}
/**
@@ -558,7 +558,7 @@
* @return the newly created element
*/
public final MetaElement createMetaElement() {
- return (MetaElement) DOMImpl.impl.createElement(MetaElement.TAG);
+ return (MetaElement) DOMImpl.impl.createElement(this, MetaElement.TAG);
}
/**
@@ -735,7 +735,7 @@
* @return the newly created element
*/
public final ObjectElement createObjectElement() {
- return (ObjectElement) DOMImpl.impl.createElement(ObjectElement.TAG);
+ return (ObjectElement) DOMImpl.impl.createElement(this, ObjectElement.TAG);
}
/**
@@ -744,7 +744,7 @@
* @return the newly created element
*/
public final OListElement createOLElement() {
- return (OListElement) DOMImpl.impl.createElement(OListElement.TAG);
+ return (OListElement) DOMImpl.impl.createElement(this, OListElement.TAG);
}
/**
@@ -753,7 +753,7 @@
* @return the newly created element
*/
public final OptGroupElement createOptGroupElement() {
- return (OptGroupElement) DOMImpl.impl.createElement(OptGroupElement.TAG);
+ return (OptGroupElement) DOMImpl.impl.createElement(this, OptGroupElement.TAG);
}
/**
@@ -762,7 +762,7 @@
* @return the newly created element
*/
public final OptionElement createOptionElement() {
- return (OptionElement) DOMImpl.impl.createElement(OptionElement.TAG);
+ return (OptionElement) DOMImpl.impl.createElement(this, OptionElement.TAG);
}
/**
@@ -771,7 +771,7 @@
* @return the newly created element
*/
public final ParamElement createParamElement() {
- return (ParamElement) DOMImpl.impl.createElement(ParamElement.TAG);
+ return (ParamElement) DOMImpl.impl.createElement(this, ParamElement.TAG);
}
/**
@@ -780,7 +780,7 @@
* @return the newly created element
*/
public final InputElement createPasswordInputElement() {
- return DOMImpl.impl.createInputElement("password");
+ return DOMImpl.impl.createInputElement(this, "password");
}
/**
@@ -789,7 +789,7 @@
* @return the newly created element
*/
public final ParagraphElement createPElement() {
- return (ParagraphElement) DOMImpl.impl.createElement(ParagraphElement.TAG);
+ return (ParagraphElement) DOMImpl.impl.createElement(this, ParagraphElement.TAG);
}
/**
@@ -798,7 +798,7 @@
* @return the newly created element
*/
public final PreElement createPreElement() {
- return (PreElement) DOMImpl.impl.createElement(PreElement.TAG);
+ return (PreElement) DOMImpl.impl.createElement(this, PreElement.TAG);
}
/**
@@ -807,7 +807,7 @@
* @return the newly created element
*/
public final QuoteElement createQElement() {
- return (QuoteElement) DOMImpl.impl.createElement(QuoteElement.TAG_Q);
+ return (QuoteElement) DOMImpl.impl.createElement(this, QuoteElement.TAG_Q);
}
/**
@@ -817,7 +817,7 @@
* @return the newly created element
*/
public final InputElement createRadioInputElement(String name) {
- return DOMImpl.impl.createInputRadioElement(name);
+ return DOMImpl.impl.createInputRadioElement(this, name);
}
/**
@@ -826,7 +826,7 @@
* @return the newly created element
*/
public final ScriptElement createScriptElement() {
- return (ScriptElement) DOMImpl.impl.createElement(ScriptElement.TAG);
+ return (ScriptElement) DOMImpl.impl.createElement(this, ScriptElement.TAG);
}
/**
@@ -836,7 +836,7 @@
* @return the newly created element
*/
public final ScriptElement createScriptElement(String source) {
- return DOMImpl.impl.createScriptElement(source);
+ return DOMImpl.impl.createScriptElement(this, source);
}
/**
@@ -857,7 +857,7 @@
* @return the newly created element
*/
public final SelectElement createSelectElement() {
- return DOMImpl.impl.createSelectElement(false);
+ return DOMImpl.impl.createSelectElement(this, false);
}
/**
@@ -867,7 +867,7 @@
* @return the newly created element
*/
public final SelectElement createSelectElement(boolean multiple) {
- return DOMImpl.impl.createSelectElement(multiple);
+ return DOMImpl.impl.createSelectElement(this, multiple);
}
/**
@@ -876,7 +876,7 @@
* @return the newly created element
*/
public final SpanElement createSpanElement() {
- return (SpanElement) DOMImpl.impl.createElement(SpanElement.TAG);
+ return (SpanElement) DOMImpl.impl.createElement(this, SpanElement.TAG);
}
/**
@@ -885,7 +885,7 @@
* @return the newly created element
*/
public final StyleElement createStyleElement() {
- return (StyleElement) DOMImpl.impl.createElement(StyleElement.TAG);
+ return (StyleElement) DOMImpl.impl.createElement(this, StyleElement.TAG);
}
/**
@@ -894,7 +894,7 @@
* @return the newly created element
*/
public final TableElement createTableElement() {
- return (TableElement) DOMImpl.impl.createElement(TableElement.TAG);
+ return (TableElement) DOMImpl.impl.createElement(this, TableElement.TAG);
}
/**
@@ -903,7 +903,7 @@
* @return the newly created element
*/
public final TableSectionElement createTBodyElement() {
- return (TableSectionElement) DOMImpl.impl.createElement(TableSectionElement.TAG_TBODY);
+ return (TableSectionElement) DOMImpl.impl.createElement(this, TableSectionElement.TAG_TBODY);
}
/**
@@ -912,7 +912,7 @@
* @return the newly created element
*/
public final TableCellElement createTDElement() {
- return (TableCellElement) DOMImpl.impl.createElement(TableCellElement.TAG_TD);
+ return (TableCellElement) DOMImpl.impl.createElement(this, TableCellElement.TAG_TD);
}
/**
@@ -921,7 +921,7 @@
* @return the newly created element
*/
public final TextAreaElement createTextAreaElement() {
- return (TextAreaElement) DOMImpl.impl.createElement(TextAreaElement.TAG);
+ return (TextAreaElement) DOMImpl.impl.createElement(this, TextAreaElement.TAG);
}
/**
@@ -930,7 +930,7 @@
* @return the newly created element
*/
public final InputElement createTextInputElement() {
- return DOMImpl.impl.createInputElement("text");
+ return DOMImpl.impl.createInputElement(this, "text");
}
/**
@@ -949,7 +949,7 @@
* @return the newly created element
*/
public final TableSectionElement createTFootElement() {
- return (TableSectionElement) DOMImpl.impl.createElement(TableSectionElement.TAG_TFOOT);
+ return (TableSectionElement) DOMImpl.impl.createElement(this, TableSectionElement.TAG_TFOOT);
}
/**
@@ -958,7 +958,7 @@
* @return the newly created element
*/
public final TableSectionElement createTHeadElement() {
- return (TableSectionElement) DOMImpl.impl.createElement(TableSectionElement.TAG_THEAD);
+ return (TableSectionElement) DOMImpl.impl.createElement(this, TableSectionElement.TAG_THEAD);
}
/**
@@ -967,7 +967,7 @@
* @return the newly created element
*/
public final TableCellElement createTHElement() {
- return (TableCellElement) DOMImpl.impl.createElement(TableCellElement.TAG_TH);
+ return (TableCellElement) DOMImpl.impl.createElement(this, TableCellElement.TAG_TH);
}
/**
@@ -976,7 +976,7 @@
* @return the newly created element
*/
public final TitleElement createTitleElement() {
- return (TitleElement) DOMImpl.impl.createElement(TitleElement.TAG);
+ return (TitleElement) DOMImpl.impl.createElement(this, TitleElement.TAG);
}
/**
@@ -985,7 +985,7 @@
* @return the newly created element
*/
public final TableRowElement createTRElement() {
- return (TableRowElement) DOMImpl.impl.createElement(TableRowElement.TAG);
+ return (TableRowElement) DOMImpl.impl.createElement(this, TableRowElement.TAG);
}
/**
@@ -994,7 +994,7 @@
* @return the newly created element
*/
public final UListElement createULElement() {
- return (UListElement) DOMImpl.impl.createElement(UListElement.TAG);
+ return (UListElement) DOMImpl.impl.createElement(this, UListElement.TAG);
}
/**
@@ -1015,6 +1015,16 @@
}-*/;
/**
+ * Enables or disables scrolling of the document
+ *
+ * @param enable whether scrolling should be enabled or disabled
+ */
+ public final void enableScrolling(boolean enable) {
+ getViewportElement().getStyle().setProperty("overflow",
+ enable ? "" : "hidden");
+ }
+
+ /**
* The element that contains the content for the document. In documents with
* BODY contents, returns the BODY element.
*
@@ -1052,7 +1062,7 @@
* @return the left offset of the body's positioning coordinate system
*/
public final int getBodyOffsetLeft() {
- return DOMImpl.impl.getBodyOffsetLeft();
+ return DOMImpl.impl.getBodyOffsetLeft(this);
}
/**
@@ -1064,10 +1074,47 @@
* @see #getBodyOffsetLeft()
*/
public final int getBodyOffsetTop() {
- return DOMImpl.impl.getBodyOffsetTop();
+ return DOMImpl.impl.getBodyOffsetTop(this);
}
/**
+ * The height of the document's client area.
+ *
+ * @return the document's client height
+ */
+ public final int getClientHeight() {
+ return getViewportElement().getClientHeight();
+ }
+
+ /**
+ * The width of the document's client area.
+ *
+ * @return the document's client width
+ */
+ public final int getClientWidth() {
+ return getViewportElement().getClientWidth();
+ }
+
+ /**
+ * Gets the document's "compatibility mode", typically used for determining
+ * whether the document is in "quirks" or "strict" mode.
+ *
+ * @return one of "BackCompat" or "CSS1Compat"
+ */
+ public final native String getCompatMode() /*-{
+ return this.compatMode;
+ }-*/;
+
+ /**
+ * Gets the document's element. This is typically the <html> element.
+ *
+ * @return the document element
+ */
+ public final native Element getDocumentElement() /*-{
+ return this.documentElement;
+ }-*/;
+
+ /**
* The domain name of the server that served the document, or null if the
* server cannot be identified by a domain name.
*
@@ -1114,6 +1161,42 @@
}-*/;
/**
+ * The height of the scrollable area of the document.
+ *
+ * @return the height of the document's scrollable area
+ */
+ public final int getScrollHeight() {
+ return getViewportElement().getScrollHeight();
+ }
+
+ /**
+ * The number of pixels that the document's content is scrolled from the left.
+ *
+ * @return the document's left scroll position
+ */
+ public final int getScrollLeft() {
+ return DOMImpl.impl.getScrollLeft(this);
+ }
+
+ /**
+ * The number of pixels that the document's content is scrolled from the top.
+ *
+ * @return the document's top scroll position
+ */
+ public final int getScrollTop() {
+ return DOMImpl.impl.getScrollTop(this);
+ }
+
+ /**
+ * The width of the scrollable area of the document.
+ *
+ * @return the width of the document's scrollable area
+ */
+ public final int getScrollWidth() {
+ return getViewportElement().getScrollWidth();
+ }
+
+ /**
* Gets the title of a document as specified by the TITLE element in the head
* of the document.
*
@@ -1158,6 +1241,36 @@
}-*/;
/**
+ * Determines whether the document's "compatMode" is "CSS1Compat". This is
+ * normally described as "strict" mode.
+ *
+ * @return <code>true</code> if the document is in CSS1Compat mode
+ */
+ public final boolean isCSS1Compat() {
+ return getCompatMode().equals("CSS1Compat");
+ }
+
+ /**
+ * Sets the number of pixels that the document's content is scrolled from the
+ * left.
+ *
+ * @param left the document's left scroll position
+ */
+ public final void setScrollLeft(int left) {
+ DOMImpl.impl.setScrollLeft(this, left);
+ }
+
+ /**
+ * Sets the number of pixels that the document's content is scrolled from the
+ * top.
+ *
+ * @param top the document's top scroll position
+ */
+ public final void setScrollTop(int top) {
+ DOMImpl.impl.setScrollTop(this, top);
+ }
+
+ /**
* Sets the title of a document as specified by the TITLE element in the head
* of the document.
*
@@ -1166,4 +1279,18 @@
public final native void setTitle(String title) /*-{
this.title = title;
}-*/;
+
+ /**
+ * Gets the document's viewport element. This is the element that should be
+ * used to for scrolling and client-area measurement. In quirks-mode it is the
+ * <body> element, while in standards-mode it is the <html>
+ * element.
+ *
+ * This is package-protected because the viewport is
+ *
+ * @return the document's viewport element
+ */
+ final Element getViewportElement() {
+ return isCSS1Compat() ? getDocumentElement() : getBody();
+ }
}
diff --git a/user/src/com/google/gwt/dom/client/Element.java b/user/src/com/google/gwt/dom/client/Element.java
index 5bcfd0c..f5c9aed 100644
--- a/user/src/com/google/gwt/dom/client/Element.java
+++ b/user/src/com/google/gwt/dom/client/Element.java
@@ -66,15 +66,18 @@
}
/**
- * Retrieves an attribute value by name.
+ * Retrieves an attribute value by name. Attribute support can be
+ * inconsistent across various browsers. Consider using the accessors in
+ * {@link Element} and its specific subclasses to retrieve attributes and
+ * properties.
*
* @param name The name of the attribute to retrieve
* @return The Attr value as a string, or the empty string if that attribute
* does not have a specified or default value
*/
- public final native String getAttribute(String name) /*-{
- return this.getAttribute(name) || '';
- }-*/;
+ public final String getAttribute(String name) {
+ return DOMImpl.impl.getAttribute(this, name);
+ }
/**
* The class attribute of the element. This attribute has been renamed due to
@@ -89,6 +92,26 @@
}-*/;
/**
+ * Returns the inner height of an element in pixels, including padding but not
+ * the horizontal scrollbar height, border, or margin.
+ *
+ * @return the element's client height
+ */
+ public final native int getClientHeight() /*-{
+ return this.clientHeight;
+ }-*/;
+
+ /**
+ * Returns the inner width of an element in pixels, including padding but not
+ * the vertical scrollbar width, border, or margin.
+ *
+ * @return the element's client width
+ */
+ public final native int getClientWidth() /*-{
+ return this.clientWidth;
+ }-*/;
+
+ /**
* Specifies the base direction of directionally neutral text and the
* directionality of tables.
*/
@@ -250,14 +273,14 @@
}-*/;
/**
- * The number of pixels that an element's content is scrolled to the left.
+ * The number of pixels that an element's content is scrolled from the left.
*/
public final native int getScrollLeft() /*-{
return this.scrollLeft || 0;
}-*/;
/**
- * The number of pixels that an element's content is scrolled to the top.
+ * The number of pixels that an element's content is scrolled from the top.
*/
public final native int getScrollTop() /*-{
return this.scrollTop || 0;
diff --git a/user/src/com/google/gwt/event/dom/client/MouseEvent.java b/user/src/com/google/gwt/event/dom/client/MouseEvent.java
index 1357261..e86407e 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseEvent.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.event.dom.client;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.shared.EventHandler;
/**
@@ -24,6 +26,7 @@
*
*/
public abstract class MouseEvent<H extends EventHandler> extends DomEvent<H> {
+
/**
* Gets the mouse x-position within the browser window's client area.
*
@@ -55,6 +58,32 @@
}
/**
+ * Gets the mouse x-position relative to a given element.
+ *
+ * @param target the element whose coordinate system is to be used
+ * @return the relative x-position
+ */
+ public int getRelativeX(Element target) {
+ NativeEvent e = getNativeEvent();
+
+ return e.getClientX() - target.getAbsoluteLeft() + target.getScrollLeft() +
+ target.getOwnerDocument().getScrollLeft();
+ }
+
+ /**
+ * Gets the mouse y-position relative to a given element.
+ *
+ * @param target the element whose coordinate system is to be used
+ * @return the relative y-position
+ */
+ public int getRelativeY(Element target) {
+ NativeEvent e = getNativeEvent();
+
+ return e.getClientY() - target.getAbsoluteTop() + target.getScrollTop() +
+ target.getOwnerDocument().getScrollTop();
+ }
+
+ /**
* Gets the mouse x-position on the user's display.
*
* @return the mouse x-position
@@ -73,6 +102,24 @@
}
/**
+ * Gets the mouse x-position relative to the event's target element.
+ *
+ * @return the relative x-position
+ */
+ public int getTargetX() {
+ return getRelativeX(getNativeEvent().getTarget());
+ }
+
+ /**
+ * Gets the mouse y-position relative to the event's target element.
+ *
+ * @return the relative y-position
+ */
+ public int getTargetY() {
+ return getRelativeY(getNativeEvent().getTarget());
+ }
+
+ /**
* Is <code>alt</code> key down.
*
* @return whether the alt key is down
@@ -107,4 +154,4 @@
public boolean isShiftKeyDown() {
return getNativeEvent().getShiftKey();
}
-}
\ No newline at end of file
+}
diff --git a/user/src/com/google/gwt/event/dom/client/package-info.java b/user/src/com/google/gwt/event/dom/client/package-info.java
new file mode 100644
index 0000000..b6b0843
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ * Types related to DOM events.
+ */
+@com.google.gwt.util.PreventSpuriousRebuilds
+package com.google.gwt.event.dom.client;
diff --git a/user/src/com/google/gwt/event/logical/shared/package-info.java b/user/src/com/google/gwt/event/logical/shared/package-info.java
new file mode 100644
index 0000000..6840892
--- /dev/null
+++ b/user/src/com/google/gwt/event/logical/shared/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ * Types related to logical events that do not have direct analogues to DOM
+ * events and which can be used in contexts other than web browsers. Types
+ * within this package do not use JSNI and do not have static (even
+ * indirect) dependencies upon types which use JSNI.
+ */
+@com.google.gwt.util.PreventSpuriousRebuilds
+package com.google.gwt.event.logical.shared;
diff --git a/user/src/com/google/gwt/event/shared/package-info.java b/user/src/com/google/gwt/event/shared/package-info.java
new file mode 100644
index 0000000..74bcfc3
--- /dev/null
+++ b/user/src/com/google/gwt/event/shared/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ * Shared infrastructure underlying both browser and non-browser events. Types
+ * within this package do not use JSNI and do not have static (even indirect)
+ * dependencies upon types which use JSNI.
+ */
+@com.google.gwt.util.PreventSpuriousRebuilds
+package com.google.gwt.event.shared;
diff --git a/user/src/com/google/gwt/i18n/client/BidiUtils.java b/user/src/com/google/gwt/i18n/client/BidiUtils.java
index a51a489..ee89859 100644
--- a/user/src/com/google/gwt/i18n/client/BidiUtils.java
+++ b/user/src/com/google/gwt/i18n/client/BidiUtils.java
@@ -15,8 +15,7 @@
*/
package com.google.gwt.i18n.client;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.DOM;
+import com.google.gwt.dom.client.Element;
import com.google.gwt.i18n.client.HasDirection.Direction;
/**
@@ -50,8 +49,7 @@
* <code>DEFAULT</code> if the directionality is not explicitly set
*/
public static HasDirection.Direction getDirectionOnElement(Element elem) {
-
- String dirPropertyValue = DOM.getElementProperty(elem, DIR_PROPERTY_NAME);
+ String dirPropertyValue = elem.getPropertyString(DIR_PROPERTY_NAME);
if (DIR_PROPERTY_VALUE_RTL.equalsIgnoreCase(dirPropertyValue)) {
return HasDirection.Direction.RTL;
@@ -71,15 +69,14 @@
* <code>DEFAULT</code> if the directionality should be removed from the element
*/
public static void setDirectionOnElement(Element elem, Direction direction) {
-
switch (direction) {
case RTL: {
- DOM.setElementProperty(elem, DIR_PROPERTY_NAME, DIR_PROPERTY_VALUE_RTL);
+ elem.setPropertyString(DIR_PROPERTY_NAME, DIR_PROPERTY_VALUE_RTL);
break;
}
case LTR: {
- DOM.setElementProperty(elem, DIR_PROPERTY_NAME, DIR_PROPERTY_VALUE_LTR);
+ elem.setPropertyString(DIR_PROPERTY_NAME, DIR_PROPERTY_VALUE_LTR);
break;
}
@@ -87,7 +84,7 @@
if (getDirectionOnElement(elem) != HasDirection.Direction.DEFAULT) {
// only clear out the the dir property if it has already been set to something
// explicitly
- DOM.setElementProperty(elem, DIR_PROPERTY_NAME, "");
+ elem.setPropertyString(DIR_PROPERTY_NAME, "");
}
break;
}
diff --git a/user/src/com/google/gwt/user/DocumentRoot.gwt.xml b/user/src/com/google/gwt/user/DocumentRoot.gwt.xml
index 211eb95..4a79d87 100644
--- a/user/src/com/google/gwt/user/DocumentRoot.gwt.xml
+++ b/user/src/com/google/gwt/user/DocumentRoot.gwt.xml
@@ -19,9 +19,4 @@
<module>
<inherits name="com.google.gwt.core.Core"/>
<inherits name="com.google.gwt.user.UserAgent"/>
-
- <replace-with class="com.google.gwt.user.client.impl.DocumentRootImplSafari">
- <when-type-is class="com.google.gwt.user.client.impl.DocumentRootImpl"/>
- <when-property-is name="user.agent" value="safari"/>
- </replace-with>
</module>
diff --git a/user/src/com/google/gwt/user/Window.gwt.xml b/user/src/com/google/gwt/user/Window.gwt.xml
index ec8571b..9511634 100644
--- a/user/src/com/google/gwt/user/Window.gwt.xml
+++ b/user/src/com/google/gwt/user/Window.gwt.xml
@@ -24,14 +24,4 @@
<when-type-is class="com.google.gwt.user.client.impl.WindowImpl"/>
<when-property-is name="user.agent" value="ie6"/>
</replace-with>
-
- <replace-with class="com.google.gwt.user.client.impl.WindowImplOpera">
- <when-type-is class="com.google.gwt.user.client.impl.WindowImpl"/>
- <when-property-is name="user.agent" value="opera"/>
- </replace-with>
-
- <replace-with class="com.google.gwt.user.client.impl.WindowImplSafari">
- <when-type-is class="com.google.gwt.user.client.impl.WindowImpl"/>
- <when-property-is name="user.agent" value="safari"/>
- </replace-with>
</module>
diff --git a/user/src/com/google/gwt/user/client/DOM.java b/user/src/com/google/gwt/user/client/DOM.java
index c781bd1..8ba36b5 100644
--- a/user/src/com/google/gwt/user/client/DOM.java
+++ b/user/src/com/google/gwt/user/client/DOM.java
@@ -784,6 +784,17 @@
}
/**
+ * Gets the {@link EventListener} that will receive events for the given
+ * element. Only one such listener may exist for a single element.
+ *
+ * @param elem the element whose listener is to be set
+ * @return the element's event listener
+ */
+ public static EventListener getEventListener(Element elem) {
+ return impl.getEventListener(elem);
+ }
+
+ /**
* Gets the current set of events sunk by a given element.
*
* @param elem the element whose events are to be retrieved
diff --git a/user/src/com/google/gwt/user/client/Event.java b/user/src/com/google/gwt/user/client/Event.java
index 0d633fd..a7e466a 100644
--- a/user/src/com/google/gwt/user/client/Event.java
+++ b/user/src/com/google/gwt/user/client/Event.java
@@ -424,6 +424,17 @@
}
/**
+ * Gets the {@link EventListener} that will receive events for the given
+ * element. Only one such listener may exist for a single element.
+ *
+ * @param elem the element whose listener is to be set
+ * @return the element's event listener
+ */
+ public static EventListener getEventListener(Element elem) {
+ return DOM.getEventListener((com.google.gwt.user.client.Element) elem);
+ }
+
+ /**
* Gets the current set of events sunk by a given element.
*
* @param elem the element whose events are to be retrieved
diff --git a/user/src/com/google/gwt/user/client/Window.java b/user/src/com/google/gwt/user/client/Window.java
index 9e4338f..872ac69 100644
--- a/user/src/com/google/gwt/user/client/Window.java
+++ b/user/src/com/google/gwt/user/client/Window.java
@@ -17,6 +17,7 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
+import com.google.gwt.dom.client.Document;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.HasCloseHandlers;
@@ -513,7 +514,7 @@
* @param enable <code>false</code> to disable window scrolling
*/
public static void enableScrolling(boolean enable) {
- impl.enableScrolling(enable);
+ Document.get().enableScrolling(enable);
}
/**
@@ -523,7 +524,7 @@
* @return the window's client height
*/
public static int getClientHeight() {
- return impl.getClientHeight();
+ return Document.get().getClientHeight();
}
/**
@@ -533,7 +534,7 @@
* @return the window's client width
*/
public static int getClientWidth() {
- return impl.getClientWidth();
+ return Document.get().getClientWidth();
}
/**
@@ -542,7 +543,7 @@
* @return window's scroll left
*/
public static int getScrollLeft() {
- return impl.getScrollLeft();
+ return Document.get().getScrollLeft();
}
/**
@@ -551,7 +552,7 @@
* @return the window's scroll top
*/
public static int getScrollTop() {
- return impl.getScrollTop();
+ return Document.get().getScrollTop();
}
/**
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImpl.java b/user/src/com/google/gwt/user/client/impl/DOMImpl.java
index a42eaa5..2b31054 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImpl.java
@@ -100,6 +100,10 @@
public abstract int getChildIndex(Element parent, Element child);
+ public native EventListener getEventListener(Element elem) /*-{
+ return elem.__listener;
+ }-*/;
+
public native int getEventsSunk(Element elem) /*-{
return elem.__eventBits || 0;
}-*/;
diff --git a/user/src/com/google/gwt/user/client/impl/DocumentRootImpl.java b/user/src/com/google/gwt/user/client/impl/DocumentRootImpl.java
index 1b4cf58..609f352 100644
--- a/user/src/com/google/gwt/user/client/impl/DocumentRootImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/DocumentRootImpl.java
@@ -16,18 +16,23 @@
package com.google.gwt.user.client.impl;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Document;
import com.google.gwt.user.client.Element;
/**
* Native implementation used by {@link WindowImpl} and {@link DOMImpl} to
* access the appropriate documentRoot element, which varies based on the render
* mode of the browser.
+ *
+ * @deprecated use the direct methods provided in {@link Document} instead
*/
+@Deprecated
public class DocumentRootImpl {
protected static Element documentRoot =
((DocumentRootImpl) GWT.create(DocumentRootImpl.class)).getDocumentRoot();
- protected native Element getDocumentRoot() /*-{
- return $doc.compatMode == 'CSS1Compat' ? $doc.documentElement : $doc.body;
- }-*/;
+ protected Element getDocumentRoot() {
+ Document doc = Document.get();
+ return (doc.isCSS1Compat() ? doc.getDocumentElement() : doc.getBody()).cast();
+ }
}
diff --git a/user/src/com/google/gwt/user/client/impl/DocumentRootImplSafari.java b/user/src/com/google/gwt/user/client/impl/DocumentRootImplSafari.java
deleted file mode 100644
index f88c4ab..0000000
--- a/user/src/com/google/gwt/user/client/impl/DocumentRootImplSafari.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2008 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.impl;
-
-import com.google.gwt.user.client.Element;
-
-/**
- * Safari implementation of {@link DocumentRootImpl}.
- */
-public class DocumentRootImplSafari extends DocumentRootImpl {
- @Override
- protected native Element getDocumentRoot() /*-{
- // Safari does not implement $doc.compatMode.
- // Use a CSS test to determine rendering mode.
- var elem = $doc.createElement('div');
- elem.style.cssText = "width:0px;width:1";
- return parseInt(elem.style.width) != 1 ? $doc.documentElement : $doc.body;
- }-*/;
-}
diff --git a/user/src/com/google/gwt/user/client/impl/WindowImpl.java b/user/src/com/google/gwt/user/client/impl/WindowImpl.java
index 9bb6333..3be39bc 100644
--- a/user/src/com/google/gwt/user/client/impl/WindowImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/WindowImpl.java
@@ -20,18 +20,6 @@
* {@link com.google.gwt.user.client.Window}.
*/
public class WindowImpl {
- public native void enableScrolling(boolean enable) /*-{
- @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.style.overflow =
- enable ? "" : "hidden";
- }-*/;
-
- public native int getClientHeight() /*-{
- return @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.clientHeight;
- }-*/;
-
- public native int getClientWidth() /*-{
- return @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.clientWidth;
- }-*/;
public native String getHash() /*-{
return $wnd.location.hash;
@@ -41,14 +29,6 @@
return $wnd.location.search;
}-*/;
- public native int getScrollLeft() /*-{
- return @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollLeft;
- }-*/;
-
- public native int getScrollTop() /*-{
- return @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollTop;
- }-*/;
-
public native void initWindowCloseHandler() /*-{
var oldOnBeforeUnload = $wnd.onbeforeunload;
var oldOnUnload = $wnd.onunload;
diff --git a/user/src/com/google/gwt/user/client/impl/WindowImplOpera.java b/user/src/com/google/gwt/user/client/impl/WindowImplOpera.java
deleted file mode 100644
index a6e8d0e..0000000
--- a/user/src/com/google/gwt/user/client/impl/WindowImplOpera.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2008 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.impl;
-
-import com.google.gwt.user.client.Element;
-
-/**
- * Opera implementation of {@link com.google.gwt.user.client.impl.WindowImpl}.
- */
-public class WindowImplOpera extends WindowImpl {
- @SuppressWarnings("unused")
- private static Element body;
-
- /**
- * In standards mode, on Opera 9.5 (and presumably, above), the clientHeight
- * and clientWidth are defined on doc.documentElement instead of doc.body.
- */
- @SuppressWarnings("unused")
- private static native Element getBodyElement() /*-{
- if (@com.google.gwt.user.client.impl.WindowImplOpera::body == null) {
- @com.google.gwt.user.client.impl.WindowImplOpera::body =
- ($doc.compatMode == 'CSS1Compat' && opera.version() >= 9.5) ?
- $doc.documentElement : $doc.body;
- }
- return @com.google.gwt.user.client.impl.WindowImplOpera::body;
- }-*/;
-
- @Override
- public native int getClientHeight() /*-{
- return @com.google.gwt.user.client.impl.WindowImplOpera::getBodyElement()().clientHeight;
- }-*/;
-
- @Override
- public native int getClientWidth() /*-{
- return @com.google.gwt.user.client.impl.WindowImplOpera::getBodyElement()().clientWidth;
- }-*/;
-}
diff --git a/user/src/com/google/gwt/user/client/impl/WindowImplSafari.java b/user/src/com/google/gwt/user/client/impl/WindowImplSafari.java
deleted file mode 100644
index 75b9130..0000000
--- a/user/src/com/google/gwt/user/client/impl/WindowImplSafari.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2008 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.impl;
-
-/**
- * Safari implementation of {@link com.google.gwt.user.client.impl.WindowImpl}.
- */
-public class WindowImplSafari extends WindowImpl {
- @Override
- public native int getClientHeight() /*-{
- // Safari 2 and Safari 3 disagree on the clientHeight value.
- // $wnd.devicePixelRatio is only defined in Safari 3.
- // documentRoot.clientWidth works in both Safari 2 and 3, so we do not need
- // an override for the width.
- return $wnd.devicePixelRatio ?
- @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.clientHeight :
- $wnd.innerHeight;
- }-*/;
-
- @Override
- public native int getScrollLeft() /*-{
- return $doc.body.scrollLeft;
- }-*/;
-
- @Override
- public native int getScrollTop() /*-{
- return $doc.body.scrollTop;
- }-*/;
-}
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 09be6ff..4251521 100644
--- a/user/src/com/google/gwt/user/client/ui/CheckBox.java
+++ b/user/src/com/google/gwt/user/client/ui/CheckBox.java
@@ -20,6 +20,10 @@
import com.google.gwt.dom.client.LabelElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
+import com.google.gwt.event.dom.client.MouseUpEvent;
+import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
@@ -55,6 +59,7 @@
private InputElement inputElem;
private LabelElement labelElem;
private boolean valueChangeHandlerInitialized;
+ private boolean valueBeforeClick;
/**
* Creates a check box with no label.
@@ -111,17 +116,29 @@
public HandlerRegistration addValueChangeHandler(
ValueChangeHandler<Boolean> handler) {
- // Is this the first value change handler? If so, time to listen to clicks
- // on the checkbox
+ // Is this the first value change handler? If so, time to add handlers
if (!valueChangeHandlerInitialized) {
- valueChangeHandlerInitialized = true;
- this.addClickHandler(new ClickHandler() {
- public void onClick(ClickEvent event) {
- // No need to compare old value and new value--click handler
- // only fires on real click, and value always toggles
- ValueChangeEvent.fire(CheckBox.this, getValue());
+
+ this.addKeyUpHandler(new KeyUpHandler() {
+ public void onKeyUp(KeyUpEvent event) {
+ valueBeforeClick = getValue();
}
});
+
+ this.addMouseUpHandler(new MouseUpHandler() {
+ public void onMouseUp(MouseUpEvent event) {
+ valueBeforeClick = getValue();
+ }
+ });
+
+ this.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ ValueChangeEvent.fireIfNotEqual(CheckBox.this, valueBeforeClick,
+ getValue());
+ }
+ });
+
+ valueChangeHandlerInitialized = true;
}
return addHandler(handler, ValueChangeEvent.getType());
}
@@ -312,13 +329,15 @@
}
}
- // Unlike other widgets the CheckBox sinks on its input element, not its
- // wrapper element.
+ // Unlike other widgets the CheckBox sinks on its constituent elements, not
+ // their wrapper element.
@Override
public void sinkEvents(int eventBitsToAdd) {
if (isOrWasAttached()) {
Event.sinkEvents(inputElem,
eventBitsToAdd | Event.getEventsSunk(inputElem));
+ Event.sinkEvents(labelElem,
+ eventBitsToAdd | Event.getEventsSunk(labelElem));
} else {
super.sinkEvents(eventBitsToAdd);
}
diff --git a/user/src/com/google/gwt/user/client/ui/HTMLPanel.java b/user/src/com/google/gwt/user/client/ui/HTMLPanel.java
index ca7fa68..1bbdeb6 100644
--- a/user/src/com/google/gwt/user/client/ui/HTMLPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/HTMLPanel.java
@@ -116,7 +116,7 @@
if (hiddenDiv == null) {
hiddenDiv = DOM.createDiv();
UIObject.setVisible(hiddenDiv, false);
- DOM.appendChild(RootPanel.getBodyElement(), hiddenDiv);
+ RootPanel.getBodyElement().appendChild(hiddenDiv);
}
// Hang on to the panel's original parent and sibling elements so that it
@@ -133,6 +133,8 @@
// Put the panel's element back where it was.
if (origParent != null) {
DOM.insertBefore(origParent, getElement(), origSibling);
+ } else {
+ DOM.removeChild(hiddenDiv, getElement());
}
return child;
diff --git a/user/src/com/google/gwt/user/client/ui/ListBox.java b/user/src/com/google/gwt/user/client/ui/ListBox.java
index 80531fc..35b1b87 100644
--- a/user/src/com/google/gwt/user/client/ui/ListBox.java
+++ b/user/src/com/google/gwt/user/client/ui/ListBox.java
@@ -312,7 +312,7 @@
* fail on Internet Explorer 6.0.</em>
*
* @param multiple <code>true</code> to allow multiple selections
- * @deprecated use {@link #ListBox(boolean) instead
+ * @deprecated use {@link #ListBox(boolean)} instead
*/
@Deprecated
public void setMultipleSelect(boolean multiple) {
diff --git a/user/src/com/google/gwt/user/client/ui/RootPanel.java b/user/src/com/google/gwt/user/client/ui/RootPanel.java
index 3f70afb..96999c4 100644
--- a/user/src/com/google/gwt/user/client/ui/RootPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/RootPanel.java
@@ -15,14 +15,15 @@
*/
package com.google.gwt.user.client.ui;
+import com.google.gwt.dom.client.BodyElement;
import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.i18n.client.BidiUtils;
import com.google.gwt.i18n.client.HasDirection;
import com.google.gwt.i18n.client.LocaleInfo;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import java.util.HashMap;
@@ -32,7 +33,8 @@
/**
* The panel to which all other widgets must ultimately be added. RootPanels are
- * never created directly. Rather, they are accessed via {@link RootPanel#get()}.
+ * never created directly. Rather, they are accessed via {@link RootPanel#get()}
+ * .
*
* <p>
* Most applications will add widgets to the default root panel in their
@@ -67,24 +69,24 @@
/**
* Marks a widget as detached and removes it from the detach list.
*
+ * <p>
* If an element belonging to a widget originally passed to
- * {@link #detachOnWindowClose(Widget)} has been removed from the document, calling
- * this method will cause it to be marked as detached immediately. Failure to
- * do so will keep the widget from being garbage collected until the page is
- * unloaded.
+ * {@link #detachOnWindowClose(Widget)} has been removed from the document,
+ * calling this method will cause it to be marked as detached immediately.
+ * Failure to do so will keep the widget from being garbage collected until
+ * the page is unloaded.
+ * </p>
*
+ * <p>
* This method may only be called per widget, and only for widgets that were
- * originally passed to {@link #detachOnWindowClose(Widget)}. Any widget in the
- * detach list, whose element is no longer in the document when the page
- * unloads, will cause an assertion error.
+ * originally passed to {@link #detachOnWindowClose(Widget)}.
+ * </p>
*
* @param widget the widget that no longer needs to be cleaned up when the
* page closes
* @see #detachOnWindowClose(Widget)
*/
public static void detachNow(Widget widget) {
- assert !getBodyElement().isOrHasChild(widget.getElement()) : "detachNow() "
- + "called on a widget whose element is still attached to the document";
assert widgetsToDetach.contains(widget) : "detachNow() called on a widget "
+ "not currently in the detach list";
@@ -96,12 +98,20 @@
* Adds a widget to the detach list. This is the list of widgets to be
* detached when the page unloads.
*
+ * <p>
* This method must be called for all widgets that have no parent widgets.
* These are most commonly {@link RootPanel RootPanels}, but can also be any
* widget used to wrap an existing element on the page. Failing to do this may
* cause these widgets to leak memory. This method is called automatically by
* widgets' wrap methods (e.g.
* {@link Button#wrap(com.google.gwt.dom.client.Element)}).
+ * </p>
+ *
+ * <p>
+ * This method may <em>not</em> be called on any widget whose element is
+ * contained in another widget. This is to ensure that the DOM and Widget
+ * hierarchies cannot get into an inconsistent state.
+ * </p>
*
* @param widget the widget to be cleaned up when the page closes
* @see #detachNow(Widget)
@@ -109,12 +119,14 @@
public static void detachOnWindowClose(Widget widget) {
assert !widgetsToDetach.contains(widget) : "detachOnUnload() called twice "
+ "for the same widget";
+ assert !isElementChildOfWidget(widget.getElement()) : "A widget that has "
+ + "an existing parent widget may not be added to the detach list";
widgetsToDetach.add(widget);
}
/**
- * Gets the default root panel. This panel wraps body of the browser's
+ * Gets the default root panel. This panel wraps the body of the browser's
* document. This root panel can contain any number of widgets, which will be
* laid out in their natural HTML ordering. Many applications, however, will
* add a single panel to the RootPanel to provide more structure.
@@ -130,24 +142,34 @@
* work, the HTML document into which the application is loaded must have
* specified an element with the given id.
*
- * @param id the id of the element to be wrapped with a root panel
+ * @param id the id of the element to be wrapped with a root panel (
+ * <code>null</code> specifies the default instance, which wraps the
+ * <body> element)
* @return the root panel, or <code>null</code> if no such element was found
*/
public static RootPanel get(String id) {
// See if this RootPanel is already created.
RootPanel rp = rootPanels.get(id);
- if (rp != null) {
- return rp;
- }
// Find the element that this RootPanel will wrap.
Element elem = null;
if (id != null) {
- if (null == (elem = DOM.getElementById(id))) {
+ // Return null if the id is specified, but no element is found.
+ if (null == (elem = Document.get().getElementById(id))) {
return null;
}
}
+ if (rp != null) {
+ // If the element associated with an existing RootPanel has been replaced
+ // for any reason, return a new RootPanel rather than the existing one (
+ // see issue 1937).
+ if ((elem == null) || (rp.getElement() == elem)) {
+ // There's already an existing RootPanel for this element. Return it.
+ return rp;
+ }
+ }
+
// Note that the code in this if block only happens once -
// on the first RootPanel.get(String) or RootPanel.get()
// call.
@@ -181,10 +203,20 @@
*
* @return the document's body element
*/
- public static native Element getBodyElement() /*-{
+ public static native com.google.gwt.user.client.Element getBodyElement() /*-{
return $doc.body;
}-*/;
+ /**
+ * Determines whether the given widget is in the detach list.
+ *
+ * @param widget the widget to be checked
+ * @return <code>true</code> if the widget is in the detach list
+ */
+ public static boolean isInDetachList(Widget widget) {
+ return widgetsToDetach.contains(widget);
+ }
+
// Package-protected for use by unit tests. Do not call this method directly.
static void detachWidgets() {
// When the window is closing, detach all widgets that need to be
@@ -194,16 +226,15 @@
if (widget.isAttached()) {
widget.onDetach();
}
-
- // Assert that each widget's element is actually attached to the
- // document. If not, then it was probably wrapped and removed, but not
- // properly detached.
- assert getBodyElement().isOrHasChild(widget.getElement()) : "A "
- + "widget in the detach list was found not attached to the "
- + "document. The is likely caused by wrapping an existing "
- + "element and removing it from the document without calling "
- + "RootPanel.detachNow().";
}
+
+ widgetsToDetach.clear();
+
+ // Clear the RootPanel cache, since we've "detached" all RootPanels at this
+ // point. This would be pointless, since it only happens on unload, but it
+ // is very helpful for unit tests, because it allows RootPanel.get() to work
+ // properly even after a synthesized "unload".
+ rootPanels.clear();
}
/**
@@ -224,8 +255,29 @@
});
}
+ /*
+ * Checks to see whether the given element has any parent element that
+ * belongs to a widget. This is not terribly efficient, and is thus only used
+ * in an assertion.
+ */
+ private static boolean isElementChildOfWidget(Element element) {
+ // Walk up the DOM hierarchy, looking for any widget with an event listener
+ // set. Though it is not dependable in the general case that a widget will
+ // have set its element's event listener at all times, it *is* dependable
+ // if the widget is attached. Which it will be in this case.
+ element = element.getParentElement();
+ BodyElement body = Document.get().getBody();
+ while ((element != null) && (body != element)) {
+ if (Event.getEventListener(element) != null) {
+ return true;
+ }
+ element = element.getParentElement().cast();
+ }
+ return false;
+ }
+
private RootPanel(Element elem) {
- super(elem);
+ super(elem.<com.google.gwt.user.client.Element> cast());
onAttach();
}
}
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 fcabb5c..7f30b3d 100644
--- a/user/src/com/google/gwt/user/client/ui/SuggestBox.java
+++ b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
@@ -15,6 +15,8 @@
*/
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.event.dom.client.HandlesAllKeyEvents;
import com.google.gwt.event.dom.client.HasAllKeyHandlers;
import com.google.gwt.event.dom.client.KeyCodes;
@@ -207,6 +209,7 @@
}
}
+
/**
* Class for menu items in a SuggestionMenu. A SuggestionMenuItem differs from
* a MenuItem in that each item is backed by a Suggestion object. The text of
@@ -241,6 +244,31 @@
private static final String STYLENAME_DEFAULT = "gwt-SuggestBox";
+ /**
+ * Creates a {@link SuggestBox} widget that wraps an existing <input
+ * type='text'> element.
+ *
+ * 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 oracle the suggest box oracle to use
+ * @param element the element to be wrapped
+ */
+ public static SuggestBox wrap(SuggestOracle oracle, Element element) {
+ // Assert that the element is attached.
+ assert Document.get().getBody().isOrHasChild(element);
+
+ TextBox textBox = new TextBox(element);
+ SuggestBox suggestBox = new SuggestBox(oracle, textBox);
+
+ // Mark it attached and remember it for cleanup.
+ suggestBox.onAttach();
+ RootPanel.detachOnWindowClose(suggestBox);
+
+ return suggestBox;
+ }
+
private int limit = 20;
private boolean selectsFirstItem = true;
private SuggestOracle oracle;
diff --git a/user/src/com/google/gwt/user/client/ui/UIObject.java b/user/src/com/google/gwt/user/client/ui/UIObject.java
index d6d91c4..9341329 100644
--- a/user/src/com/google/gwt/user/client/ui/UIObject.java
+++ b/user/src/com/google/gwt/user/client/ui/UIObject.java
@@ -97,7 +97,7 @@
* The implementation of the set debug id method, which does nothing by
* default.
*/
- public static class DebugIdImpl {
+ private static class DebugIdImpl {
@SuppressWarnings("unused")
// parameters
public void ensureDebugId(UIObject uiObject, String id) {
@@ -113,7 +113,8 @@
* The implementation of the setDebugId method, which sets the id of the
* {@link Element}s in this {@link UIObject}.
*/
- public static class DebugIdImplEnabled extends DebugIdImpl {
+ @SuppressWarnings("unused")
+ private static class DebugIdImplEnabled extends DebugIdImpl {
@Override
public void ensureDebugId(UIObject uiObject, String id) {
uiObject.onEnsureDebugId(id);
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 f3aa9d9..e2e5860 100644
--- a/user/src/com/google/gwt/user/client/ui/Widget.java
+++ b/user/src/com/google/gwt/user/client/ui/Widget.java
@@ -89,16 +89,29 @@
}
DomEvent.fireNativeEvent(event, this);
}
-
+
/**
- * Removes this widget from its parent widget. If it has no parent, this
- * method does nothing.
+ * Removes this widget from its parent widget, if one exists.
+ *
+ * <p>
+ * If it has no parent, this method does nothing. If it is a "root" widget
+ * (meaning it's been added to the detach list via
+ * {@link RootPanel#detachOnWindowClose(Widget)}), it will be removed from the
+ * detached immediately. This makes it possible for Composites and Panels to
+ * adopt root widgets.
+ * </p>
*
* @throws IllegalStateException if this widget's parent does not support
* removal (e.g. {@link Composite})
*/
public void removeFromParent() {
- if (parent instanceof HasWidgets) {
+ if (parent == null) {
+ // If the widget had no parent, check to see if it was in the detach list
+ // and remove it if necessary.
+ if (RootPanel.isInDetachList(this)) {
+ RootPanel.detachNow(this);
+ }
+ } else if (parent instanceof HasWidgets) {
((HasWidgets) parent).remove(this);
} else if (parent != null) {
throw new IllegalStateException(
diff --git a/user/src/com/google/gwt/user/datepicker/client/package-info.java b/user/src/com/google/gwt/user/datepicker/client/package-info.java
new file mode 100644
index 0000000..c6f60c9
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ * The date picker widget and associated types.
+ */
+@com.google.gwt.util.PreventSpuriousRebuilds
+package com.google.gwt.user.datepicker.client;
diff --git a/user/src/com/google/gwt/user/tools/AppHtml.htmlsrc b/user/src/com/google/gwt/user/tools/AppHtml.htmlsrc
index f3b8917..bb0d8c3 100644
--- a/user/src/com/google/gwt/user/tools/AppHtml.htmlsrc
+++ b/user/src/com/google/gwt/user/tools/AppHtml.htmlsrc
@@ -9,10 +9,12 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+
<!-- -->
<!-- Consider inlining CSS to reduce the number of requested files -->
<!-- -->
<link type="text/css" rel="stylesheet" href="@moduleShortName.css">
+
<!-- -->
<!-- Any title is fine -->
<!-- -->
diff --git a/user/src/com/google/gwt/user/tools/README.txtsrc b/user/src/com/google/gwt/user/tools/README.txtsrc
new file mode 100644
index 0000000..3a9d1c0
--- /dev/null
+++ b/user/src/com/google/gwt/user/tools/README.txtsrc
@@ -0,0 +1,62 @@
+--- Generated by GWT WebAppCreator ---
+
+Congratulations, you've successfully generated a starter project! What next?
+
+-- Option A: Import your project into Eclipse (recommended) --
+
+If you use Eclipse, you can simply import the generated project into Eclipse.
+We've tested against Eclipse 3.3 and 3.4. Later versions will likely also work,
+eariler versions may not.
+
+In Eclipse, go to the File menu and choose:
+
+ File -> Import... -> Existing Projects into Workspace
+
+ Browse to the directory containing this file,
+ select "@moduleShortName".
+
+ Be sure to uncheck "Copy projects into workspace" if it is checked.
+
+ Click Finish.
+
+You can now browse the project in Eclipse.
+
+To launch your web app in GWT hosted mode, go to the Run menu and choose:
+
+ Run -> Open Debug Dialog...
+
+ Under Java Application, you should find a launch configuration
+ named "@moduleShortName". Select and click "Debug".
+
+ You can now use the built-in debugger to debug your web app in hosted mode.
+
+To compile for web mode, just run your app in hosted mode and press the
+"Compile/Browse" button.
+
+-- Option B: Build from the command line with Ant --
+
+If you prefer to work from the command line, you can use Ant to build your
+project. (http://ant.apache.org/) Ant uses the generated 'build.xml' file
+which describes exactly how to build your project. This file has been tested
+to work against Ant 1.7.1. The following assumes 'ant' is on your command
+line path.
+
+To run hosted mode, just type 'ant hosted'.
+
+To compile your project for deployment, just type 'ant'.
+
+To compile and also bundle into a .war file, type 'ant war'.
+
+For a full listing of other targets, type 'ant -p'.
+
+-- Option C: Using another IDE --
+
+GWT projects can be run in other IDEs as well, but will require some manual
+setup. If you go this route, be sure to:
+
+* Have your IDE build .class files into 'war/WEB-INF/classes'.
+* Add gwt-user.jar and gwt-dev-<platform>.jar to your project build path.
+* When creating a launch configuration, add a classpath entry for your 'src'
+ folder (this is somewhat unusual but GWT needs access to your source files).
+
+If you get stuck, try to mimic what the Ant 'build.xml' would do.
diff --git a/user/src/com/google/gwt/user/tools/RpcServerTemplate.javasrc b/user/src/com/google/gwt/user/tools/RpcServerTemplate.javasrc
index 2b122de..4278c86 100644
--- a/user/src/com/google/gwt/user/tools/RpcServerTemplate.javasrc
+++ b/user/src/com/google/gwt/user/tools/RpcServerTemplate.javasrc
@@ -4,8 +4,9 @@
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
/**
- * The server side implementation of the Rpc service.
+ * The server side implementation of the RPC service.
*/
+@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService {
diff --git a/user/src/com/google/gwt/user/tools/WebAppCreator.java b/user/src/com/google/gwt/user/tools/WebAppCreator.java
index 9dd36be..280372e 100644
--- a/user/src/com/google/gwt/user/tools/WebAppCreator.java
+++ b/user/src/com/google/gwt/user/tools/WebAppCreator.java
@@ -101,7 +101,7 @@
@Override
public String getPurpose() {
- return "The name of the module to create (fully-qualified Java class name)";
+ return "The name of the module to create (e.g. com.example.myapp.MyApp)";
}
@Override
@@ -302,6 +302,7 @@
files.add(new FileCreator(serverDir, "GreetingServiceImpl" + ".java",
"RpcServerTemplate.java"));
files.add(new FileCreator(outDir, "build.xml", "project.ant.xml"));
+ files.add(new FileCreator(outDir, "README.txt", "README.txt"));
}
if (!noEclipse) {
assert new File(gwtDevPath).isAbsolute();
@@ -314,14 +315,13 @@
// copy source files, replacing the content as needed
for (FileCreator fileCreator : files) {
+ URL url = WebAppCreator.class.getResource(fileCreator.sourceName + "src");
+ if (url == null) {
+ throw new FileNotFoundException(fileCreator.sourceName + "src");
+ }
File file = Utility.createNormalFile(fileCreator.destDir,
fileCreator.destName, overwrite, ignore);
if (file != null) {
- URL url = WebAppCreator.class.getResource(fileCreator.sourceName
- + "src");
- if (url == null) {
- throw new FileNotFoundException(fileCreator.sourceName + "src");
- }
String data = Util.readURLAsString(url);
Utility.writeTemplateFile(file, data, replacements);
}
@@ -329,10 +329,10 @@
// copy libs directly
for (FileCreator fileCreator : libs) {
+ FileInputStream is = new FileInputStream(fileCreator.sourceName);
File file = Utility.createNormalFile(fileCreator.destDir,
fileCreator.destName, overwrite, ignore);
if (file != null) {
- FileInputStream is = new FileInputStream(fileCreator.sourceName);
FileOutputStream os = new FileOutputStream(file);
Util.copy(is, os);
}
diff --git a/user/test/com/google/gwt/debug/client/DebugInfoTest.java b/user/test/com/google/gwt/debug/client/DebugInfoTest.java
index 04fcaeb..9d7f4f4 100644
--- a/user/test/com/google/gwt/debug/client/DebugInfoTest.java
+++ b/user/test/com/google/gwt/debug/client/DebugInfoTest.java
@@ -18,7 +18,7 @@
import com.google.gwt.junit.client.GWTTestCase;
/**
- * Test Case for {@link DebugInfo}.
+ * Test Case for {@link DebugInfo} when <code>gwt.enableDebugId</code> is enabled.
*/
public class DebugInfoTest extends GWTTestCase {
diff --git a/user/test/com/google/gwt/debug/client/DebugInfoTestDisabled.java b/user/test/com/google/gwt/debug/client/DebugInfoTestDisabled.java
new file mode 100644
index 0000000..c3677be
--- /dev/null
+++ b/user/test/com/google/gwt/debug/client/DebugInfoTestDisabled.java
@@ -0,0 +1,36 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.debug.client;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Test Case for {@link DebugInfo} when <code>gwt.enableDebugId</code> is disabled.
+ */
+public class DebugInfoTestDisabled extends GWTTestCase {
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.DebugTestDisabled";
+ }
+
+ /**
+ * Test that the {@link DebugInfo#isDebugIdEnabled()} method works correctly when debug ids are disabled.
+ */
+ public void testIsDebugIdDisabled() {
+ assertFalse(DebugInfo.isDebugIdEnabled());
+ }
+}
diff --git a/user/test/com/google/gwt/dom/client/ElementTest.java b/user/test/com/google/gwt/dom/client/ElementTest.java
index f51fe92..a4f965a 100644
--- a/user/test/com/google/gwt/dom/client/ElementTest.java
+++ b/user/test/com/google/gwt/dom/client/ElementTest.java
@@ -31,7 +31,7 @@
}
/**
- * [get|set|remove]Attribute
+ * [get|set|remove]Attribute.
*/
public void testElementAttribute() {
DivElement div = Document.get().createDivElement();
@@ -44,7 +44,21 @@
}
/**
- * getAbsolute[Left|Top]
+ * Ensure that the return type of an attribute is always a string. IE should
+ * not return a numeric attribute based on the element property. See issue
+ * 3238.
+ */
+ public void testElementAttributeNumeric() {
+ DivElement div = Document.get().createDivElement();
+ Document.get().getBody().appendChild(div);
+ div.setInnerText("Hello World");
+ div.getAttribute("offsetWidth").length();
+ div.getAttribute("offsetWidth").trim().length();
+ Document.get().getBody().removeChild(div);
+ }
+
+ /**
+ * getAbsolute[Left|Top].
*/
public void testGetAbsolutePosition() {
final int border = 8;
@@ -77,7 +91,7 @@
}
/**
- * scroll[Left|Top], scrollIntoView
+ * scroll[Left|Top], scrollIntoView.
*/
public void testGetAbsolutePositionWhenScrolled() {
final DivElement outer = Document.get().createDivElement();
@@ -111,7 +125,7 @@
}
/**
- * getParentElement
+ * getParentElement.
*/
public void testGetParent() {
Element element = Document.get().getBody();
@@ -131,7 +145,7 @@
}
/**
- * firstChildElement, nextSiblingElement
+ * firstChildElement, nextSiblingElement.
*/
public void testChildElements() {
Document doc = Document.get();
@@ -151,7 +165,7 @@
}
/**
- * isOrHasChild
+ * isOrHasChild.
*/
public void testIsOrHasChild() {
DivElement div = Document.get().createDivElement();
@@ -171,7 +185,7 @@
}
/**
- * innerText
+ * innerText.
*/
public void testSetInnerText() {
Document doc = Document.get();
@@ -198,7 +212,7 @@
}
/**
- * innerHTML
+ * innerHTML.
*/
public void testSetInnerHTML() {
DivElement div = Document.get().createDivElement();
@@ -213,7 +227,7 @@
}
/**
- * setProperty*, getProperty*
+ * setProperty*, getProperty*.
*/
public void testProperties() {
DivElement div = Document.get().createDivElement();
@@ -231,7 +245,7 @@
}
/**
- * className, id, tagName, title, dir, lang
+ * className, id, tagName, title, dir, lang.
*/
public void testNativeProperties() {
DivElement div = Document.get().createDivElement();
@@ -255,7 +269,7 @@
}
/**
- * style
+ * style.
*/
public void testStyle() {
DivElement div = Document.get().createDivElement();
@@ -303,7 +317,7 @@
}
/**
- * offset[Left|Top|Width|Height], offsetParent
+ * offset[Left|Top|Width|Height], offsetParent.
*/
public void testOffsets() {
DivElement outer = Document.get().createDivElement();
@@ -329,7 +343,7 @@
}
/**
- * getElementsByTagName
+ * getElementsByTagName.
*/
public void testGetElementsByTagName() {
DivElement div = Document.get().createDivElement();
diff --git a/user/test/com/google/gwt/user/DebugTestDisabled.gwt.xml b/user/test/com/google/gwt/user/DebugTestDisabled.gwt.xml
new file mode 100644
index 0000000..0b0e425
--- /dev/null
+++ b/user/test/com/google/gwt/user/DebugTestDisabled.gwt.xml
@@ -0,0 +1,19 @@
+<!-- -->
+<!-- Copyright 2008 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 -->
+<!-- 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. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module>
+ <inherits name="com.google.gwt.user.User"/>
+ <inherits name="com.google.gwt.user.Debug"/>
+ <set-property name="gwt.enableDebugId" value="false"/>
+</module>
diff --git a/user/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java
index c5bac76..0566294 100644
--- a/user/test/com/google/gwt/user/UISuite.java
+++ b/user/test/com/google/gwt/user/UISuite.java
@@ -23,7 +23,6 @@
import com.google.gwt.user.client.WindowTest;
import com.google.gwt.user.client.ui.AbsolutePanelTest;
import com.google.gwt.user.client.ui.AnchorTest;
-import com.google.gwt.user.client.ui.WidgetTest;
import com.google.gwt.user.client.ui.ButtonTest;
import com.google.gwt.user.client.ui.CaptionPanelTest;
import com.google.gwt.user.client.ui.CheckBoxTest;
@@ -66,6 +65,7 @@
import com.google.gwt.user.client.ui.PrefixTreeTest;
import com.google.gwt.user.client.ui.RadioButtonTest;
import com.google.gwt.user.client.ui.RichTextAreaTest;
+import com.google.gwt.user.client.ui.RootPanelTest;
import com.google.gwt.user.client.ui.ScrollPanelTest;
import com.google.gwt.user.client.ui.SimpleCheckBoxTest;
import com.google.gwt.user.client.ui.SimpleRadioButtonTest;
@@ -82,6 +82,7 @@
import com.google.gwt.user.client.ui.WidgetIteratorsTest;
import com.google.gwt.user.client.ui.WidgetOnLoadTest;
import com.google.gwt.user.client.ui.WidgetSubclassingTest;
+import com.google.gwt.user.client.ui.WidgetTest;
import com.google.gwt.user.client.ui.impl.ClippedImagePrototypeTest;
import com.google.gwt.user.datepicker.client.DateChangeEventTest;
import com.google.gwt.user.rebind.ui.ImageBundleGeneratorTest;
@@ -168,6 +169,7 @@
suite.addTestSuite(DateChangeEventTest.class);
suite.addTestSuite(CreateEventTest.class);
suite.addTestSuite(WidgetTest.class);
+ suite.addTestSuite(RootPanelTest.class);
return suite;
}
}
diff --git a/user/test/com/google/gwt/user/client/rpc/ManuallySerializedImmutableClass.java b/user/test/com/google/gwt/user/client/rpc/ManuallySerializedImmutableClass.java
index ff407d0..d1a7de7 100644
--- a/user/test/com/google/gwt/user/client/rpc/ManuallySerializedImmutableClass.java
+++ b/user/test/com/google/gwt/user/client/rpc/ManuallySerializedImmutableClass.java
@@ -32,8 +32,21 @@
@SuppressWarnings("unused")
private Date dateTypeExposeToSerialization;
- private final Date endDate;
- private final Date startDate;
+ /**
+ * Transient to avoid 'cannot serialize final field' RPC warning.
+ *
+ * FIXME: when final fields are supported, or don't generate warnings for
+ * custom serialized classes.
+ */
+ private final transient Date endDate;
+
+ /**
+ * Transient to avoid 'cannot serialize final field' RPC warning.
+ *
+ * FIXME: when final fields are supported, or don't generate warnings for
+ * custom serialized classes.
+ */
+ private final transient Date startDate;
public ManuallySerializedImmutableClass(Date startDate, Date endDate) {
this.startDate = startDate;
diff --git a/user/test/com/google/gwt/user/client/ui/ElementWrappingTest.java b/user/test/com/google/gwt/user/client/ui/ElementWrappingTest.java
index 1a8d5f0..27a8b50 100644
--- a/user/test/com/google/gwt/user/client/ui/ElementWrappingTest.java
+++ b/user/test/com/google/gwt/user/client/ui/ElementWrappingTest.java
@@ -34,6 +34,9 @@
return "com.google.gwt.user.UserTest";
}
+ /**
+ * Tests {@link Anchor#wrap(Element)}.
+ */
public void testAnchor() {
ensureDiv().setInnerHTML("<a id='foo' href='" + TEST_URL + "'>myAnchor</a>");
Anchor anchor = Anchor.wrap(Document.get().getElementById("foo"));
@@ -43,6 +46,9 @@
assertEquals("myAnchor", anchor.getText());
}
+ /**
+ * Tests {@link Button#wrap(Element)}.
+ */
public void testButton() {
ensureDiv().setInnerHTML("<button id='foo'>myButton</button>");
Button button = Button.wrap(Document.get().getElementById("foo"));
@@ -51,136 +57,10 @@
assertEquals("myButton", button.getText());
}
- public void testFileUpload() {
- ensureDiv().setInnerHTML("<input type='file' id='foo'>myInput</input>");
- FileUpload upload = FileUpload.wrap(Document.get().getElementById("foo"));
-
- assertExistsAndAttached(upload);
- }
-
- public void testFormPanel() {
- ensureDiv().setInnerHTML("<form id='foo'></form>");
- FormPanel formPanel = FormPanel.wrap(Document.get().getElementById("foo"));
-
- assertExistsAndAttached(formPanel);
- }
-
- public void testFrame() {
- ensureDiv().setInnerHTML("<iframe id='foo'>myFrame</iframe>");
- Frame frame = Frame.wrap(Document.get().getElementById("foo"));
-
- assertExistsAndAttached(frame);
- }
-
- public void testHidden() {
- ensureDiv().setInnerHTML("<input type='hidden' id='foo'></input>");
- Hidden hidden = Hidden.wrap(Document.get().getElementById("foo"));
-
- assertExistsAndAttached(hidden);
- }
-
- public void testHTML() {
- ensureDiv().setInnerHTML("<div id='foo'>myHTML</div>");
- HTML html = HTML.wrap(Document.get().getElementById("foo"));
-
- assertExistsAndAttached(html);
- assertEquals("myHTML", html.getHTML());
- }
-
- public void testImage() {
- ensureDiv().setInnerHTML("<img id='foo' src='" + IMG_URL + "'>");
- Image image = Image.wrap(Document.get().getElementById("foo"));
-
- assertExistsAndAttached(image);
- assertEquals(IMG_URL, image.getUrl());
- }
-
- public void testInlineHTML() {
- ensureDiv().setInnerHTML("<span id='foo'>myInlineHTML</span>");
- InlineHTML html = InlineHTML.wrap(Document.get().getElementById("foo"));
-
- assertExistsAndAttached(html);
- assertEquals("myInlineHTML", html.getHTML());
- }
-
- public void testInlineLabel() {
- ensureDiv().setInnerHTML("<span id='foo'>myInlineLabel</span>");
- InlineLabel label = InlineLabel.wrap(Document.get().getElementById("foo"));
-
- assertExistsAndAttached(label);
- assertEquals("myInlineLabel", label.getText());
- }
-
- public void testLabel() {
- ensureDiv().setInnerHTML("<div id='foo'>myLabel</div>");
- Label label = Label.wrap(Document.get().getElementById("foo"));
-
- assertExistsAndAttached(label);
- assertEquals("myLabel", label.getText());
- }
-
- public void testListBox() {
- ensureDiv().setInnerHTML("<select id='foo'></select>");
- ListBox listBox = ListBox.wrap(Document.get().getElementById("foo"));
-
- assertExistsAndAttached(listBox);
- }
-
- public void testPasswordTextBox() {
- ensureDiv().setInnerHTML("<input type='password' id='foo'></input>");
- PasswordTextBox textBox = PasswordTextBox.wrap(Document.get().getElementById(
- "foo"));
-
- assertExistsAndAttached(textBox);
- }
-
- public void testSimpleCheckBox() {
- ensureDiv().setInnerHTML("<input type='checkbox' id='foo'></input>");
- SimpleCheckBox checkBox = SimpleCheckBox.wrap(Document.get().getElementById(
- "foo"));
-
- assertExistsAndAttached(checkBox);
- }
-
- public void testSimpleRadioButton() {
- ensureDiv().setInnerHTML("<input type='radio' id='foo'></input>");
- SimpleRadioButton radio = SimpleRadioButton.wrap(Document.get().getElementById(
- "foo"));
-
- assertExistsAndAttached(radio);
- }
-
- public void testTextArea() {
- ensureDiv().setInnerHTML("<textarea rows='1' cols='1' id='foo'></textarea>");
- TextArea textArea = TextArea.wrap(Document.get().getElementById("foo"));
-
- assertExistsAndAttached(textArea);
- }
-
- public void testTextBox() {
- ensureDiv().setInnerHTML("<input type='text' id='foo'></input>");
- TextBox textBox = TextBox.wrap(Document.get().getElementById("foo"));
-
- assertExistsAndAttached(textBox);
- }
-
- public void testDetachOnUnloadTwiceFails() {
- // Testing hosted-mode-only assertion.
- if (!GWT.isScript()) {
- try {
- // Trying to pass the same widget to RootPanel.detachOnUnload() twice
- // should fail an assertion (the first call is implicit through
- // Anchor.wrap()).
- ensureDiv().setInnerHTML(
- "<a id='foo' href='" + TEST_URL + "'>myAnchor</a>");
- Anchor a = Anchor.wrap(Document.get().getElementById("foo")); // pass
- RootPanel.detachOnWindowClose(a); // fail
- fail("Expected assertion failure calling detachOnLoad() twice");
- } catch (AssertionError e) {
- }
- }
- }
-
+ /**
+ * Tests that {@link RootPanel#detachNow(Widget)} can only be called once per
+ * widget.
+ */
public void testDetachNowTwiceFails() {
// Testing hosted-mode-only assertion.
if (!GWT.isScript()) {
@@ -198,6 +78,245 @@
}
}
+ /**
+ * Tests that {@link RootPanel#detachOnWindowClose(Widget)} can only be called
+ * once per widget.
+ */
+ public void testDetachOnWindowCloseTwiceFails() {
+ // Testing hosted-mode-only assertion.
+ if (!GWT.isScript()) {
+ try {
+ // Trying to pass the same widget to RootPanel.detachOnUnload() twice
+ // should fail an assertion (the first call is implicit through
+ // Anchor.wrap()).
+ ensureDiv().setInnerHTML(
+ "<a id='foo' href='" + TEST_URL + "'>myAnchor</a>");
+ Anchor a = Anchor.wrap(Document.get().getElementById("foo")); // pass
+ RootPanel.detachOnWindowClose(a); // fail
+ fail("Expected assertion failure calling detachOnLoad() twice");
+ } catch (AssertionError e) {
+ }
+ }
+ }
+
+ /**
+ * Tests {@link FileUpload#wrap(Element)}.
+ */
+ public void testFileUpload() {
+ ensureDiv().setInnerHTML("<input type='file' id='foo'>myInput</input>");
+ FileUpload upload = FileUpload.wrap(Document.get().getElementById("foo"));
+
+ assertExistsAndAttached(upload);
+ }
+
+ /**
+ * Tests {@link FormPanel#wrap(Element)}.
+ */
+ public void testFormPanel() {
+ ensureDiv().setInnerHTML("<form id='foo'></form>");
+ FormPanel formPanel = FormPanel.wrap(Document.get().getElementById("foo"));
+
+ assertExistsAndAttached(formPanel);
+ }
+
+ /**
+ * Tests {@link Frame#wrap(Element)}.
+ */
+ public void testFrame() {
+ ensureDiv().setInnerHTML("<iframe id='foo'>myFrame</iframe>");
+ Frame frame = Frame.wrap(Document.get().getElementById("foo"));
+
+ assertExistsAndAttached(frame);
+ }
+
+ /**
+ * Tests {@link Hidden#wrap(Element)}.
+ */
+ public void testHidden() {
+ ensureDiv().setInnerHTML("<input type='hidden' id='foo'></input>");
+ Hidden hidden = Hidden.wrap(Document.get().getElementById("foo"));
+
+ assertExistsAndAttached(hidden);
+ }
+
+ /**
+ * Tests {@link HTML#wrap(Element)}.
+ */
+ public void testHTML() {
+ ensureDiv().setInnerHTML("<div id='foo'>myHTML</div>");
+ HTML html = HTML.wrap(Document.get().getElementById("foo"));
+
+ assertExistsAndAttached(html);
+ assertEquals("myHTML", html.getHTML());
+ }
+
+ /**
+ * Tests {@link Image#wrap(Element)}.
+ */
+ public void testImage() {
+ ensureDiv().setInnerHTML("<img id='foo' src='" + IMG_URL + "'>");
+ Image image = Image.wrap(Document.get().getElementById("foo"));
+
+ assertExistsAndAttached(image);
+ assertEquals(IMG_URL, image.getUrl());
+ }
+
+ /**
+ * Tests {@link InlineHTML#wrap(Element)}.
+ */
+ public void testInlineHTML() {
+ ensureDiv().setInnerHTML("<span id='foo'>myInlineHTML</span>");
+ InlineHTML html = InlineHTML.wrap(Document.get().getElementById("foo"));
+
+ assertExistsAndAttached(html);
+ assertEquals("myInlineHTML", html.getHTML());
+ }
+
+ /**
+ * Tests {@link InlineLabel#wrap(Element)}.
+ */
+ public void testInlineLabel() {
+ ensureDiv().setInnerHTML("<span id='foo'>myInlineLabel</span>");
+ InlineLabel label = InlineLabel.wrap(Document.get().getElementById("foo"));
+
+ assertExistsAndAttached(label);
+ assertEquals("myInlineLabel", label.getText());
+ }
+
+ /**
+ * Tests {@link Label#wrap(Element)}.
+ */
+ public void testLabel() {
+ ensureDiv().setInnerHTML("<div id='foo'>myLabel</div>");
+ Label label = Label.wrap(Document.get().getElementById("foo"));
+
+ assertExistsAndAttached(label);
+ assertEquals("myLabel", label.getText());
+ }
+
+ /**
+ * Tests {@link ListBox#wrap(Element)}.
+ */
+ public void testListBox() {
+ ensureDiv().setInnerHTML("<select id='foo'></select>");
+ ListBox listBox = ListBox.wrap(Document.get().getElementById("foo"));
+
+ assertExistsAndAttached(listBox);
+ }
+
+ /**
+ * Tests that all widgets passed to
+ * {@link RootPanel#detachOnWindowClose(Widget)} are cleaned up properly when
+ * the window is unloaded, regardless of whether their associated elements are
+ * still in the DOM or not.
+ */
+ public void testOnUnloadDetachesAllWidgets() {
+ // Testing hosted-mode-only assertion.
+ if (!GWT.isScript()) {
+ ensureDiv().setInnerHTML(
+ "<a id='foo' href='" + TEST_URL + "'>myAnchor</a>"
+ + "<a id='bar' href='" + TEST_URL + "'>myOtherAnchor</a>");
+
+ // Wrap one widget that will be left in the DOM normally.
+ Element fooElem = Document.get().getElementById("foo");
+ Anchor fooAnchor = Anchor.wrap(fooElem);
+
+ // Wrap another widget and remove its element from the DOM.
+ Element barElem = Document.get().getElementById("bar");
+ Anchor barAnchor = Anchor.wrap(barElem);
+ barElem.getParentElement().removeChild(barElem);
+
+ // Fake an unload by telling the RootPanel to go ahead and detach all
+ // of its widgets.
+ RootPanel.detachWidgets();
+
+ // Now make sure that both widgets were detached properly.
+ assertFalse("fooAnchor should have been detached", fooAnchor.isAttached());
+ assertFalse("barAnchor should have been detached", barAnchor.isAttached());
+ }
+ }
+
+ /**
+ * Tests {@link PasswordTextBox#wrap(Element)}.
+ */
+ public void testPasswordTextBox() {
+ ensureDiv().setInnerHTML("<input type='password' id='foo'></input>");
+ PasswordTextBox textBox = PasswordTextBox.wrap(Document.get().getElementById(
+ "foo"));
+
+ assertExistsAndAttached(textBox);
+ }
+
+ /**
+ * Tests {@link SimpleCheckBox#wrap(Element)}.
+ */
+ public void testSimpleCheckBox() {
+ ensureDiv().setInnerHTML("<input type='checkbox' id='foo'></input>");
+ SimpleCheckBox checkBox = SimpleCheckBox.wrap(Document.get().getElementById(
+ "foo"));
+
+ assertExistsAndAttached(checkBox);
+ }
+
+ /**
+ * Tests {@link SimpleRadioButton#wrap(Element)}.
+ */
+ public void testSimpleRadioButton() {
+ ensureDiv().setInnerHTML("<input type='radio' id='foo'></input>");
+ SimpleRadioButton radio = SimpleRadioButton.wrap(Document.get().getElementById(
+ "foo"));
+
+ assertExistsAndAttached(radio);
+ }
+
+ /**
+ * Tests {@link TextArea#wrap(Element)}.
+ */
+ public void testTextArea() {
+ ensureDiv().setInnerHTML("<textarea rows='1' cols='1' id='foo'></textarea>");
+ TextArea textArea = TextArea.wrap(Document.get().getElementById("foo"));
+
+ assertExistsAndAttached(textArea);
+ }
+
+ /**
+ * Tests {@link TextBox#wrap(Element)}.
+ */
+ public void testTextBox() {
+ ensureDiv().setInnerHTML("<input type='text' id='foo'></input>");
+ TextBox textBox = TextBox.wrap(Document.get().getElementById("foo"));
+
+ assertExistsAndAttached(textBox);
+ }
+
+ /**
+ * Tests that wrapping an element that is already a child of an existing
+ * widget's element fails.
+ */
+ public void testWrappingChildElementFails() {
+ // Testing hosted-mode-only assertion.
+ if (!GWT.isScript()) {
+ try {
+ // Create a panel that contains HTML with a unique id, which we're
+ // going to try and wrap below.
+ FlowPanel p = new FlowPanel();
+ RootPanel.get().add(p);
+ p.add(new HTML("<a id='twcef_id'>foo</a>"));
+
+ // Get the element and try to wrap it.
+ Element unwrappableElement = Document.get().getElementById("twcef_id");
+ Anchor.wrap(unwrappableElement);
+ fail("Attempting to wrap the above element should have failed.");
+ } catch (AssertionError e) {
+ // Expected error.
+ }
+ }
+ }
+
+ /**
+ * Tests that wrap() may only be called on elements that are already attached
+ * to the DOM.
+ */
public void testWrapUnattachedFails() {
// Testing hosted-mode-only assertion.
if (!GWT.isScript()) {
@@ -214,28 +333,6 @@
}
}
- public void testOnUnloadAssertions() {
- // Testing hosted-mode-only assertion.
- if (!GWT.isScript()) {
- try {
- // When a wrap()ed element is detached from the document without being
- // properly unwrapped, there will be an assertion to catch this run on
- // unload.
- ensureDiv().setInnerHTML(
- "<a id='foo' href='" + TEST_URL + "'>myAnchor</a>");
- Element aElem = Document.get().getElementById("foo");
- Anchor.wrap(aElem);
- aElem.getParentElement().removeChild(aElem);
-
- // Fake an unload by telling the RootPanel to go ahead and detach all
- // of its widgets.
- RootPanel.detachWidgets();
- fail("Assertion expected for orphaned wrap()ed widgets");
- } catch (AssertionError e) {
- }
- }
- }
-
private void assertExistsAndAttached(Widget widget) {
assertNotNull(widget);
assertTrue(widget.isAttached());
diff --git a/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java b/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java
index 8d6986d..9e7f8ac 100644
--- a/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java
@@ -15,10 +15,9 @@
*/
package com.google.gwt.user.client.ui;
+import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Node;
import com.google.gwt.junit.client.GWTTestCase;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
/**
* Tests the HTMLPanel widget.
@@ -44,10 +43,8 @@
p.add(labelA, "a");
p.add(labelB, "b");
// Ensure that both Label's have the correct parent.
- assertEquals("a", DOM.getElementAttribute(
- DOM.getParent(labelA.getElement()), "id"));
- assertEquals("b", DOM.getElementAttribute(
- DOM.getParent(labelB.getElement()), "id"));
+ assertEquals("a", labelA.getElement().getParentElement().getId());
+ assertEquals("b", labelB.getElement().getParentElement().getId());
}
/**
@@ -70,9 +67,12 @@
// If all goes well, the HTMLPanel's element should still be properly
// connected to the SimplePanel's element.
- assertTrue(DOM.isOrHasChild(sp.getElement(), p.getElement()));
+ assertTrue(sp.getElement().isOrHasChild(p.getElement()));
}
+ /**
+ * Tests child attachment order using {@link HasWidgetsTester}.
+ */
public void testAttachDetachOrder() {
HTMLPanel p = new HTMLPanel("<div id='w00t'></div>");
HasWidgetsTester.testAll(p, new Adder());
@@ -96,9 +96,9 @@
hp.add(new Button("foo"), "foo");
- assertTrue(DOM.isOrHasChild(fp.getElement(), hp.getElement()));
- assertTrue(DOM.getNextSibling(ba.getElement()) == hp.getElement());
- assertTrue(DOM.getNextSibling(hp.getElement()) == bb.getElement());
+ assertTrue(fp.getElement().isOrHasChild(hp.getElement()));
+ assertTrue(ba.getElement().getNextSibling() == hp.getElement());
+ assertTrue(hp.getElement().getNextSibling() == bb.getElement());
}
/**
@@ -119,6 +119,10 @@
assertEquals("bar", next.getNodeValue());
}
+ /**
+ * Ensure that {@link HTMLPanel#getElementById(String)} behaves properly in
+ * both attached and unattached states.
+ */
public void testGetElementById() {
HTMLPanel hp = new HTMLPanel("foo<div id='toFind'>bar</div>baz");
@@ -130,4 +134,27 @@
// Make sure we got the same element in both cases.
assertEquals(elem0, elem1);
}
+
+ /**
+ * Tests that the HTMLPanel's element is not moved from its original location
+ * when {@link HTMLPanel#add(Widget, String)} is called on it while it is
+ * unattached.
+ */
+ public void testElementIsUnmoved() {
+ HTMLPanel unattached = new HTMLPanel("<div id='unattached'></div>");
+ HTMLPanel attached = new HTMLPanel("<div id='attached'></div>");
+
+ RootPanel.get().add(attached);
+
+ Element unattachedParentElem = unattached.getElement().getParentElement();
+ Element attachedParentElem = attached.getElement().getParentElement();
+
+ unattached.add(new Button("unattached"), "unattached");
+ attached.add(new Button("attached"), "attached");
+
+ assertEquals("Unattached's parent element should be unaffected",
+ unattachedParentElem, unattached.getElement().getParentElement());
+ assertEquals("Unattached's parent element should be unaffected",
+ attachedParentElem, attached.getElement().getParentElement());
+ }
}
diff --git a/user/test/com/google/gwt/user/client/ui/ImageTest.java b/user/test/com/google/gwt/user/client/ui/ImageTest.java
index 2201dd2..f4b222e 100644
--- a/user/test/com/google/gwt/user/client/ui/ImageTest.java
+++ b/user/test/com/google/gwt/user/client/ui/ImageTest.java
@@ -1,12 +1,12 @@
/*
* Copyright 2008 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.client.ui;
+import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.event.dom.client.ErrorEvent;
import com.google.gwt.event.dom.client.ErrorHandler;
@@ -26,6 +27,7 @@
* Tests for the Image widget. Images in both clipped mode and unclipped mode
* are tested, along with the transitions between the two modes.
*/
+@SuppressWarnings("deprecation")
public class ImageTest extends GWTTestCase {
private static class TestErrorHandler implements ErrorHandler {
private Image image;
@@ -41,17 +43,13 @@
@Deprecated
private abstract static class TestLoadListener implements LoadListener {
- private Image image;
private boolean finished = false;
+ private Image image;
public TestLoadListener(Image image) {
this.image = image;
}
- public void onError(Widget sender) {
- fail("The image " + image.getUrl() + " failed to load.");
- }
-
/**
* Mark the test as finished.
*/
@@ -65,32 +63,72 @@
public boolean isFinished() {
return finished;
}
+
+ public void onError(Widget sender) {
+ fail("The image " + image.getUrl() + " failed to load.");
+ }
}
-
+
/**
* Helper method that allows us to 'peek' at the private <code>state</code>
* field in the Image object, and call the <code>state.getStateName()</code>
* method.
- *
+ *
* @param image The image instance
- * @return "unclipped" if image is in the unclipped state, or
- * "clipped" if the image is in the clipped state
+ * @return "unclipped" if image is in the unclipped state, or "clipped" if the
+ * image is in the clipped state
*/
public static native String getCurrentImageStateName(Image image) /*-{
var imgState = image.@com.google.gwt.user.client.ui.Image::state;
return imgState.@com.google.gwt.user.client.ui.Image.State::getStateName() ();
}-*/;
- @Override
- public String getModuleName() {
- return "com.google.gwt.user.UserTest";
+ private int firedError;
+
+ private int firedLoad;
+
+ /**
+ * Tests the transition from the clipped state to the unclipped state.
+ *
+ * Disabled because of issue #863 & #864. It fails intermittently in linux
+ * hosted mode tests.
+ */
+ public void disabledTestChangeClippedImageToUnclipped() {
+ final Image image = new Image("counting-forwards.png", 12, 13, 8, 8);
+ assertEquals("clipped", getCurrentImageStateName(image));
+
+ image.addLoadListener(new LoadListener() {
+ private int onLoadEventCount = 0;
+
+ public void onError(Widget sender) {
+ fail("The image " + ((Image) sender).getUrl() + " failed to load.");
+ }
+
+ public void onLoad(Widget sender) {
+ ++onLoadEventCount;
+ if (onLoadEventCount == 1) { // Set the url after the first image loads
+ image.setUrl("counting-forwards.png");
+ } else if (onLoadEventCount == 2) {
+ assertEquals(0, image.getOriginLeft());
+ assertEquals(0, image.getOriginTop());
+ assertEquals(32, image.getWidth());
+ assertEquals(32, image.getHeight());
+ assertEquals("unclipped", getCurrentImageStateName(image));
+ finishTest();
+ }
+ }
+ });
+
+ delayTestFinish(5000);
+ RootPanel.get().add(image);
}
/**
- * Tests the transition from the unclipped state to the clipped state
+ * Tests the transition from the unclipped state to the clipped state.
+ *
+ * Disabled because of issue #863.
*/
- /* This test is commented out because of issue #863
- public void testChangeImageToClipped() {
+ public void disabledTestChangeImageToClipped() {
final Image image = new Image("counting-forwards.png");
assertEquals("unclipped", getCurrentImageStateName(image));
@@ -117,56 +155,16 @@
}
});
- RootPanel.get().add(image);
-
delayTestFinish(5000);
+ RootPanel.get().add(image);
}
- */
/**
- * Tests the transition from the clipped state to the unclipped state.
+ * Tests the creation of an image in unclipped mode.
+ *
+ * Disabled because of issue #863 & #864.
*/
- /* This test is commented out because of issue #863 & #864
- It fails intermittently in linux hosted mode tests.
- public void testChangeClippedImageToUnclipped() {
- final Image image = new Image("counting-forwards.png",
- 12, 13, 8, 8);
- assertEquals("clipped", getCurrentImageStateName(image));
-
- image.addLoadListener(new LoadListener() {
- private int onLoadEventCount = 0;
-
- public void onError(Widget sender) {
- fail("The image " + ((Image) sender).getUrl() + " failed to load.");
- }
-
- public void onLoad(Widget sender) {
- ++onLoadEventCount;
- if (onLoadEventCount == 1) {
- // Set the url after the first image loads
- image.setUrl("counting-forwards.png");
- } else if (onLoadEventCount == 2) {
- assertEquals(0, image.getOriginLeft());
- assertEquals(0, image.getOriginTop());
- assertEquals(32, image.getWidth());
- assertEquals(32, image.getHeight());
- assertEquals("unclipped", getCurrentImageStateName(image));
- finishTest();
- }
- }
- });
-
- RootPanel.get().add(image);
-
- delayTestFinish(5000);
- }
- */
-
- /**
- * Tests the creation of an image in unclipped mode
- */
- /* This test is commented out because of issue #864 and issue #863
- public void testCreateImage() {
+ public void disabledTestCreateImage() {
final Image image = new Image("counting-forwards.png");
image.addLoadListener(new LoadListener() {
@@ -185,67 +183,21 @@
}
});
+ delayTestFinish(5000);
RootPanel.get().add(image);
assertEquals(0, image.getOriginLeft());
assertEquals(0, image.getOriginTop());
assertEquals("unclipped", getCurrentImageStateName(image));
-
- delayTestFinish(5000);
- }
- */
-
- /**
- * Tests the creation of an image in clipped mode.
- */
- public void testCreateClippedImage() {
- final Image image = new Image("counting-forwards.png",
- 16, 16, 16, 16);
-
- final TestLoadListener listener = new TestLoadListener(image) {
- private int onLoadEventCount = 0;
-
- public void onLoad(Widget sender) {
- if (++onLoadEventCount == 1) {
- assertEquals(16, image.getWidth());
- assertEquals(16, image.getHeight());
- finish();
- }
- }
- };
- image.addLoadListener(listener);
-
- image.addLoadHandler(new LoadHandler() {
- private int onLoadEventCount = 0;
-
- public void onLoad(LoadEvent event) {
- if (++onLoadEventCount == 1) {
- assertEquals(16, image.getWidth());
- assertEquals(16, image.getHeight());
- if (listener.isFinished()) {
- finishTest();
- } else {
- fail("Listener did not fire first");
- }
- }
- }
- });
- image.addErrorHandler(new TestErrorHandler(image));
-
- RootPanel.get().add(image);
- assertEquals(16, image.getOriginLeft());
- assertEquals(16, image.getOriginTop());
- assertEquals("clipped", getCurrentImageStateName(image));
-
- delayTestFinish(5000);
}
/**
- * Tests the firing of onload events when
- * {@link com.google.gwt.user.client.ui.Image#setUrl(String)}
- * is called on an unclipped image.
+ * Tests the firing of onload events when
+ * {@link com.google.gwt.user.client.ui.Image#setUrl(String)} is called on an
+ * unclipped image.
+ *
+ * Disabled because of issue #863
*/
- /* This test has been commented out because of issue #863
- public void testSetUrlAndLoadEventsOnUnclippedImage() {
+ public void disabledTestSetUrlAndLoadEventsOnUnclippedImage() {
final Image image = new Image();
image.addLoadListener(new LoadListener() {
@@ -264,12 +216,122 @@
}
});
+ delayTestFinish(5000);
RootPanel.get().add(image);
image.setUrl("counting-backwards.png");
+ }
+
+ /**
+ * Tests the behavior of
+ * <code>setUrlAndVisibleRect(String, int, int, int, int)</code> method on
+ * an unclipped image, which causes a state transition to the clipped state.
+ *
+ * Disabled because of issue #863.
+ */
+ public void disabledTestSetUrlAndVisibleRectOnUnclippedImage() {
+ final Image image = new Image("counting-backwards.png");
+
+ image.addLoadListener(new LoadListener() {
+ private int onLoadEventCount = 0;
+
+ public void onError(Widget sender) {
+ fail("The image " + ((Image) sender).getUrl() + " failed to load.");
+ }
+
+ public void onLoad(Widget sender) {
+ if (getCurrentImageStateName(image).equals("unclipped")) {
+ image.setUrlAndVisibleRect("counting-forwards.png", 0, 16, 16, 16);
+ }
+
+ if (++onLoadEventCount == 2) {
+ assertEquals(0, image.getOriginLeft());
+ assertEquals(16, image.getOriginTop());
+ assertEquals(16, image.getWidth());
+ assertEquals(16, image.getHeight());
+ assertEquals("clipped", getCurrentImageStateName(image));
+ finishTest();
+ }
+ }
+ });
delayTestFinish(5000);
+ RootPanel.get().add(image);
+ assertEquals("unclipped", getCurrentImageStateName(image));
}
- */
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.UserTest";
+ }
+
+ /**
+ * Tests the creation of an image in clipped mode.
+ */
+ public void testCreateClippedImage() {
+ final Image image = new Image("counting-forwards.png", 16, 16, 16, 16);
+
+ final TestLoadListener listener = new TestLoadListener(image) {
+ private int onLoadEventCount = 0;
+
+ public void onLoad(Widget sender) {
+ if (++onLoadEventCount == 1) {
+ assertEquals(16, image.getWidth());
+ assertEquals(16, image.getHeight());
+ finish();
+ }
+ }
+ };
+ image.addLoadListener(listener);
+
+ image.addLoadHandler(new LoadHandler() {
+ private int onLoadEventCount = 0;
+
+ public void onLoad(LoadEvent event) {
+ if (++onLoadEventCount == 1) {
+ assertEquals(16, image.getWidth());
+ assertEquals(16, image.getHeight());
+ if (listener.isFinished()) {
+ finishTest();
+ } else {
+ fail("Listener did not fire first");
+ }
+ }
+ }
+ });
+ image.addErrorHandler(new TestErrorHandler(image));
+
+ delayTestFinish(5000);
+ RootPanel.get().add(image);
+ assertEquals(16, image.getOriginLeft());
+ assertEquals(16, image.getOriginTop());
+ assertEquals("clipped", getCurrentImageStateName(image));
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testLoadListenerWiring() {
+ Image im = new Image();
+
+ im.addLoadListener(new LoadListener() {
+
+ public void onError(Widget sender) {
+ ++firedError;
+ }
+
+ public void onLoad(Widget sender) {
+ ++firedLoad;
+ }
+ });
+ im.fireEvent(new LoadEvent() {
+ // Replaced by Joel's event firing when possible.
+ });
+ assertEquals(1, firedLoad);
+ assertEquals(0, firedError);
+ im.fireEvent(new ErrorEvent() {
+ // Replaced by Joel's event firing when possible.
+ });
+ assertEquals(1, firedLoad);
+ assertEquals(1, firedError);
+ }
/**
* Tests the behavior of
@@ -277,8 +339,7 @@
* on a clipped image.
*/
public void testSetUrlAndVisibleRectOnClippedImage() {
- final Image image = new Image("counting-backwards.png",
- 12, 12, 12, 12);
+ final Image image = new Image("counting-backwards.png", 12, 12, 12, 12);
final TestLoadListener listener = new TestLoadListener(image) {
private int onLoadEventCount = 0;
@@ -316,46 +377,13 @@
});
image.addErrorHandler(new TestErrorHandler(image));
+ delayTestFinish(5000);
RootPanel.get().add(image);
assertEquals("clipped", getCurrentImageStateName(image));
- image.setUrlAndVisibleRect("counting-forwards.png",
- 0, 16, 16, 16);
-
- delayTestFinish(5000);
+ image.setUrlAndVisibleRect("counting-forwards.png", 0, 16, 16, 16);
}
/**
- * Tests the behavior of
- * <code>setUrlAndVisibleRect(String, int, int, int, int)</code> method on an
- * unclipped image, which causes a state transition to the clipped state.
- */
- /*
- * This test has been commented out because of issue #863 public void
- * testSetUrlAndVisibleRectOnUnclippedImage() { final Image image = new
- * Image("counting-backwards.png");
- *
- * image.addLoadListener(new LoadListener() { private int onLoadEventCount =
- * 0;
- *
- * public void onError(Widget sender) { fail("The image " + ((Image)
- * sender).getUrl() + " failed to load."); }
- *
- * public void onLoad(Widget sender) { if
- * (getCurrentImageStateName(image).equals("unclipped")) {
- * image.setUrlAndVisibleRect("counting-forwards.png", 0, 16, 16, 16); }
- *
- * if (++onLoadEventCount == 2) { assertEquals(0, image.getOriginLeft());
- * assertEquals(16, image.getOriginTop()); assertEquals(16, image.getWidth());
- * assertEquals(16, image.getHeight()); assertEquals("clipped",
- * getCurrentImageStateName(image)); finishTest(); } } });
- *
- * RootPanel.get().add(image); assertEquals("unclipped",
- * getCurrentImageStateName(image));
- *
- * delayTestFinish(5000); }
- */
-
- /**
* Tests the firing of onload events when calling
* {@link com.google.gwt.user.client.ui.Image#setVisibleRect(int,int,int,int)}
* on a clipped image.
@@ -389,13 +417,12 @@
});
image.addErrorHandler(new TestErrorHandler(image));
+ delayTestFinish(5000);
RootPanel.get().add(image);
image.setVisibleRect(0, 0, 16, 16);
image.setVisibleRect(0, 0, 16, 16);
image.setVisibleRect(16, 0, 16, 16);
image.setVisibleRect(16, 8, 8, 8);
-
- delayTestFinish(5000);
}
/**
@@ -404,8 +431,10 @@
*/
public void testWrapThenSetUrlAndVisibleRect() {
String uid = Document.get().createUniqueId();
- HTML html = new HTML("<img id='" + uid + "' src='counting-backwards.png' width='16' height='16'>");
- RootPanel.get().add(html);
+ DivElement div = Document.get().createDivElement();
+ div.setInnerHTML("<img id='" + uid
+ + "' src='counting-backwards.png' width='16' height='16'>");
+ Document.get().getBody().appendChild(div);
final Image image = Image.wrap(Document.get().getElementById(uid));
assertEquals(0, image.getOriginLeft());
@@ -421,34 +450,4 @@
assertEquals(16, image.getHeight());
assertEquals("clipped", getCurrentImageStateName(image));
}
-
-
- private int firedLoad;
- private int firedError;
- @SuppressWarnings("deprecation")
- public void testLoadListenerWiring() {
- Image im = new Image();
-
- im.addLoadListener(new LoadListener() {
-
- public void onError(Widget sender) {
- ++firedError;
- }
-
- public void onLoad(Widget sender) {
- ++firedLoad;
- }
- });
- im.fireEvent(new LoadEvent() {
- // Replaced by Joel's event firing when possible.
- });
- assertEquals(1, firedLoad);
- assertEquals(0, firedError);
- im.fireEvent(new ErrorEvent() {
- // Replaced by Joel's event firing when possible.
- });
- assertEquals(1, firedLoad);
- assertEquals(1, firedError);
- }
-
}
diff --git a/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java b/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
index 566c50e..c223773 100644
--- a/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
+++ b/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
@@ -15,15 +15,29 @@
*/
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.dom.client.InputElement;
+import com.google.gwt.dom.client.LabelElement;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
/**
* Tests the RadioButton class.
*/
public class RadioButtonTest extends GWTTestCase {
+ private static class Changeable implements ValueChangeHandler<Boolean> {
+ Boolean received;
+
+ public void onValueChange(ValueChangeEvent<Boolean> event) {
+ received = event.getValue();
+ }
+ }
+
@Override
public String getModuleName() {
return "com.google.gwt.user.DebugTest";
@@ -33,7 +47,7 @@
RadioButton radio = new RadioButton("myName", "myLabel");
// We need to replace the input element so we can keep a handle to it
- Element newInput = DOM.createInputRadio("MyName");
+ com.google.gwt.user.client.Element newInput = DOM.createInputRadio("MyName");
radio.replaceInputElement(newInput);
radio.ensureDebugId("myRadio");
@@ -45,6 +59,39 @@
}
/**
+ * Test the name and grouping methods.
+ */
+ public void testGrouping() {
+ // Create some radio buttons
+ RadioButton r1 = new RadioButton("group1", "Radio 1");
+ RadioButton r2 = new RadioButton("group1", "Radio 2");
+ RadioButton r3 = new RadioButton("group2", "Radio 3");
+ RootPanel.get().add(r1);
+ RootPanel.get().add(r2);
+ RootPanel.get().add(r3);
+
+ // Check one button in each group
+ r2.setValue(true);
+ r3.setValue(true);
+
+ // Move a button over
+ r2.setName("group2");
+
+ // Check that the correct buttons are checked
+ assertTrue(r2.getValue());
+ assertFalse(r3.getValue());
+
+ r1.setValue(true);
+ assertTrue(r1.getValue());
+ assertTrue(r2.getValue());
+
+ r3.setValue(true);
+ assertTrue(r1.getValue());
+ assertFalse(r2.getValue());
+ assertTrue(r3.getValue());
+ }
+
+ /**
* Test the name and grouping methods via deprecated calls.
*/
@SuppressWarnings("deprecation")
@@ -77,39 +124,6 @@
assertFalse(r2.isChecked());
assertTrue(r3.isChecked());
}
-
- /**
- * Test the name and grouping methods.
- */
- public void testGrouping() {
- // Create some radio buttons
- RadioButton r1 = new RadioButton("group1", "Radio 1");
- RadioButton r2 = new RadioButton("group1", "Radio 2");
- RadioButton r3 = new RadioButton("group2", "Radio 3");
- RootPanel.get().add(r1);
- RootPanel.get().add(r2);
- RootPanel.get().add(r3);
-
- // Check one button in each group
- r2.setValue(true);
- r3.setValue(true);
-
- // Move a button over
- r2.setName("group2");
-
- // Check that the correct buttons are checked
- assertTrue(r2.getValue());
- assertFalse(r3.getValue());
-
- r1.setValue(true);
- assertTrue(r1.getValue());
- assertTrue(r2.getValue());
-
- r3.setValue(true);
- assertTrue(r1.getValue());
- assertFalse(r2.getValue());
- assertTrue(r3.getValue());
- }
/**
* Ensures that the element order doesn't get reversed when the radio's
@@ -128,4 +142,95 @@
assertEquals("input", firstChild.getTagName().toLowerCase());
assertEquals("label", secondChild.getTagName().toLowerCase());
}
+
+// TODO: Re-enable these tests when we figure out how to make them work
+// properly on IE (which has the unfortunate property of not passing
+// synthesized events on to native controls, keeping the clicks created by
+// these tests from actually affecting the radio buttons' states).
+//
+// public void testValueChangeViaClick() {
+// RadioButton r1 = new RadioButton("group1", "Radio 1");
+// RadioButton r2 = new RadioButton("group1", "Radio 2");
+// RootPanel.get().add(r1);
+// RootPanel.get().add(r2);
+// r1.setValue(true);
+//
+// Changeable c1 = new Changeable();
+// r1.addValueChangeHandler(c1);
+//
+// Changeable c2 = new Changeable();
+// r2.addValueChangeHandler(c2);
+//
+// // Brittle, but there's no public access
+// InputElement r1Radio = getRadioElement(r1);
+// InputElement r2Radio = getRadioElement(r2);
+//
+// doClick(r1Radio);
+// assertEquals(null, c1.received);
+// assertEquals(null, c2.received);
+//
+// doClick(r2Radio);
+// assertEquals(null, c1.received);
+// assertEquals(Boolean.TRUE, c2.received);
+// c2.received = null;
+//
+// doClick(r1Radio);
+// assertEquals(Boolean.TRUE, c1.received);
+// assertEquals(null, c2.received);
+// }
+//
+// public void testValueChangeViaLabelClick() {
+// RadioButton r1 = new RadioButton("group1", "Radio 1");
+// RadioButton r2 = new RadioButton("group1", "Radio 2");
+// RootPanel.get().add(r1);
+// RootPanel.get().add(r2);
+// r1.setValue(true);
+//
+// Changeable c1 = new Changeable();
+// r1.addValueChangeHandler(c1);
+//
+// Changeable c2 = new Changeable();
+// r2.addValueChangeHandler(c2);
+//
+// LabelElement r1Label = getLabelElement(r1);
+// LabelElement r2Label = getLabelElement(r2);
+//
+// doClick(r1Label);
+// assertEquals(null, c1.received);
+// assertEquals(null, c2.received);
+//
+// doClick(r2Label);
+// assertEquals(null, c1.received);
+// assertEquals(Boolean.TRUE, c2.received);
+// c2.received = null;
+//
+// doClick(r1Label);
+// assertEquals(Boolean.TRUE, c1.received);
+// assertEquals(null, c2.received);
+// }
+//
+// private void doClick(Element elm) {
+// NativeEvent e = Document.get().createMouseDownEvent(0, 25, 25, 25, 25,
+// false, false, false, false, NativeEvent.BUTTON_LEFT);
+// elm.dispatchEvent(e);
+//
+// e = Document.get().createMouseUpEvent(0, 25, 25, 25, 25, false, false,
+// false, false, NativeEvent.BUTTON_LEFT);
+// elm.dispatchEvent(e);
+//
+// e = Document.get().createClickEvent(0, 25, 25, 25, 25, false, false, false,
+// false);
+// elm.dispatchEvent(e);
+// }
+//
+// private LabelElement getLabelElement(RadioButton radioButton) {
+// LabelElement r1Label = LabelElement.as(Element.as(getRadioElement(
+// radioButton).getNextSiblingElement()));
+// return r1Label;
+// }
+//
+// private InputElement getRadioElement(RadioButton radioButton) {
+// InputElement r1Radio = InputElement.as(Element.as(radioButton.getElement().getFirstChild()));
+// return r1Radio;
+// }
}
diff --git a/user/test/com/google/gwt/user/client/ui/RootPanelTest.java b/user/test/com/google/gwt/user/client/ui/RootPanelTest.java
new file mode 100644
index 0000000..8d985b4
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/RootPanelTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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
+ * 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.DivElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests {@link RootPanel}.
+ */
+public class RootPanelTest extends GWTTestCase {
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.User";
+ }
+
+ /**
+ * Ensures that {@link RootPanel#get(String)} behaves properly.
+ */
+ public void testGetById() {
+ Document doc = Document.get();
+ DivElement div = doc.createDivElement();
+ doc.getBody().appendChild(div);
+ div.setInnerHTML("<div id='a'></div><div id='b'></div>");
+
+ // You should get the same RootPanel for subsequent calls to get() with the
+ // same id. But you should get *different* RootPanels for calls with
+ // different ids.
+ RootPanel aRoot = RootPanel.get("a");
+ RootPanel bRoot = RootPanel.get("b");
+
+ assertSame(
+ "RootPanel.get() should return the same instancefor the same id",
+ aRoot, RootPanel.get("a"));
+ assertSame(
+ "RootPanel.get() should return the same instancefor the same id",
+ bRoot, RootPanel.get("b"));
+ assertNotSame("RootPanels a and b should be different", aRoot, bRoot);
+
+ // If a RootPanel's element is replaced in the DOM, you should get a
+ // new RootPanel instance if you ask for it again (see issue 1937).
+ Element aElem = doc.getElementById("a");
+ Element newAElem = doc.createDivElement();
+ newAElem.setId("a");
+ aElem.getParentElement().replaceChild(newAElem, aElem);
+
+ RootPanel newARoot = RootPanel.get("a");
+ assertNotSame("New RootPanel should not be same as old", newARoot, aRoot);
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/SuggestBoxTest.java b/user/test/com/google/gwt/user/client/ui/SuggestBoxTest.java
index 96e2f3c..feb84c1 100644
--- a/user/test/com/google/gwt/user/client/ui/SuggestBoxTest.java
+++ b/user/test/com/google/gwt/user/client/ui/SuggestBoxTest.java
@@ -15,6 +15,8 @@
*/
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.junit.client.GWTTestCase;
import java.util.Arrays;
@@ -110,7 +112,31 @@
RootPanel.get().clear();
}
+ public void testWrapUsingStaticWrapMethod() {
+ Element wrapper = Document.get().createTextInputElement();
+ RootPanel.get().getElement().appendChild(wrapper);
+
+ // Use direct wrap method from suggest box.
+ SuggestBox box = SuggestBox.wrap(createOracle(), wrapper);
+ assertTrue(box.isAttached());
+ assertTrue(box.getWidget().getParent() == box);
+ }
+
+ public void testWrapUsingComposite() {
+ // Ensure we can use this with normal composites
+ Element wrapper = Document.get().createTextInputElement();
+ RootPanel.get().getElement().appendChild(wrapper);
+ TextBox b = TextBox.wrap(wrapper);
+ SuggestBox box = new SuggestBox(createOracle(), b);
+ assertTrue(b.getParent() == box);
+ }
+
protected SuggestBox createSuggestBox() {
+ MultiWordSuggestOracle oracle = createOracle();
+ return new SuggestBox(oracle);
+ }
+
+ private MultiWordSuggestOracle createOracle() {
MultiWordSuggestOracle oracle = new MultiWordSuggestOracle();
oracle.add("test");
oracle.add("test1");
@@ -118,6 +144,6 @@
oracle.add("test3");
oracle.add("test4");
oracle.add("john");
- return new SuggestBox(oracle);
+ return oracle;
}
}
diff --git a/user/test/com/google/gwt/user/server/rpc/RPCRequestTest.java b/user/test/com/google/gwt/user/server/rpc/RPCRequestTest.java
index 73bd3fe..5aa9aa9 100644
--- a/user/test/com/google/gwt/user/server/rpc/RPCRequestTest.java
+++ b/user/test/com/google/gwt/user/server/rpc/RPCRequestTest.java
@@ -53,7 +53,6 @@
Object params2[] = new Object[] {"ab\"cde\"fg", 1234};
RPCRequest request2 = new RPCRequest(method, params2, null, 0);
String strRequest2 = request2.toString();
- System.out.println(strRequest2);
assertEquals("com.google.gwt.user.server.rpc.RPCRequestTest$"
+ "MockRequestImplementation.doSomething(\"ab\\\"cde\\\"fg\", 1234)",
strRequest2);