Merging releases/1.6 into trunk.
svn merge -r4511:4604 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
svn merge -r4605:4657 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4659 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/common.ant.xml b/common.ant.xml
index 2b19d63..52d6c5a 100755
--- a/common.ant.xml
+++ b/common.ant.xml
@@ -253,10 +253,12 @@
<element name="sourcepath" implicit="yes" optional="true" />
<sequential>
<taskdef resource="checkstyletask.properties" classpath="${gwt.tools.antlib}/checkstyle-all-4.2.jar;${gwt.build.lib}/gwt-customchecks.jar" />
- <checkstyle config="${gwt.root}/eclipse/settings/code-style/gwt-checkstyle.xml" maxWarnings="0">
+ <checkstyle config="${gwt.root}/eclipse/settings/code-style/gwt-checkstyle.xml" maxErrors="0">
+ <formatter type="xml" toFile="${project.build}/checkstyle_log.xml"/>
<property key="checkstyle.header.file" file="${gwt.root}/eclipse/settings/code-style/google.header" />
<sourcepath />
</checkstyle>
+ <echo message="Checkstyle messages are reported in checkstyle_log.xml located at ${project.build}" />
</sequential>
</macrodef>
diff --git a/dev/core/src/com/google/gwt/dev/Compiler.java b/dev/core/src/com/google/gwt/dev/Compiler.java
index d41debd..4a4759c 100644
--- a/dev/core/src/com/google/gwt/dev/Compiler.java
+++ b/dev/core/src/com/google/gwt/dev/Compiler.java
@@ -23,6 +23,9 @@
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.util.FileBackedObject;
+import com.google.gwt.dev.shell.CheckForUpdates;
+import com.google.gwt.dev.shell.PlatformSpecific;
+import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;
@@ -34,6 +37,7 @@
import java.io.File;
import java.io.IOException;
import java.util.List;
+import java.util.concurrent.FutureTask;
/**
* The main executable entry point for the GWT Java to JavaScript compiler.
@@ -124,7 +128,16 @@
if (new ArgProcessor(options).processArgs(args)) {
CompileTask task = new CompileTask() {
public boolean run(TreeLogger logger) throws UnableToCompleteException {
- return new Compiler(options).run(logger);
+ FutureTask<UpdateResult> updater = null;
+ if (!options.isUpdateCheckDisabled()) {
+ updater = PlatformSpecific.checkForUpdatesInBackgroundThread(logger,
+ CheckForUpdates.ONE_DAY);
+ }
+ boolean success = new Compiler(options).run(logger);
+ if (success) {
+ PlatformSpecific.logUpdateAvailable(logger, updater);
+ }
+ return success;
}
};
if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
index 0c1097b..913785d 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -22,6 +22,9 @@
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.util.FileBackedObject;
+import com.google.gwt.dev.shell.CheckForUpdates;
+import com.google.gwt.dev.shell.PlatformSpecific;
+import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerLocalWorkers;
@@ -33,6 +36,7 @@
import java.io.File;
import java.io.IOException;
import java.util.List;
+import java.util.concurrent.FutureTask;
/**
* The main executable entry point for the GWT Java to JavaScript compiler.
@@ -111,7 +115,16 @@
if (new ArgProcessor(options).processArgs(args)) {
CompileTask task = new CompileTask() {
public boolean run(TreeLogger logger) throws UnableToCompleteException {
- return new GWTCompiler(options).run(logger);
+ FutureTask<UpdateResult> updater = null;
+ if (!options.isUpdateCheckDisabled()) {
+ updater = PlatformSpecific.checkForUpdatesInBackgroundThread(logger,
+ CheckForUpdates.ONE_DAY);
+ }
+ boolean success = new GWTCompiler(options).run(logger);
+ if (success) {
+ PlatformSpecific.logUpdateAvailable(logger, updater);
+ }
+ return success;
}
};
if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index 338815e..a3dfdd6 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -166,6 +166,14 @@
return new GWTCompilerOptionsImpl(options);
}
+ public WebServerRestart hasWebServer() {
+ return WebServerRestart.NONE;
+ }
+
+ public void restartServer(TreeLogger logger) throws UnableToCompleteException {
+ // Unimplemented.
+ }
+
public void setCompilerOptions(CompilerOptions options) {
this.options.copyFrom(options);
}
@@ -238,6 +246,11 @@
}
@Override
+ protected String getTitleText() {
+ return "Google Web Toolkit Development Shell";
+ }
+
+ @Override
protected boolean initModule(String moduleName) {
/*
* Not used in legacy mode due to GWTShellServlet playing this role.
diff --git a/dev/core/src/com/google/gwt/dev/HostedMode.java b/dev/core/src/com/google/gwt/dev/HostedMode.java
index c5da1d8..bfd5d15 100644
--- a/dev/core/src/com/google/gwt/dev/HostedMode.java
+++ b/dev/core/src/com/google/gwt/dev/HostedMode.java
@@ -281,6 +281,15 @@
HostedMode() {
}
+ public WebServerRestart hasWebServer() {
+ return options.isNoServer() ? WebServerRestart.DISABLED
+ : WebServerRestart.ENABLED;
+ }
+
+ public void restartServer(TreeLogger logger) throws UnableToCompleteException {
+ server.refresh();
+ }
+
@Override
protected void compile(TreeLogger logger) throws UnableToCompleteException {
CompilerOptions newOptions = new CompilerOptionsImpl(options);
@@ -391,6 +400,11 @@
}
@Override
+ protected String getTitleText() {
+ return "Google Web Toolkit Hosted Mode";
+ }
+
+ @Override
protected boolean initModule(String moduleName) {
ModuleDef module = modulesByName.get(moduleName);
if (module == null) {
@@ -432,8 +446,8 @@
*
* @param logger the logger to use
* @param module the module to link
- * @param includePublicFiles if <code>true</code>, include public files in the
- * link, otherwise do not include them
+ * @param includePublicFiles if <code>true</code>, include public files in
+ * the link, otherwise do not include them
* @throws UnableToCompleteException
*/
private void link(TreeLogger logger, ModuleDef module)
diff --git a/dev/core/src/com/google/gwt/dev/HostedModeBase.java b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
index 559e5d1..92b24f1 100644
--- a/dev/core/src/com/google/gwt/dev/HostedModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
@@ -27,7 +27,9 @@
import com.google.gwt.dev.shell.BrowserWidgetHost;
import com.google.gwt.dev.shell.BrowserWidgetHostChecker;
import com.google.gwt.dev.shell.BrowserWindowController;
+import com.google.gwt.dev.shell.CheckForUpdates;
import com.google.gwt.dev.shell.ModuleSpaceHost;
+import com.google.gwt.dev.shell.PlatformSpecific;
import com.google.gwt.dev.shell.ShellModuleSpaceHost;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
@@ -40,9 +42,6 @@
import com.google.gwt.dev.util.arg.OptionLogLevel;
import com.google.gwt.util.tools.ArgHandlerFlag;
import com.google.gwt.util.tools.ArgHandlerString;
-import com.google.gwt.util.tools.ToolBase;
-
-import org.eclipse.swt.widgets.Display;
import java.io.File;
import java.util.ArrayList;
@@ -324,14 +323,6 @@
}
}
- static {
- // Force ToolBase to clinit, which causes SWT stuff to happen.
- new ToolBase() {
- };
- // Correct menu on Mac OS X
- Display.setAppName("GWT");
- }
-
protected final HostedModeBaseOptions options;
/**
@@ -427,6 +418,13 @@
}
/**
+ * Derived classes can override to lengthen ping delay.
+ */
+ protected long checkForUpdatesInterval() {
+ return CheckForUpdates.ONE_MINUTE;
+ }
+
+ /**
* Compiles all modules.
*/
protected abstract void compile(TreeLogger logger)
@@ -463,13 +461,6 @@
"gen"), doCreateArtifactAcceptor(moduleDef));
}
- /**
- * Derived classes can override to prevent automatic update checking.
- */
- protected boolean doShouldCheckForUpdates() {
- return true;
- }
-
protected abstract void doShutDownServer();
protected boolean doStartup() {
@@ -481,6 +472,22 @@
// Initialize the logger.
//
initializeLogger();
+
+ // Check for updates
+ final TreeLogger logger = getTopLogger();
+ final CheckForUpdates updateChecker
+ = PlatformSpecific.createUpdateChecker(logger);
+ if (updateChecker != null) {
+ Thread checkerThread = new Thread("GWT Update Checker") {
+ @Override
+ public void run() {
+ PlatformSpecific.logUpdateAvailable(logger,
+ updateChecker.check(checkForUpdatesInterval()));
+ }
+ };
+ checkerThread.setDaemon(true);
+ checkerThread.start();
+ }
return true;
}
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java
index d64c2ed..c16b494 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -37,16 +37,21 @@
import com.google.gwt.dev.jjs.JsOutputOption;
import com.google.gwt.dev.jjs.UnifiedAst;
import com.google.gwt.dev.jjs.impl.FragmentLoaderCreator;
+import com.google.gwt.dev.shell.CheckForUpdates;
+import com.google.gwt.dev.shell.PlatformSpecific;
import com.google.gwt.dev.shell.StandardRebindOracle;
+import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
import com.google.gwt.dev.util.PerfLogger;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
import com.google.gwt.dev.util.arg.ArgHandlerDisableRunAsync;
import com.google.gwt.dev.util.arg.ArgHandlerDraftCompile;
+import com.google.gwt.dev.util.arg.ArgHandlerDisableUpdateCheck;
import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
import com.google.gwt.dev.util.arg.ArgHandlerValidateOnlyFlag;
+import com.google.gwt.dev.util.arg.OptionDisableUpdateCheck;
import com.google.gwt.dev.util.arg.OptionGenDir;
import com.google.gwt.dev.util.arg.OptionValidateOnly;
@@ -56,6 +61,7 @@
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
+import java.util.concurrent.FutureTask;
/**
* Performs the first phase of compilation, generating the set of permutations
@@ -67,7 +73,7 @@
* The set of options for the precompiler.
*/
public interface PrecompileOptions extends JJSOptions, CompileTaskOptions,
- OptionGenDir, OptionValidateOnly {
+ OptionGenDir, OptionValidateOnly, OptionDisableUpdateCheck {
}
static class ArgProcessor extends CompileArgProcessor {
@@ -80,6 +86,7 @@
registerHandler(new ArgHandlerValidateOnlyFlag(options));
registerHandler(new ArgHandlerDisableRunAsync(options));
registerHandler(new ArgHandlerDraftCompile(options));
+ registerHandler(new ArgHandlerDisableUpdateCheck(options));
}
@Override
@@ -90,7 +97,7 @@
static class PrecompileOptionsImpl extends CompileTaskOptionsImpl implements
PrecompileOptions {
-
+ private boolean disableUpdateCheck;
private File genDir;
private final JJSOptionsImpl jjsOptions = new JJSOptionsImpl();
private boolean validateOnly;
@@ -107,6 +114,7 @@
jjsOptions.copyFrom(other);
+ setDisableUpdateCheck(other.isUpdateCheckDisabled());
setGenDir(other.getGenDir());
setValidateOnly(other.isValidateOnly());
}
@@ -139,6 +147,10 @@
return jjsOptions.isSoycEnabled();
}
+ public boolean isUpdateCheckDisabled() {
+ return disableUpdateCheck;
+ }
+
public boolean isValidateOnly() {
return validateOnly;
}
@@ -151,6 +163,10 @@
jjsOptions.setDraftCompile(draft);
}
+ public void setDisableUpdateCheck(boolean disabled) {
+ disableUpdateCheck = disabled;
+ }
+
public void setEnableAssertions(boolean enableAssertions) {
jjsOptions.setEnableAssertions(enableAssertions);
}
@@ -257,7 +273,16 @@
if (new ArgProcessor(options).processArgs(args)) {
CompileTask task = new CompileTask() {
public boolean run(TreeLogger logger) throws UnableToCompleteException {
- return new Precompile(options).run(logger);
+ FutureTask<UpdateResult> updater = null;
+ if (!options.isUpdateCheckDisabled()) {
+ updater = PlatformSpecific.checkForUpdatesInBackgroundThread(logger,
+ CheckForUpdates.ONE_DAY);
+ }
+ boolean success = new Precompile(options).run(logger);
+ if (success) {
+ PlatformSpecific.logUpdateAvailable(logger, updater);
+ }
+ return success;
}
};
if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
diff --git a/dev/core/src/com/google/gwt/dev/SwtHostedModeBase.java b/dev/core/src/com/google/gwt/dev/SwtHostedModeBase.java
index bda5243..0fac666 100644
--- a/dev/core/src/com/google/gwt/dev/SwtHostedModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/SwtHostedModeBase.java
@@ -178,6 +178,8 @@
return browserHost;
}
+ protected abstract String getTitleText();
+
@Override
protected void initializeLogger() {
final AbstractTreeLogger logger = mainWnd.getLogger();
@@ -221,10 +223,8 @@
shell.setImages(ShellMainWindow.getIcons());
- boolean checkForUpdates = doShouldCheckForUpdates();
-
- mainWnd = new ShellMainWindow(this, shell, options.isNoServer() ? 0
- : getPort(), checkForUpdates);
+ mainWnd = new ShellMainWindow(this, shell, getTitleText(),
+ options.isNoServer() ? 0 : getPort());
shell.setSize(700, 600);
if (!isHeadless()) {
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
index e2653a1..e3c2f19 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
@@ -15,11 +15,13 @@
*/
package com.google.gwt.dev.javac;
+import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.asm.ClassReader;
import com.google.gwt.dev.asm.Opcodes;
import com.google.gwt.dev.asm.commons.EmptyVisitor;
import com.google.gwt.dev.jdt.TypeRefVisitor;
import com.google.gwt.dev.shell.CompilingClassLoader;
+import com.google.gwt.dev.util.Util;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
@@ -30,6 +32,9 @@
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -46,25 +51,129 @@
*/
public abstract class CompilationUnit {
- static class AnonymousClassVisitor extends EmptyVisitor {
- /*
- * array of classNames of inner clases that aren't synthetic classes.
- */
- List<String> classNames = new ArrayList<String>();
+ /**
+ * Encapsulates the functionality to find all nested classes of this class
+ * that have compiler-generated names. All class bytes are loaded from the
+ * disk and then analyzed using ASM.
+ */
+ static class GeneratedClassnameFinder {
+ private static class AnonymousClassVisitor extends EmptyVisitor {
+ /*
+ * array of classNames of inner clases that aren't synthetic classes.
+ */
+ List<String> classNames = new ArrayList<String>();
- public List<String> getInnerClassNames() {
- return classNames;
- }
+ public List<String> getInnerClassNames() {
+ return classNames;
+ }
- @Override
- public void visitInnerClass(String name, String outerName,
- String innerName, int access) {
- if ((access & Opcodes.ACC_SYNTHETIC) == 0) {
- classNames.add(name);
+ @Override
+ public void visitInnerClass(String name, String outerName,
+ String innerName, int access) {
+ if ((access & Opcodes.ACC_SYNTHETIC) == 0) {
+ classNames.add(name);
+ }
}
}
- }
+ private final List<String> classesToScan;
+ private final TreeLogger logger;
+ private final String mainClass;
+ private String mainUrlBase = null;
+
+ GeneratedClassnameFinder(TreeLogger logger, String mainClass) {
+ assert mainClass != null;
+ this.mainClass = mainClass;
+ classesToScan = new ArrayList<String>();
+ classesToScan.add(mainClass);
+ this.logger = logger;
+ }
+
+ List<String> getClassNames() {
+ // using a list because presumably there will not be many generated
+ // classes
+ List<String> allGeneratedClasses = new ArrayList<String>();
+ for (int i = 0; i < classesToScan.size(); i++) {
+ String lookupName = classesToScan.get(i);
+ byte classBytes[] = getClassBytes(lookupName);
+ if (classBytes == null) {
+ /*
+ * Weird case: javac might generate a name and reference the class in
+ * the bytecode but decide later that the class is unnecessary. In the
+ * bytecode, a null is passed for the class.
+ */
+ continue;
+ }
+
+ /*
+ * Add the class to the list only if it can be loaded to get around the
+ * javac weirdness issue where javac refers a class but does not
+ * generate it.
+ */
+ if (CompilingClassLoader.isClassnameGenerated(lookupName)
+ && !allGeneratedClasses.contains(lookupName)) {
+ allGeneratedClasses.add(lookupName);
+ }
+ AnonymousClassVisitor cv = new AnonymousClassVisitor();
+ new ClassReader(classBytes).accept(cv, 0);
+ List<String> innerClasses = cv.getInnerClassNames();
+ for (String innerClass : innerClasses) {
+ // The innerClass has to be an inner class of the lookupName
+ if (!innerClass.startsWith(mainClass + "$")) {
+ continue;
+ }
+ /*
+ * TODO (amitmanjhi): consider making this a Set if necessary for
+ * performance
+ */
+ // add the class to classes
+ if (!classesToScan.contains(innerClass)) {
+ classesToScan.add(innerClass);
+ }
+ }
+ }
+ Collections.sort(allGeneratedClasses, new GeneratedClassnameComparator());
+ return allGeneratedClasses;
+ }
+
+ /*
+ * Load classBytes from disk. Check if the classBytes are loaded from the
+ * same location as the location of the mainClass.
+ */
+ private byte[] getClassBytes(String slashedName) {
+ URL url = Thread.currentThread().getContextClassLoader().getResource(
+ slashedName + ".class");
+ if (url == null) {
+ logger.log(TreeLogger.DEBUG, "Unable to find " + slashedName
+ + " on the classPath");
+ return null;
+ }
+ String urlStr = url.toExternalForm();
+ if (slashedName.equals(mainClass)) {
+ // initialize the mainUrlBase for later use.
+ mainUrlBase = urlStr.substring(0, urlStr.lastIndexOf('/'));
+ } else {
+ assert mainUrlBase != null;
+ if (!mainUrlBase.equals(urlStr.substring(0, urlStr.lastIndexOf('/')))) {
+ logger.log(TreeLogger.DEBUG, "Found " + slashedName + " at " + urlStr
+ + " The base location is different from that of " + mainUrlBase
+ + " Not loading");
+ return null;
+ }
+ }
+
+ // url != null, we found it on the class path.
+ try {
+ URLConnection conn = url.openConnection();
+ return Util.readURLConnectionAsBytes(conn);
+ } catch (IOException ignored) {
+ logger.log(TreeLogger.DEBUG, "Unable to load " + urlStr
+ + ", in trying to load " + slashedName);
+ // Fall through.
+ }
+ return null;
+ }
+ }
/**
* Tracks the state of a compilation unit through the compile and recompile
* process.
@@ -167,26 +276,31 @@
private State state = State.FRESH;
/*
- * Check if the unit has one or more anonymous classes. 'javac' below refers
- * to the compiler that was used to compile the java files on disk. Returns
- * true if our heuristic for constructing the anonymous class mappings worked.
+ * Check if the unit has one or more classes with generated names. 'javac'
+ * below refers to the compiler that was used to compile the java files on
+ * disk. Returns true if our heuristic for constructing the anonymous class
+ * mappings worked.
*/
- public boolean constructAnonymousClassMappings(byte classBytes[]) {
+ public boolean constructAnonymousClassMappings(TreeLogger logger) {
// map from the name in javac to the name in jdt
anonymousClassMap = new HashMap<String, String>();
- List<String> javacClasses = getJavacClassNames(classBytes);
- List<String> jdtClasses = getJdtClassNames();
- if (javacClasses.size() == jdtClasses.size()) {
+ for (String topLevelClass : getTopLevelClasses()) {
+ // Generate a mapping for each top-level class separately
+ List<String> javacClasses = new GeneratedClassnameFinder(logger,
+ topLevelClass).getClassNames();
+ List<String> jdtClasses = getJdtClassNames(topLevelClass);
+ if (javacClasses.size() != jdtClasses.size()) {
+ anonymousClassMap = Collections.emptyMap();
+ return false;
+ }
int size = javacClasses.size();
for (int i = 0; i < size; i++) {
if (!javacClasses.get(i).equals(jdtClasses.get(i))) {
anonymousClassMap.put(javacClasses.get(i), jdtClasses.get(i));
}
}
- return true;
}
- anonymousClassMap = Collections.emptyMap();
- return false;
+ return true;
}
public boolean createdClassMapping() {
@@ -383,25 +497,11 @@
}
}
- private List<String> getJavacClassNames(byte classBytes[]) {
- AnonymousClassVisitor cv = new AnonymousClassVisitor();
- new ClassReader(classBytes).accept(cv, 0);
- List<String> classNames = cv.getInnerClassNames();
- List<String> namesToRemove = new ArrayList<String>();
- for (String className : classNames) {
- if (!CompilingClassLoader.isClassnameGenerated(className)) {
- namesToRemove.add(className);
- }
- }
- classNames.removeAll(namesToRemove);
- Collections.sort(classNames, new GeneratedClassnameComparator());
- return classNames;
- }
-
- private List<String> getJdtClassNames() {
+ private List<String> getJdtClassNames(String topLevelClass) {
List<String> classNames = new ArrayList<String>();
for (CompiledClass cc : getCompiledClasses()) {
- if (isAnonymousClass(cc)) {
+ if (isAnonymousClass(cc)
+ && cc.getBinaryName().startsWith(topLevelClass + "$")) {
classNames.add(cc.getBinaryName());
}
}
@@ -409,6 +509,16 @@
return classNames;
}
+ private List<String> getTopLevelClasses() {
+ List<String> topLevelClasses = new ArrayList<String>();
+ for (CompiledClass cc : getCompiledClasses()) {
+ if (cc.getEnclosingClass() == null) {
+ topLevelClasses.add(cc.binaryName);
+ }
+ }
+ return topLevelClasses;
+ }
+
/**
* Removes all accumulated state associated with compilation.
*/
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/ClassPathEntry.java
index aaa46f9..5ada435 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ClassPathEntry.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ClassPathEntry.java
@@ -17,7 +17,7 @@
import com.google.gwt.core.ext.TreeLogger;
-import java.util.Set;
+import java.util.Map;
/**
* A location that acts as a starting point for finding resources
@@ -30,11 +30,12 @@
* begins with a prefix X from the path prefix set and P is allowed by the
* filter associated with X.
*
- * @return a set of zero or more resources; note no guarantees are made
- * regarding the identities of the returned resource objects, and the
- * same object may be returned across multiple calls
+ * @return a map with key as an allowed resource and value as the PathPrefix
+ * that allows the resource; note no guarantees are made regarding the
+ * identities of the returned resource objects, and the same object
+ * may be returned across multiple calls
*/
- public abstract Set<AbstractResource> findApplicableResources(
+ public abstract Map<AbstractResource, PathPrefix> findApplicableResources(
TreeLogger logger, PathPrefixSet pathPrefixSet);
/**
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/DirectoryClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/DirectoryClassPathEntry.java
index 7d29ca6..2fd2964 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/DirectoryClassPathEntry.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/DirectoryClassPathEntry.java
@@ -19,8 +19,8 @@
import com.google.gwt.dev.util.msg.Message1String;
import java.io.File;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.IdentityHashMap;
+import java.util.Map;
/**
* TODO(bruce): write me.
@@ -48,9 +48,9 @@
}
@Override
- public Set<AbstractResource> findApplicableResources(TreeLogger logger,
- PathPrefixSet pathPrefixSet) {
- Set<AbstractResource> results = new HashSet<AbstractResource>();
+ public Map<AbstractResource, PathPrefix> findApplicableResources(
+ TreeLogger logger, PathPrefixSet pathPrefixSet) {
+ Map<AbstractResource, PathPrefix> results = new IdentityHashMap<AbstractResource, PathPrefix>();
descendToFindResources(logger, pathPrefixSet, results, dir, "");
return results;
}
@@ -62,14 +62,15 @@
/**
* @param logger logs progress
- * @param resources the accumulating set of resources found
+ * @param resources the accumulating set of resources (each with the
+ * corresponding pathPrefix) found
* @param dir the file or directory to consider
* @param dirPath the abstract path name associated with 'parent', which
* explicitly does not include the classpath entry in its path
*/
private void descendToFindResources(TreeLogger logger,
- PathPrefixSet pathPrefixSet, Set<AbstractResource> resources, File dir,
- String dirPath) {
+ PathPrefixSet pathPrefixSet, Map<AbstractResource, PathPrefix> resources,
+ File dir, String dirPath) {
assert (dir.isDirectory());
// Assert: this directory is included in the path prefix set.
@@ -89,10 +90,11 @@
null);
}
} else {
- if (pathPrefixSet.includesResource(childPath)) {
+ PathPrefix prefix = null;
+ if ((prefix = pathPrefixSet.includesResource(childPath)) != null) {
Messages.INCLUDING_FILE.log(logger, childPath, null);
FileResource r = new FileResource(this, childPath, child);
- resources.add(r);
+ resources.put(r, prefix);
} else {
Messages.EXCLUDING_FILE.log(logger, childPath, null);
}
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefix.java b/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefix.java
index 25537bb..096dfb1 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefix.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefix.java
@@ -33,6 +33,7 @@
private final ResourceFilter filter;
private final String prefix;
+ private int priority = -1;
private final boolean shouldReroot;
/**
@@ -135,6 +136,20 @@
return shouldReroot;
}
+ @Override
+ public String toString() {
+ return prefix + (shouldReroot ? "**" : "*") + (filter == null ? "" : "?");
+ }
+
+ int getPriority() {
+ return priority;
+ }
+
+ void setPriority(int priority) {
+ assert (this.priority == -1);
+ this.priority = priority;
+ }
+
private void assertValidPrefix(String prefix) {
assert (prefix != null);
assert ("".equals(prefix) || (!prefix.startsWith("/") && prefix.endsWith("/"))) : "malformed prefix";
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefixSet.java b/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefixSet.java
index 0e72bf4..0220db6 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefixSet.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/PathPrefixSet.java
@@ -27,11 +27,22 @@
* answer questions regarding an entire set of path prefixes.
*/
public class PathPrefixSet {
+ /*
+ * (1) TODO(amitmanjhi): Support multiple PathPrefixes with different filters
+ * but the same "path". This could arise when client code inherits some
+ * library code and defines the same path prefix with a more specific resource
+ * filter.
+ *
+ * (2) TODO(amitmanjhi): Improve the api of the PathPrefixSet so that with one
+ * trie-traversal, it could be found out which resources rooted at a directory
+ * are allowed?
+ */
private static class TrieNode {
- // TODO(bruce): test to see if Map would be faster; I'm on the fence
- private final List<TrieNode> children = new ArrayList<TrieNode>();
+ // TODO(amitmanjhi): Consider the memory-speed tradeoff here
+ private final Map<String, TrieNode> children = new HashMap<String, TrieNode>();
private final String part;
+
private PathPrefix prefix;
public TrieNode(String part) {
@@ -39,19 +50,14 @@
}
public TrieNode addChild(String part) {
- assert (findChild(part) == null);
TrieNode newChild = new TrieNode(part);
- children.add(newChild);
+ TrieNode oldChild = children.put(part, newChild);
+ assert (oldChild == null);
return newChild;
}
public TrieNode findChild(String part) {
- for (TrieNode child : children) {
- if (child.part.equals(part)) {
- return child;
- }
- }
- return null;
+ return children.get(part);
}
public PathPrefix getPathPrefix() {
@@ -80,14 +86,17 @@
sb.append(indent);
sb.append(' ');
sb.append(part);
- for (TrieNode child : children) {
+ for (TrieNode child : children.values()) {
child.toString(sb, indent + " ");
}
}
}
- private int modCount;
- private final Map<String, PathPrefix> prefixes = new HashMap<String, PathPrefix>();
+ /**
+ * List of all path prefixes in priority order.
+ */
+ private final List<PathPrefix> prefixes = new ArrayList<PathPrefix>();
+
private final TrieNode rootTrieNode = new TrieNode("/");
/**
@@ -98,13 +107,14 @@
* wins)
*/
public boolean add(PathPrefix prefix) {
- ++modCount;
+ prefix.setPriority(prefixes.size());
+ prefixes.add(prefix);
+
String pathPrefix = prefix.getPrefix();
- prefixes.put(pathPrefix, prefix);
/*
- * An empty prefix means we have no prefix requirement, but we do attached
- * the prefix to the root so that we can apply the filter.
+ * An empty prefix means we have no prefix requirement, but we do attach the
+ * prefix to the root so that we can apply the filter.
*/
if ("".equals(pathPrefix)) {
rootTrieNode.setPathPrefix(prefix);
@@ -132,8 +142,8 @@
return didAdd;
}
- public int getModCount() {
- return modCount;
+ public int getSize() {
+ return prefixes.size();
}
/**
@@ -141,19 +151,17 @@
* included. The primary purpose of this method is to allow
* {@link ClassPathEntry} subclasses to avoid descending into directory
* hierarchies that could not possibly contain resources that would be
- * included by {@link #includesResource(String).
+ * included by {@link #includesResource(String)}
*
- * @param dirPath must be a valid abstract directory name or the empty string
- * @return
+ * @param dirPath must be a valid abstract directory name (must not be an
+ * empty string)
+ * @return true if some PathPrefix allows the directory
*/
public boolean includesDirectory(String dirPath) {
assertValidAbstractDirectoryPathName(dirPath);
/*
- * There are five cases:
- *
- * (0) dirPath is the empty string, which is (a) trivially included unless
- * (b) no prefix paths have been specified at all.
+ * There are four cases:
*
* (1) The empty string was specified as a prefix, which causes everything
* to be included.
@@ -171,22 +179,12 @@
* includes it).
*/
- // if ("".equals(dirPath)) {
- // if (rootTrieNode.hasChildren() || rootTrieNode.getPathPrefix() != null) {
- // // Case (0)(a): trivially true.
- // return true;
- // } else {
- // // Case (0)(b): no directories are included.
- // return false;
- // }
- // }
if (rootTrieNode.getPathPrefix() != null) {
// Case (1).
return true;
}
TrieNode parentNode = rootTrieNode;
-
String[] parts = dirPath.split("/");
for (String part : parts) {
assert (!"".equals(part));
@@ -215,10 +213,12 @@
* prefix set and the corresponding filters.
*
* @param resourceAbstractPathName
- * @return <code>true</code> if the resource matches some specified prefix
- * and any associated filters don't exclude it
+ * @return matching <code>PathPrefix</code> if the resource matches some
+ * specified prefix and any associated filters don't exclude it.
+ * Otherwise, returns null. So it returns null if either no prefixes
+ * match or the most specific prefix excludes the resource.
*/
- public boolean includesResource(String resourceAbstractPathName) {
+ public PathPrefix includesResource(String resourceAbstractPathName) {
/*
* Algorithm: dive down the package hierarchy looking for the most specific
* package that applies to this resource. The filter of the most specific
@@ -232,12 +232,8 @@
TrieNode currentNode = rootTrieNode;
PathPrefix mostSpecificPrefix = rootTrieNode.getPathPrefix();
- // TODO(bruce): consider not using split for speed
- String[] parts = resourceAbstractPathName.split("/");
-
// Walk all but the last path part, which is assumed to be a file name.
- for (int i = 0, n = parts.length - 1; i < n; ++i) {
- String part = parts[i];
+ for (String part : resourceAbstractPathName.split("/")) {
assert (!"".equals(part));
TrieNode childNode = currentNode.findChild(part);
if (childNode != null) {
@@ -253,17 +249,25 @@
}
}
- if (mostSpecificPrefix == null) {
- // Didn't match any specified prefix.
- return false;
+ if (mostSpecificPrefix == null
+ || !mostSpecificPrefix.allows(resourceAbstractPathName)) {
+ /*
+ * Didn't match any specified prefix or the filter of the most specific
+ * prefix disallows the resource
+ */
+ return null;
}
- // Test the filter of the most specific prefix we found.
- return mostSpecificPrefix.allows(resourceAbstractPathName);
+ return mostSpecificPrefix;
+ }
+
+ @Override
+ public String toString() {
+ return rootTrieNode.toString();
}
public Collection<PathPrefix> values() {
- return Collections.unmodifiableCollection(prefixes.values());
+ return Collections.unmodifiableCollection(prefixes);
}
private void assertValidAbstractDirectoryPathName(String name) {
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
index 50a1985..075bc13 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
@@ -15,12 +15,6 @@
*/
package com.google.gwt.dev.resource.impl;
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.dev.resource.Resource;
-import com.google.gwt.dev.resource.ResourceOracle;
-import com.google.gwt.dev.util.msg.Message0;
-import com.google.gwt.dev.util.msg.Message1String;
-
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -36,9 +30,16 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Map.Entry;
import java.util.jar.JarFile;
import java.util.zip.ZipFile;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.dev.resource.ResourceOracle;
+import com.google.gwt.dev.util.msg.Message0;
+import com.google.gwt.dev.util.msg.Message1String;
+
/**
* The normal implementation of {@link ResourceOracle}.
*
@@ -75,17 +76,14 @@
}
/**
- * Used by rebasing {@link ResourceOracle ResourceOracles} to map from a full
- * classpath-based abstract path to an abstract path within a logical package.
- *
- * @see ResourceOracleImpl#shouldRebasePaths()
+ * Wrapper object around a resource to change its path when it is rerooted.
*/
- private static class ResourceWrapper extends AbstractResource {
+ private static class RerootedResource extends AbstractResource {
private final String path;
private final AbstractResource resource;
- public ResourceWrapper(String path, AbstractResource resource) {
- this.path = path;
+ public RerootedResource(AbstractResource resource, PathPrefix pathPrefix) {
+ this.path = pathPrefix.getRerootedPath(resource.getPath());
this.resource = resource;
}
@@ -130,6 +128,31 @@
}
}
+ private static class ResourceData implements Comparable<ResourceData> {
+ public final PathPrefix pathPrefix;
+ public final AbstractResource resource;
+
+ public ResourceData(AbstractResource resource, PathPrefix pathPrefix) {
+ this.resource = pathPrefix.shouldReroot() ? new RerootedResource(
+ resource, pathPrefix) : resource;
+ this.pathPrefix = pathPrefix;
+ }
+
+ public int compareTo(ResourceData other) {
+ // Rerooted takes precedence over not rerooted.
+ if (this.resource.wasRerooted() != other.resource.wasRerooted()) {
+ return this.resource.wasRerooted() ? 1 : -1;
+ }
+ // Compare priorities of the path prefixes, high number == high priority.
+ return this.pathPrefix.getPriority() - other.pathPrefix.getPriority();
+ }
+
+ @Override
+ public String toString() {
+ return "{" + resource + "," + pathPrefix + "}";
+ }
+ }
+
private static final Map<ClassLoader, List<ClassPathEntry>> classPathCache = new HashMap<ClassLoader, List<ClassPathEntry>>();
public static ClassPathEntry createEntryForUrl(TreeLogger logger, URL url)
@@ -218,7 +241,7 @@
private Set<Resource> exposedResources = Collections.emptySet();
- private Map<String, AbstractResource> internalMap = Collections.emptyMap();
+ private Map<String, ResourceData> internalMap = Collections.emptyMap();
private PathPrefixSet pathPrefixSet = new PathPrefixSet();
@@ -277,7 +300,7 @@
* "new identity for the collections if anything changes" guarantee. Use a
* LinkedHashMap because we do not want the order to change.
*/
- final Map<String, AbstractResource> newInternalMap = new LinkedHashMap<String, AbstractResource>();
+ Map<String, ResourceData> newInternalMap = new LinkedHashMap<String, ResourceData>();
/*
* Walk across path roots (i.e. classpath entries) in priority order. This
@@ -285,65 +308,71 @@
* a resource that has already been added to the new map under construction
* to create the effect that resources founder earlier on the classpath take
* precedence.
+ *
+ * Exceptions: super has priority over non-super; and if there are two super
+ * resources with the same path, the one with the higher-priority path
+ * prefix wins.
*/
- int changeCount = 0;
for (ClassPathEntry pathRoot : classPath) {
TreeLogger branchForClassPathEntry = Messages.EXAMINING_PATH_ROOT.branch(
refreshBranch, pathRoot.getLocation(), null);
- int prevChangeCount = changeCount;
-
- Set<AbstractResource> newResources = pathRoot.findApplicableResources(
+ Map<AbstractResource, PathPrefix> resourceToPrefixMap = pathRoot.findApplicableResources(
branchForClassPathEntry, pathPrefixSet);
- for (AbstractResource newResource : newResources) {
- String resourcePath = newResource.getPath();
-
- // Make sure we don't already have a resource by this name.
- if (newInternalMap.containsKey(resourcePath)) {
+ for (Entry<AbstractResource, PathPrefix> entry : resourceToPrefixMap.entrySet()) {
+ ResourceData newCpeData = new ResourceData(entry.getKey(),
+ entry.getValue());
+ String resourcePath = newCpeData.resource.getPath();
+ ResourceData oldCpeData = newInternalMap.get(resourcePath);
+ // Old wins unless the new resource has higher priority.
+ if (oldCpeData == null || oldCpeData.compareTo(newCpeData) < 0) {
+ newInternalMap.put(resourcePath, newCpeData);
+ } else {
Messages.IGNORING_SHADOWED_RESOURCE.log(branchForClassPathEntry,
resourcePath, null);
- continue;
}
-
- AbstractResource oldResource = internalMap.get(resourcePath);
- if (shouldUseNewResource(branchForClassPathEntry, oldResource,
- newResource)) {
- newInternalMap.put(resourcePath, newResource);
- ++changeCount;
- } else if (oldResource != null) {
- // Nothing changed, so carry the identity of the old one forward.
- newInternalMap.put(resourcePath, oldResource);
- }
- }
-
- if (changeCount == prevChangeCount) {
- Messages.NO_RESOURCES_CHANGED.log(branchForClassPathEntry, null);
}
}
- if (changeCount == 0) {
- /*
- * Nothing was added or modified, but we still have to be sure we didn't
- * lose any resources.
- */
- if (newInternalMap.size() == internalMap.size()) {
- /*
- * Exit without changing the current exposed collections to maintain the
- * identity requirements described in the spec for ResourceOracle.
- */
- return;
+ /*
+ * Update the newInternalMap to preserve identity for any resources that
+ * have not changed; also record whether or not there are ANY changes.
+ *
+ * There's definitely a change if the sizes don't match; even if the sizes
+ * do match, every new resource must match an old resource for there to be
+ * no changes.
+ */
+ boolean didChange = internalMap.size() != newInternalMap.size();
+ for (String resourcePath : newInternalMap.keySet()) {
+ ResourceData newData = newInternalMap.get(resourcePath);
+ ResourceData oldData = internalMap.get(resourcePath);
+ if (shouldUseNewResource(logger, oldData, newData)) {
+ didChange = true;
+ } else {
+ if (oldData.resource != newData.resource) {
+ newInternalMap.put(resourcePath, oldData);
+ }
}
}
+ if (!didChange) {
+ // Nothing to do, keep the same identities.
+ return;
+ }
+
internalMap = newInternalMap;
- Map<String, Resource> externalMap = rerootResourcePaths(newInternalMap);
- // Create a constant-time set for resources.
- Set<Resource> newResources = new HashSet<Resource>(externalMap.values());
- assert (newResources.size() == externalMap.size());
+ Map<String, Resource> externalMap = new HashMap<String, Resource>();
+ Set<Resource> externalSet = new HashSet<Resource>();
+ for (Entry<String, ResourceData> entry : internalMap.entrySet()) {
+ String path = entry.getKey();
+ ResourceData data = entry.getValue();
+ externalMap.put(path, data.resource);
+ externalSet.add(data.resource);
+ }
- // Update the gettable fields with the new (unmodifiable) data structures.
- exposedResources = Collections.unmodifiableSet(newResources);
+ // Update exposed collections with new (unmodifiable) data structures.
+ exposedResources = Collections.unmodifiableSet(externalSet);
exposedResourceMap = Collections.unmodifiableMap(externalMap);
exposedPathNames = Collections.unmodifiableSet(externalMap.keySet());
}
@@ -357,59 +386,13 @@
return classPath;
}
- private Map<String, Resource> rerootResourcePaths(
- Map<String, AbstractResource> newInternalMap) {
- Map<String, Resource> externalMap;
- // Create an external map with rebased path names.
- externalMap = new HashMap<String, Resource>();
- for (AbstractResource resource : newInternalMap.values()) {
- String path = resource.getPath();
- if (externalMap.get(path) instanceof ResourceWrapper) {
- // A rerooted resource blocks any other resource at this path.
- continue;
- }
- int hitCount = 0;
- for (PathPrefix pathPrefix : pathPrefixSet.values()) {
- if (pathPrefix.allows(path)) {
- assert (path.startsWith(pathPrefix.getPrefix()));
- if (pathPrefix.shouldReroot()) {
- String rerootedPath = pathPrefix.getRerootedPath(path);
- if (externalMap.get(rerootedPath) instanceof ResourceWrapper) {
- // A rerooted instance blocks any other resource at this path.
- ++hitCount;
- break;
- }
- // Try to reuse the same wrapper.
- Resource exposed = exposedResourceMap.get(rerootedPath);
- if (exposed instanceof ResourceWrapper) {
- ResourceWrapper exposedWrapper = (ResourceWrapper) exposed;
- if (exposedWrapper.resource == resource) {
- externalMap.put(rerootedPath, exposedWrapper);
- ++hitCount;
- break;
- }
- }
- // Just create a new wrapper.
- AbstractResource wrapper = new ResourceWrapper(rerootedPath,
- resource);
- externalMap.put(rerootedPath, wrapper);
- ++hitCount;
- } else {
- externalMap.put(path, resource);
- ++hitCount;
- }
- }
- }
- assert (hitCount > 0);
- }
- return externalMap;
- }
-
- private boolean shouldUseNewResource(TreeLogger logger,
- AbstractResource oldResource, AbstractResource newResource) {
+ private boolean shouldUseNewResource(TreeLogger logger, ResourceData oldData,
+ ResourceData newData) {
+ AbstractResource newResource = newData.resource;
String resourcePath = newResource.getPath();
- if (oldResource != null) {
+ if (oldData != null) {
// Test 1: Is the resource found in a different location than before?
+ AbstractResource oldResource = oldData.resource;
if (oldResource.getClassPathEntry() == newResource.getClassPathEntry()) {
// Test 2: Has the resource changed since we last found it?
if (!oldResource.isStale()) {
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
index 6076260..f7a0420 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
@@ -21,6 +21,8 @@
import java.io.File;
import java.util.Enumeration;
import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -51,9 +53,10 @@
}
private Set<ZipFileResource> allZipFileResources;
- private Set<AbstractResource> cachedAnswers;
+ private Map<AbstractResource, PathPrefix> cachedAnswers;
private String cachedLocation;
private PathPrefixSet lastPrefixSet;
+ private int lastPrefixSetSize;
private final ZipFile zipFile;
public ZipFileClassPathEntry(ZipFile zipFile) {
@@ -64,18 +67,19 @@
* Indexes the zip file on-demand, and only once over the life of the process.
*/
@Override
- public Set<AbstractResource> findApplicableResources(TreeLogger logger,
- PathPrefixSet pathPrefixSet) {
+ public Map<AbstractResource, PathPrefix> findApplicableResources(
+ TreeLogger logger, PathPrefixSet pathPrefixSet) {
// Never re-index.
if (allZipFileResources == null) {
allZipFileResources = buildIndex(logger);
}
if (cachedAnswers == null || lastPrefixSet != pathPrefixSet
- || lastPrefixSet.getModCount() != pathPrefixSet.getModCount()) {
+ || lastPrefixSetSize != pathPrefixSet.getSize()) {
cachedAnswers = computeApplicableResources(logger, pathPrefixSet);
+ lastPrefixSet = pathPrefixSet;
+ lastPrefixSetSize = pathPrefixSet.getSize();
}
-
return cachedAnswers;
}
@@ -113,17 +117,18 @@
return results;
}
- private Set<AbstractResource> computeApplicableResources(TreeLogger logger,
- PathPrefixSet pathPrefixSet) {
+ private Map<AbstractResource, PathPrefix> computeApplicableResources(
+ TreeLogger logger, PathPrefixSet pathPrefixSet) {
logger = Messages.FINDING_INCLUDED_RESOURCES.branch(logger,
zipFile.getName(), null);
- Set<AbstractResource> results = new HashSet<AbstractResource>();
+ Map<AbstractResource, PathPrefix> results = new IdentityHashMap<AbstractResource, PathPrefix>();
for (ZipFileResource r : allZipFileResources) {
String path = r.getPath();
- if (pathPrefixSet.includesResource(path)) {
+ PathPrefix prefix = null;
+ if ((prefix = pathPrefixSet.includesResource(path)) != null) {
Messages.INCLUDING_RESOURCE.log(logger, path, null);
- results.add(r);
+ results.put(r, prefix);
} else {
Messages.EXCLUDING_RESOURCE.log(logger, path, null);
}
diff --git a/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java b/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java
index e2bb884..ec178b1 100644
--- a/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java
+++ b/dev/core/src/com/google/gwt/dev/shell/BrowserWindowController.java
@@ -15,17 +15,29 @@
*/
package com.google.gwt.dev.shell;
+import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
/**
* Interface to the browser window controller.
*/
public interface BrowserWindowController {
+ /**
+ * Whether to display server control(s).
+ */
+ enum WebServerRestart {
+ DISABLED, ENABLED, NONE
+ }
+
void closeAllBrowserWindows();
boolean hasBrowserWindowsOpen();
+ WebServerRestart hasWebServer();
+
String normalizeURL(String string);
BrowserWidget openNewBrowserWindow() throws UnableToCompleteException;
-}
\ No newline at end of file
+
+ void restartServer(TreeLogger logger) throws UnableToCompleteException;
+}
diff --git a/dev/core/src/com/google/gwt/dev/shell/CheckForUpdates.java b/dev/core/src/com/google/gwt/dev/shell/CheckForUpdates.java
index e9e7886..51bfbe4 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CheckForUpdates.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CheckForUpdates.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.shell;
+import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.About;
import org.w3c.dom.Document;
@@ -27,8 +28,11 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
@@ -43,18 +47,121 @@
* Orchestrates a best-effort attempt to find out if a new version of GWT is
* available.
*/
-public abstract class CheckForUpdates {
+public class CheckForUpdates {
/**
- * Abstract the action to take when an update is available.
+ * Represents a GWT version.
*/
- public static interface UpdateAvailableCallback {
- void onUpdateAvailable(String html);
+ public static class GwtVersion implements Comparable<GwtVersion> {
+
+ private final int[] version = new int[3];
+
+ /**
+ * Create a version that avoids any nagging -- "0.0.999".
+ */
+ public GwtVersion() {
+ version[2] = 999;
+ }
+
+ /**
+ * Parse a version number as a string. An empty or null string are
+ * explicitly allowed and are equivalent to "0.0.0".
+ *
+ * @param versionString
+ * @throws NumberFormatException
+ */
+ public GwtVersion(String versionString) throws NumberFormatException {
+ if (versionString == null) {
+ return;
+ }
+ int part = 0;
+ int v = 0;
+ int len = versionString.length();
+ for (int i = 0; i < len; ++i) {
+ char ch = versionString.charAt(i);
+ if (ch == '.') {
+ if (part >= version.length) {
+ throw new NumberFormatException();
+ }
+ version[part++] = v;
+ v = 0;
+ } else if (Character.isDigit(ch)) {
+ int digit = Character.digit(ch, 10);
+ if (digit < 0) {
+ throw new NumberFormatException();
+ }
+ v = v * 10 + digit;
+ }
+ }
+ version[part++] = v;
+ }
+
+ public int compareTo(GwtVersion o) {
+ for (int i = 0; i <= 2; ++i) {
+ if (version[i] != o.version[i]) {
+ return version[i] - o.version[i];
+ }
+ }
+ return 0;
+ }
+
+ public int getPart(int part) {
+ // TODO: something besides IORE here?
+ return version[part];
+ }
+
+ public boolean isNoNagVersion() {
+ return version[2] == 999;
+ }
+
+ public boolean isUnspecified() {
+ return version[0] == 0 && version[1] == 0 && version[2] == 0;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+ buf.append(version[0]).append('.').append(version[1]).append('.');
+ buf.append(version[2]);
+ return buf.toString();
+ }
}
- protected static final String LAST_SERVER_VERSION = "lastServerVersion";
- private static final boolean DEBUG_VERSION_CHECK;
+ /**
+ * Returns the result of an update check.
+ */
+ public interface UpdateResult {
+ /**
+ * @return the new version of GWT available.
+ */
+ GwtVersion getNewVersion();
+
+ /**
+ * @return the URL for details about the new version.
+ */
+ URL getURL();
+ }
+
+ public static final long ONE_DAY = 24 * 60 * 60 * 1000;
+ public static final long ONE_MINUTE = 60 * 1000;
+
+ // System properties used by CheckForUpdates
+ protected static final String PROPERTY_DEBUG_HTTP_GET = "gwt.debugLowLevelHttpGet";
+ protected static final String PROPERTY_FORCE_NONNATIVE = "gwt.forceVersionCheckNonNative";
+ protected static final String PROPERTY_PREFS_NAME = "gwt.prefsPathName";
+ protected static final String PROPERTY_QUERY_URL = "gwt.forceVersionCheckURL";
+
+ // Log levels -- in general we want the logging of the update process
+ // to not be visible to normal users.
+ private static final TreeLogger.Type CHECK_ERROR = TreeLogger.DEBUG;
+ private static final TreeLogger.Type CHECK_INFO = TreeLogger.SPAM;
+ private static final TreeLogger.Type CHECK_SPAM = TreeLogger.SPAM;
+ private static final TreeLogger.Type CHECK_WARN = TreeLogger.SPAM;
+
+ // Preferences keys
private static final String FIRST_LAUNCH = "firstLaunch";
+ private static final String HIGHEST_RUN_VERSION = "highestRunVersion";
+ private static final String LAST_PING = "lastPing";
private static final String NEXT_PING = "nextPing";
// Uncomment one of constants below to try different variations of failure to
@@ -75,74 +182,6 @@
// The real URL that should be used.
private static final String QUERY_URL = "http://tools.google.com/webtoolkit/currentversion.xml";
- private static final int VERSION_PARTS = 3;
- private static final String VERSION_REGEXP = "\\d+\\.\\d+\\.\\d+";
-
- static {
- // Do this in a static initializer so we can ignore all exceptions.
- //
- boolean debugVersionCheck = false;
- try {
- if (System.getProperty("gwt.debugVersionCheck") != null) {
- debugVersionCheck = true;
- }
- } catch (Throwable e) {
- // Always silently ignore any errors.
- //
- } finally {
- DEBUG_VERSION_CHECK = debugVersionCheck;
- }
- }
-
- /**
- * Determines whether the server version is definitively newer than the client
- * version. If any errors occur in the comparison, this method returns false
- * to avoid unwanted erroneous notifications.
- *
- * @param clientVersion The current client version
- * @param serverVersion The current server version
- * @return true if the server is definitely newer, otherwise false
- */
- protected static boolean isServerVersionNewer(String clientVersion,
- String serverVersion) {
- if (clientVersion == null || serverVersion == null) {
- return false;
- }
-
- // must match expected format
- if (!clientVersion.matches(VERSION_REGEXP)
- || !serverVersion.matches(VERSION_REGEXP)) {
- return false;
- }
-
- // extract the relevant parts
- String[] clientParts = clientVersion.split("\\.");
- String[] serverParts = serverVersion.split("\\.");
- if (clientParts.length != VERSION_PARTS
- || serverParts.length != VERSION_PARTS) {
- return false;
- }
-
- // examine piece by piece from most significant to least significant
- for (int i = 0; i < VERSION_PARTS; ++i) {
- try {
- int clientPart = Integer.parseInt(clientParts[i]);
- int serverPart = Integer.parseInt(serverParts[i]);
- if (serverPart < clientPart) {
- return false;
- }
-
- if (serverPart > clientPart) {
- return true;
- }
- } catch (NumberFormatException e) {
- return false;
- }
- }
-
- return false;
- }
-
private static String getTextOfLastElementHavingTag(Document doc,
String tagName) {
NodeList nodeList = doc.getElementsByTagName(tagName);
@@ -161,197 +200,97 @@
return null;
}
- private static void parseResponse(Preferences prefs, byte[] response,
- UpdateAvailableCallback callback) throws IOException,
- ParserConfigurationException, SAXException {
+ private String entryPoint;
+ private TreeLogger logger;
+ private GwtVersion myVersion;
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Parsing response (length " + response.length + ")");
- }
+ /**
+ * Create an update checker which will poll a server URL and log a message
+ * about an update if available.
+ *
+ * @param logger TreeLogger to use
+ */
+ public CheckForUpdates(TreeLogger logger) {
+ this(logger, null);
+ }
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- DocumentBuilder builder = factory.newDocumentBuilder();
- ByteArrayInputStream bais = new ByteArrayInputStream(response);
-
- // Parse the XML.
- //
- builder.setErrorHandler(new ErrorHandler() {
-
- public void error(SAXParseException exception) throws SAXException {
- // fail quietly
- }
-
- public void fatalError(SAXParseException exception) throws SAXException {
- // fail quietly
- }
-
- public void warning(SAXParseException exception) throws SAXException {
- // fail quietly
- }
- });
- Document doc = builder.parse(bais);
-
- // The latest version number.
- //
- String version = getTextOfLastElementHavingTag(doc, "latest-version");
- if (version == null) {
- // Not valid; quietly fail.
- //
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Failed to find <latest-version>");
- }
- return;
- } else {
- version = version.trim();
- }
-
- String[] versionParts = version.split("\\.");
- if (versionParts.length != 3) {
- // Not valid; quietly fail.
- //
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Bad version format: " + version);
- }
- return;
- }
+ /**
+ * Create an update checker which will poll a server URL and log a message
+ * about an update if available.
+ *
+ * @param logger TreeLogger to use
+ * @param entryPoint the name of the main entry point used for this execution
+ */
+ public CheckForUpdates(TreeLogger logger, String entryPoint) {
+ this.logger = logger;
+ this.entryPoint = entryPoint;
try {
- Integer.parseInt(versionParts[0]);
- Integer.parseInt(versionParts[1]);
- Integer.parseInt(versionParts[2]);
+ myVersion = new GwtVersion(About.GWT_VERSION_NUM);
} catch (NumberFormatException e) {
- // Not valid; quietly fail.
- //
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Bad version number: " + version);
- }
- return;
+ // if our build version number is bogus, use one that avoids nagging
+ myVersion = new GwtVersion();
}
-
- // Ping delay for server-controlled throttling.
- //
- String pingDelaySecsStr = getTextOfLastElementHavingTag(doc,
- "min-wait-seconds");
- int pingDelaySecs = 0;
- if (pingDelaySecsStr == null) {
- // Not valid; quietly fail.
- //
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Missing <min-wait-seconds>");
- }
- return;
- } else {
- try {
- pingDelaySecs = Integer.parseInt(pingDelaySecsStr.trim());
- } catch (NumberFormatException e) {
- // Not a valid number; quietly fail.
- //
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Bad min-wait-seconds number: " + pingDelaySecsStr);
- }
- return;
- }
- }
-
- // Read the HTML.
- //
- String html = getTextOfLastElementHavingTag(doc, "notification");
-
- if (html == null) {
- // Not valid; quietly fail.
- //
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Missing <notification>");
- }
- return;
- }
-
- // Okay -- this is a valid response.
- //
- processResponse(prefs, version, pingDelaySecs, html, callback);
}
- private static void processResponse(Preferences prefs, String version,
- int pingDelaySecs, String html, UpdateAvailableCallback callback) {
-
- // Record a ping; don't ping again until the delay is up.
- //
- long nextPingTime = System.currentTimeMillis() + pingDelaySecs * 1000;
- prefs.put(NEXT_PING, String.valueOf(nextPingTime));
-
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Ping delay is " + pingDelaySecs + "; next ping at "
- + new Date(nextPingTime));
- }
-
- /*
- * Stash the version we got last time for comparison below, and record for
- * next time the version we just got.
- */
- String lastServerVersion = prefs.get(LAST_SERVER_VERSION, null);
- prefs.put(LAST_SERVER_VERSION, version);
-
- // Are we up to date already?
- //
- if (!isServerVersionNewer(About.GWT_VERSION_NUM, version)) {
-
- // Yes, we are.
- //
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Server version is not newer");
- }
- return;
- }
-
- // Have we already prompted for this particular server version?
- //
- if (version.equals(lastServerVersion)) {
-
- // We've already nagged the user once. Don't do it again.
- //
- if (DEBUG_VERSION_CHECK) {
- System.out.println("A notification has already been shown for "
- + version);
- }
- return;
- }
-
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Server version has changed to " + version
- + "; notification will be shown");
- }
-
- // Commence nagging.
- //
- callback.onUpdateAvailable(html);
+ /**
+ * Check for updates and log to the logger if they are available.
+ *
+ * @return an UpdateResult or null if there is no new update
+ */
+ public UpdateResult check() {
+ return check(0);
}
- public void check(final UpdateAvailableCallback callback) {
-
+ /**
+ * Check for updates and log to the logger if they are available.
+ *
+ * @return an UpdateResult or null if there is no new update
+ */
+ public UpdateResult check(long minCheckMillis) {
+ TreeLogger branch = logger.branch(CHECK_INFO, "Checking for updates");
try {
- String forceCheckURL = System.getProperty("gwt.forceVersionCheckURL");
+ String prefsName = System.getProperty(PROPERTY_PREFS_NAME);
+ Preferences prefs;
+ if (prefsName != null) {
+ prefs = Preferences.userRoot().node(prefsName);
+ } else {
+ prefs = Preferences.userNodeForPackage(CheckForUpdates.class);
+ }
- if (forceCheckURL != null && DEBUG_VERSION_CHECK) {
- System.out.println("Explicit version check URL: " + forceCheckURL);
+ String queryURL = QUERY_URL;
+ String forceCheckURL = System.getProperty(PROPERTY_QUERY_URL);
+
+ if (forceCheckURL != null) {
+ branch.log(CHECK_INFO, "Explicit version check URL: " + forceCheckURL);
+ queryURL = forceCheckURL;
}
// Get our unique user id (based on absolute timestamp).
//
long currentTimeMillis = System.currentTimeMillis();
- Preferences prefs = Preferences.userNodeForPackage(CheckForUpdates.class);
-
- // Get our unique user id (based on absolute timestamp).
- //
String firstLaunch = prefs.get(FIRST_LAUNCH, null);
if (firstLaunch == null) {
firstLaunch = Long.toHexString(currentTimeMillis);
prefs.put(FIRST_LAUNCH, firstLaunch);
-
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Setting first launch to " + firstLaunch);
- }
+ branch.log(CHECK_SPAM, "Setting first launch to " + firstLaunch);
} else {
- if (DEBUG_VERSION_CHECK) {
- System.out.println("First launch was " + firstLaunch);
+ branch.log(CHECK_SPAM, "First launch was " + firstLaunch);
+ }
+
+ // See if enough time has passed.
+ //
+ String lastPing = prefs.get(LAST_PING, "0");
+ if (lastPing != null) {
+ try {
+ long lastPingTime = Long.parseLong(lastPing);
+ if (currentTimeMillis < lastPingTime + minCheckMillis) {
+ // it's not time yet
+ branch.log(CHECK_INFO, "Last ping was " + new Date(lastPingTime)
+ + ", min wait is " + minCheckMillis + "ms");
+ return null;
+ }
+ } catch (NumberFormatException e) {
+ branch.log(CHECK_WARN, "Error parsing last ping time", e);
}
}
@@ -363,73 +302,86 @@
long nextPingTime = Long.parseLong(nextPing);
if (currentTimeMillis < nextPingTime) {
// it's not time yet
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Next ping is not until "
- + new Date(nextPingTime));
- }
- return;
+ branch.log(CHECK_INFO, "Next ping is not until "
+ + new Date(nextPingTime));
+ return null;
}
} catch (NumberFormatException e) {
- // ignore
+ branch.log(CHECK_WARN, "Error parsing next ping time", e);
}
}
// See if new version is available.
//
- String queryURL = forceCheckURL != null ? forceCheckURL : QUERY_URL;
String url = queryURL + "?v=" + About.GWT_VERSION_NUM + "&id="
- + firstLaunch;
-
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Checking for new version at " + url);
+ + firstLaunch + "&r=" + About.GWT_SVNREV;
+ if (entryPoint != null) {
+ url += "&e=" + entryPoint;
}
+ branch.log(CHECK_INFO, "Checking for new version at " + url);
+
// Do the HTTP GET.
//
byte[] response;
String fullUserAgent = makeUserAgent();
- if (System.getProperty("gwt.forceVersionCheckNonNative") == null) {
+ if (System.getProperty(PROPERTY_FORCE_NONNATIVE) == null) {
// Use subclass.
//
- response = doHttpGet(fullUserAgent, url);
+ response = doHttpGet(branch, fullUserAgent, url);
} else {
// Use the pure Java version, but it probably doesn't work with proxies.
//
- response = httpGetNonNative(fullUserAgent, url);
+ response = httpGetNonNative(branch, fullUserAgent, url);
}
if (response == null || response.length == 0) {
// Problem. Quietly fail.
//
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Failed to obtain current version info via HTTP");
- }
- return;
+ branch.log(CHECK_ERROR,
+ "Failed to obtain current version info via HTTP");
+ return null;
}
// Parse and process the response.
// Bad responses will be silently ignored.
//
- parseResponse(prefs, response, callback);
+ return parseResponse(branch, prefs, response);
} catch (Throwable e) {
// Always silently ignore any errors.
//
- if (DEBUG_VERSION_CHECK) {
- System.out.println("Exception while processing version info");
- e.printStackTrace();
- }
+ branch.log(CHECK_INFO, "Exception while processing version info", e);
}
+ return null;
}
- protected abstract byte[] doHttpGet(String userAgent, String url);
+ /**
+ * Default implementation just uses the platform-independent method. A
+ * subclass should override this method for platform-dependent proxy handling,
+ * for example.
+ *
+ * @param branch TreeLogger to use
+ * @param userAgent user agent string to send in request
+ * @param url URL to fetch
+ * @return byte array of response, or null if an error
+ */
+ protected byte[] doHttpGet(TreeLogger branch, String userAgent, String url) {
+ return httpGetNonNative(branch, userAgent, url);
+ }
/**
* This default implementation uses regular Java HTTP, which doesn't deal with
* proxies automagically. See the IE6 subclasses for an implementation that
* does deal with proxies.
+ *
+ * @param branch TreeLogger to use
+ * @param userAgent user agent string to send in request
+ * @param url URL to fetch
+ * @return byte array of response, or null if an error
*/
- protected byte[] httpGetNonNative(String userAgent, String url) {
+ protected byte[] httpGetNonNative(TreeLogger branch, String userAgent,
+ String url) {
Throwable caught;
InputStream is = null;
try {
@@ -458,8 +410,8 @@
}
}
- if (System.getProperty("gwt.debugLowLevelHttpGet") != null) {
- caught.printStackTrace();
+ if (System.getProperty(PROPERTY_DEBUG_HTTP_GET) != null) {
+ branch.log(CHECK_ERROR, "Exception in HTTP request", caught);
}
return null;
@@ -496,4 +448,165 @@
return ua;
}
+
+ private UpdateResult parseResponse(TreeLogger branch, Preferences prefs,
+ byte[] response) throws IOException, ParserConfigurationException,
+ SAXException {
+
+ branch.log(CHECK_SPAM, "Parsing response (length " + response.length + ")");
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ ByteArrayInputStream bais = new ByteArrayInputStream(response);
+
+ // Parse the XML.
+ //
+ builder.setErrorHandler(new ErrorHandler() {
+
+ public void error(SAXParseException exception) throws SAXException {
+ // fail quietly
+ }
+
+ public void fatalError(SAXParseException exception) throws SAXException {
+ // fail quietly
+ }
+
+ public void warning(SAXParseException exception) throws SAXException {
+ // fail quietly
+ }
+ });
+ Document doc = builder.parse(bais);
+
+ // The latest version number.
+ //
+ String versionString = getTextOfLastElementHavingTag(doc, "latest-version");
+ if (versionString == null) {
+ // Not valid; quietly fail.
+ //
+ branch.log(CHECK_ERROR, "Failed to find <latest-version>");
+ return null;
+ }
+ GwtVersion currentReleasedVersion;
+ try {
+ currentReleasedVersion = new GwtVersion(versionString.trim());
+ } catch (NumberFormatException e) {
+ branch.log(CHECK_ERROR, "Bad version: " + versionString, e);
+ return null;
+ }
+
+ // Ping delay for server-controlled throttling.
+ //
+ String pingDelaySecsStr = getTextOfLastElementHavingTag(doc,
+ "min-wait-seconds");
+ int pingDelaySecs = 0;
+ if (pingDelaySecsStr == null) {
+ // Not valid; quietly fail.
+ //
+ branch.log(CHECK_ERROR, "Missing <min-wait-seconds>");
+ return null;
+ }
+ try {
+ pingDelaySecs = Integer.parseInt(pingDelaySecsStr.trim());
+ } catch (NumberFormatException e) {
+ // Not a valid number; quietly fail.
+ //
+ branch.log(CHECK_ERROR, "Bad min-wait-seconds number: "
+ + pingDelaySecsStr);
+ return null;
+ }
+
+ String url = getTextOfLastElementHavingTag(doc, "notification-url");
+
+ if (url == null) {
+ // no URL, so write the HTML locally and provide a URL from that
+
+ // Read the HTML.
+ //
+ String html = getTextOfLastElementHavingTag(doc, "notification");
+
+ if (html == null) {
+ // Not valid; quietly fail.
+ //
+ branch.log(CHECK_ERROR, "Missing <notification>");
+ return null;
+ }
+ PrintWriter writer = null;
+ try {
+ String tempDir = System.getProperty("java.io.tmpdir");
+ File updateHtml = new File(tempDir, "gwt-update-"
+ + currentReleasedVersion + ".html");
+ writer = new PrintWriter(new FileOutputStream(updateHtml));
+ writer.print(html);
+ url = "file://" + updateHtml.getAbsolutePath();
+ } finally {
+ if (writer != null) {
+ writer.close();
+ }
+ }
+ }
+
+ // Okay -- this is a valid response.
+ //
+ return processResponse(branch, prefs, currentReleasedVersion,
+ pingDelaySecs, url);
+ }
+
+ private UpdateResult processResponse(TreeLogger branch, Preferences prefs,
+ final GwtVersion serverVersion, int pingDelaySecs, final String notifyUrl) {
+
+ // Record a ping; don't ping again until the delay is up.
+ //
+ long currentTimeMillis = System.currentTimeMillis();
+ long nextPingTime = currentTimeMillis + pingDelaySecs * 1000;
+ prefs.put(NEXT_PING, String.valueOf(nextPingTime));
+ prefs.put(LAST_PING, String.valueOf(currentTimeMillis));
+
+ branch.log(CHECK_INFO, "Ping delay is " + pingDelaySecs + "; next ping at "
+ + new Date(nextPingTime));
+
+ if (myVersion.isNoNagVersion()) {
+ // If the version number indicates no nagging about updates, exit here
+ // once we have recorded the next ping time. No-nag versions (ie,
+ // trunk builds) should also not update the highest version that has been
+ // run.
+ return null;
+ }
+
+ // Update the highest version of GWT that has been run if we are later.
+ GwtVersion highestRunVersion = new GwtVersion(prefs.get(
+ HIGHEST_RUN_VERSION, null));
+ if (myVersion.compareTo(highestRunVersion) > 0) {
+ highestRunVersion = myVersion;
+ prefs.put(HIGHEST_RUN_VERSION, highestRunVersion.toString());
+ }
+
+ // Are we up to date already?
+ //
+ if (highestRunVersion.compareTo(serverVersion) >= 0) {
+ // Yes, we are.
+ //
+ branch.log(CHECK_INFO, "Server version (" + serverVersion
+ + ") is not newer than " + highestRunVersion);
+ return null;
+ }
+
+ // Commence nagging.
+ //
+ URL url = null;
+ try {
+ url = new URL(notifyUrl);
+ } catch (MalformedURLException e) {
+ logger.log(CHECK_ERROR, "Malformed notify URL: " + notifyUrl, e);
+ }
+ final URL finalUrl = url;
+ return new UpdateResult() {
+ public GwtVersion getNewVersion() {
+ return serverVersion;
+ }
+
+ public URL getURL() {
+ return finalUrl;
+ }
+ };
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
index 90e5ebe..ebc2778 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
@@ -360,7 +360,7 @@
private static EmmaStrategy emmaStrategy;
- private static final Pattern GENERATED_CLASSNAME_PATTERN = Pattern.compile(".+\\$\\d+(\\$.*)?");
+ private static final Pattern GENERATED_CLASSNAME_PATTERN = Pattern.compile(".+\\$\\d.*");
/**
* Caches the byte code for {@link JavaScriptHost}.
@@ -390,9 +390,10 @@
/**
* Checks if the class names is generated. Accepts any classes whose names
- * match .+$\d+($.*)? (handling named classes within anonymous classes).
- * Checks if the class or any of its enclosing classes are anonymous or
- * synthetic.
+ * match .+$\d.* (handling named classes within anonymous classes and
+ * multiple named classes of the same name in a class, but in different
+ * methods). Checks if the class or any of its enclosing classes are anonymous
+ * or synthetic.
* <p>
* If new compilers have different conventions for anonymous and synthetic
* classes, this code needs to be updated.
@@ -744,7 +745,7 @@
lookupClassName);
CompilationUnit unit = (compiledClass == null)
- ? getUnitForClassName(className) : compiledClass.getUnit();
+ ? getUnitForClassName(lookupClassName) : compiledClass.getUnit();
if (emmaAvailable) {
/*
* build the map for anonymous classes. Do so only if unit has anonymous
@@ -756,20 +757,12 @@
if (unit != null && !unit.isSuperSource() && unit.hasAnonymousClasses()
&& jsniMethods != null && jsniMethods.size() > 0
&& !unit.createdClassMapping()) {
- String mainLookupClassName = unit.getTypeName().replace('.', '/');
- byte mainClassBytes[] = emmaStrategy.getEmmaClassBytes(null,
- mainLookupClassName, 0);
- if (mainClassBytes != null) {
- if (!unit.constructAnonymousClassMappings(mainClassBytes)) {
- logger.log(TreeLogger.ERROR,
- "Our heuristic for mapping anonymous classes between compilers "
- + "failed. Unsafe to continue because the wrong jsni code "
- + "could end up running. className = " + className);
- return null;
- }
- } else {
- logger.log(TreeLogger.ERROR, "main class bytes is null for unit = "
- + unit + ", mainLookupClassName = " + mainLookupClassName);
+ if (!unit.constructAnonymousClassMappings(logger)) {
+ logger.log(TreeLogger.ERROR,
+ "Our heuristic for mapping anonymous classes between compilers "
+ + "failed. Unsafe to continue because the wrong jsni code "
+ + "could end up running. className = " + className);
+ return null;
}
}
}
@@ -791,7 +784,8 @@
* find it on disk. Typically this is a synthetic class added by the
* compiler.
*/
- if (typeHasCompilationUnit(className) && isClassnameGenerated(className)) {
+ if (typeHasCompilationUnit(lookupClassName)
+ && isClassnameGenerated(className)) {
/*
* modification time = 0 ensures that whatever is on the disk is always
* loaded.
@@ -827,17 +821,19 @@
/**
* Returns the compilationUnit corresponding to the className. For nested
* classes, the unit corresponding to the top level type is returned.
+ *
+ * Since a file might have several top-level types, search using classFileMap.
*/
private CompilationUnit getUnitForClassName(String className) {
String mainTypeName = className;
int index = mainTypeName.length();
- CompilationUnit unit = null;
- while (unit == null && index != -1) {
+ CompiledClass cc = null;
+ while (cc == null && index != -1) {
mainTypeName = mainTypeName.substring(0, index);
- unit = compilationState.getCompilationUnitMap().get(mainTypeName);
+ cc = compilationState.getClassFileMap().get(mainTypeName);
index = mainTypeName.lastIndexOf('$');
}
- return unit;
+ return cc == null ? null : cc.getUnit();
}
private void injectJsniMethods(CompilationUnit unit) {
diff --git a/dev/core/src/com/google/gwt/dev/shell/LowLevel.java b/dev/core/src/com/google/gwt/dev/shell/LowLevel.java
index 9469c01..40f962f 100644
--- a/dev/core/src/com/google/gwt/dev/shell/LowLevel.java
+++ b/dev/core/src/com/google/gwt/dev/shell/LowLevel.java
@@ -103,7 +103,6 @@
+ "'. Detailed error:\n");
sb.append(e.getMessage() + ")\n\n");
sb.append("Your GWT installation may be corrupt");
- System.err.println(sb.toString());
throw new UnsatisfiedLinkError(sb.toString());
}
sInitialized = true;
diff --git a/dev/core/src/com/google/gwt/dev/shell/PlatformSpecific.java b/dev/core/src/com/google/gwt/dev/shell/PlatformSpecific.java
index 30a834d..cd25809 100644
--- a/dev/core/src/com/google/gwt/dev/shell/PlatformSpecific.java
+++ b/dev/core/src/com/google/gwt/dev/shell/PlatformSpecific.java
@@ -17,12 +17,20 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.TreeLogger.HelpInfo;
+import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* Performs platform-specific class selection.
@@ -38,12 +46,51 @@
"com.google.gwt.dev.shell.mac.BrowserWidgetSaf"};
/**
- * All of these classes must extend CheckForUpdates.
+ * All of these classes must extend CheckForUpdates. Note that currently only
+ * IE has a custom implementation (to handle proxies) and that CheckForUpdates
+ * must be the last one in the list.
*/
private static final String[] updaterClassNames = new String[] {
"com.google.gwt.dev.shell.ie.CheckForUpdatesIE6",
- "com.google.gwt.dev.shell.moz.CheckForUpdatesMoz",
- "com.google.gwt.dev.shell.mac.CheckForUpdatesSaf"};
+ "com.google.gwt.dev.shell.CheckForUpdates"};
+
+ public static FutureTask<UpdateResult> checkForUpdatesInBackgroundThread(
+ final TreeLogger logger, final long minCheckMillis) {
+ final String entryPoint = PlatformSpecific.computeEntryPoint();
+ FutureTask<UpdateResult> task = new FutureTask<UpdateResult>(
+ new Callable<UpdateResult>() {
+ public UpdateResult call() throws Exception {
+ final CheckForUpdates updateChecker = createUpdateChecker(logger,
+ entryPoint);
+ return updateChecker == null ? null
+ : updateChecker.check(minCheckMillis);
+ }
+ });
+ Thread checkerThread = new Thread(task, "GWT Update Checker");
+ checkerThread.setDaemon(true);
+ checkerThread.start();
+ return task;
+ }
+
+ /**
+ * Find the first method named "main" on the call stack and use its class as
+ * the entry point.
+ */
+ public static String computeEntryPoint() {
+ Throwable t = new Throwable();
+ for (StackTraceElement stackTrace : t.getStackTrace()) {
+ if (stackTrace.getMethodName().equals("main")) {
+ // Strip package name from main's class
+ String className = stackTrace.getClassName();
+ int i = className.lastIndexOf('.');
+ if (i >= 0) {
+ return className.substring(i + 1);
+ }
+ return className;
+ }
+ }
+ return null;
+ }
public static BrowserWidget createBrowserWidget(TreeLogger logger,
Composite parent, BrowserWidgetHost host)
@@ -51,10 +98,11 @@
Throwable caught = null;
try {
for (int i = 0; i < browserClassNames.length; i++) {
- Class<BrowserWidget> clazz = null;
+ Class<? extends BrowserWidget> clazz = null;
try {
- clazz = (Class<BrowserWidget>) Class.forName(browserClassNames[i]);
- Constructor<BrowserWidget> ctor = clazz.getDeclaredConstructor(new Class[] {
+ clazz = Class.forName(browserClassNames[i]).asSubclass(
+ BrowserWidget.class);
+ Constructor<? extends BrowserWidget> ctor = clazz.getDeclaredConstructor(new Class[] {
Shell.class, BrowserWidgetHost.class});
BrowserWidget bw = ctor.newInstance(new Object[] {parent, host});
return bw;
@@ -85,16 +133,25 @@
throw new UnableToCompleteException();
}
- public static CheckForUpdates createUpdateChecker() {
+ public static CheckForUpdates createUpdateChecker(TreeLogger logger) {
+ return createUpdateChecker(logger, computeEntryPoint());
+ }
+
+ public static CheckForUpdates createUpdateChecker(TreeLogger logger,
+ String entryPoint) {
try {
for (int i = 0; i < updaterClassNames.length; i++) {
try {
- Class<CheckForUpdates> clazz = (Class<CheckForUpdates>) Class.forName(updaterClassNames[i]);
- Constructor<CheckForUpdates> ctor = clazz.getDeclaredConstructor(new Class[] {});
- CheckForUpdates checker = ctor.newInstance(new Object[] {});
+ Class<? extends CheckForUpdates> clazz = Class.forName(
+ updaterClassNames[i]).asSubclass(CheckForUpdates.class);
+ Constructor<? extends CheckForUpdates> ctor = clazz.getDeclaredConstructor(new Class[] {
+ TreeLogger.class, String.class});
+ CheckForUpdates checker = ctor.newInstance(new Object[] {
+ logger, entryPoint});
return checker;
- } catch (ClassNotFoundException e) {
- // keep trying
+ } catch (Exception e) {
+ // Other exceptions can occur besides ClassNotFoundException,
+ // so ignore them all so we can find a functional updater.
}
}
} catch (Throwable e) {
@@ -102,4 +159,34 @@
}
return null;
}
+
+ public static void logUpdateAvailable(TreeLogger logger,
+ FutureTask<UpdateResult> updater) {
+ if (updater != null && updater.isDone()) {
+ UpdateResult result = null;
+ try {
+ result = updater.get(0, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // Silently ignore exception
+ } catch (ExecutionException e) {
+ // Silently ignore exception
+ } catch (TimeoutException e) {
+ // Silently ignore exception
+ }
+ logUpdateAvailable(logger, result);
+ }
+ }
+
+ public static void logUpdateAvailable(TreeLogger logger, UpdateResult result) {
+ if (result != null) {
+ final URL url = result.getURL();
+ logger.log(TreeLogger.WARN, "A new version of GWT ("
+ + result.getNewVersion() + ") is available", null, new HelpInfo() {
+ @Override
+ public URL getURL() {
+ return url;
+ }
+ });
+ }
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java b/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java
index 031cc44..e9a1e5e 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java
@@ -17,6 +17,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.shell.BrowserWindowController.WebServerRestart;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.TreeLoggerWidget;
@@ -50,6 +51,7 @@
private ToolItem collapseAll;
private ToolItem expandAll;
private ToolItem newWindow;
+ private ToolItem restartServer;
public Toolbar(Composite parent) {
super(parent);
@@ -69,9 +71,27 @@
}
}
});
-
newSeparator();
+ if (browserWindowController.hasWebServer() != WebServerRestart.NONE) {
+ restartServer = newItem("reload-server.gif", "&Restart Server",
+ "Restart the embedded web server to pick up code changes");
+ restartServer.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ try {
+ browserWindowController.restartServer(getLogger());
+ } catch (UnableToCompleteException e) {
+ getLogger().log(TreeLogger.ERROR, "Unable to restart server", e);
+ }
+ }
+ });
+ newSeparator();
+ if (browserWindowController.hasWebServer() == WebServerRestart.DISABLED) {
+ restartServer.setEnabled(false);
+ }
+ }
+
collapseAll = newItem("collapse.gif", "&Collapse All",
"Collapses all log entries");
collapseAll.addSelectionListener(new SelectionAdapter() {
@@ -181,9 +201,8 @@
private Toolbar toolbar;
public ShellMainWindow(BrowserWindowController browserWindowController,
- final Shell parent, int serverPort, boolean checkForUpdates) {
+ Shell parent, String titleText, int serverPort) {
super(parent, SWT.NONE);
-
this.browserWindowController = browserWindowController;
colorWhite = new Color(null, 255, 255, 255);
@@ -193,10 +212,9 @@
setLayout(new FillLayout());
if (serverPort > 0) {
- parent.setText("Google Web Toolkit Development Shell / Port "
- + serverPort);
+ parent.setText(titleText + " / Port " + serverPort);
} else {
- parent.setText("Google Web Toolkit Development Shell");
+ parent.setText(titleText);
}
GridLayout gridLayout = new GridLayout(1, true);
@@ -207,7 +225,6 @@
setLayout(gridLayout);
// Create the toolbar.
- //
{
toolbar = new Toolbar(this);
GridData data = new GridData();
@@ -217,7 +234,6 @@
}
// Create the log pane.
- //
{
logPane = new TreeLoggerWidget(this);
GridData data = new GridData();
@@ -227,41 +243,6 @@
data.verticalAlignment = GridData.FILL;
logPane.setLayoutData(data);
}
-
- // check for updates
- if (checkForUpdates) {
- try {
- final CheckForUpdates updateChecker = PlatformSpecific.createUpdateChecker();
- if (updateChecker != null) {
- final CheckForUpdates.UpdateAvailableCallback callback = new CheckForUpdates.UpdateAvailableCallback() {
- public void onUpdateAvailable(final String html) {
- // Do this on the main thread.
- //
- parent.getDisplay().asyncExec(new Runnable() {
- public void run() {
- new BrowserDialog(parent, getLogger(), html).open(true);
- }
-
- });
- }
- };
-
- // Run the update checker on a background thread.
- //
- Thread checkerThread = new Thread() {
- @Override
- public void run() {
- updateChecker.check(callback);
- }
- };
-
- checkerThread.setDaemon(true);
- checkerThread.start();
- }
- } catch (Throwable e) {
- // Always silently ignore any errors.
- }
- }
}
public AbstractTreeLogger getLogger() {
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 58ed521..d47b05b 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
@@ -23,6 +23,7 @@
import org.mortbay.jetty.Server;
import org.mortbay.jetty.nio.SelectChannelConnector;
+import org.mortbay.jetty.webapp.WebAppClassLoader;
import org.mortbay.jetty.webapp.WebAppContext;
import org.mortbay.log.Log;
import org.mortbay.log.Logger;
@@ -137,8 +138,8 @@
private final int actualPort;
private final File appRootDir;
private final TreeLogger logger;
- private final WebAppContext wac;
private final Server server;
+ private final WebAppContext wac;
public JettyServletContainer(TreeLogger logger, Server server,
WebAppContext wac, int actualPort, File appRootDir) {
@@ -188,7 +189,61 @@
}
}
- @SuppressWarnings("unchecked")
+ /**
+ * A {@link WebAppContext} tailored to GWT hosted mode. Features hot-reload
+ * with a new {@link WebAppClassLoader} to pick up disk changes. The default
+ * Jetty {@code WebAppContext} will create new instances of servlets, but it
+ * will not create a brand new {@link ClassLoader}. By creating a new
+ * {@code ClassLoader} each time, we re-read updated classes from disk.
+ *
+ * Also provides special class filtering to isolate the web app from the GWT
+ * hosting environment.
+ */
+ private 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.
+ */
+ private final ClassLoader parentClassLoader = new ClassLoader(null) {
+ private final ClassLoader delegateTo = Thread.currentThread().getContextClassLoader();
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (webAppClassLoader != null
+ && (webAppClassLoader.isServerPath(name) || webAppClassLoader.isSystemPath(name))) {
+ return delegateTo.loadClass(name);
+ }
+ throw new ClassNotFoundException();
+ }
+
+ };
+
+ private WebAppClassLoader webAppClassLoader;
+
+ @SuppressWarnings("unchecked")
+ private WebAppContextWithReload(String webApp, String contextPath) {
+ super(webApp, contextPath);
+ // Prevent file locking on Windows; pick up file changes.
+ getInitParams().put(
+ "org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false");
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ webAppClassLoader = new WebAppClassLoader(parentClassLoader, this);
+ setClassLoader(webAppClassLoader);
+ super.doStart();
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ super.doStop();
+ webAppClassLoader = null;
+ setClassLoader(null);
+ }
+ }
+
public ServletContainer start(TreeLogger logger, int port, File appRootDir)
throws Exception {
checkStartParams(logger, port, appRootDir);
@@ -221,11 +276,8 @@
server.addConnector(connector);
// Create a new web app in the war directory.
- WebAppContext wac = new WebAppContext(appRootDir.getAbsolutePath(), "/");
-
- // Prevent file locking on Windows; pick up file changes.
- wac.getInitParams().put(
- "org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false");
+ WebAppContext wac = new WebAppContextWithReload(
+ appRootDir.getAbsolutePath(), "/");
server.setHandler(wac);
server.start();
diff --git a/dev/core/src/com/google/gwt/dev/shell/reload-server.gif b/dev/core/src/com/google/gwt/dev/shell/reload-server.gif
new file mode 100644
index 0000000..129f92b
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/shell/reload-server.gif
Binary files differ
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableUpdateCheck.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableUpdateCheck.java
new file mode 100644
index 0000000..142f69c
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDisableUpdateCheck.java
@@ -0,0 +1,51 @@
+/*
+ * 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.util.arg;
+
+import com.google.gwt.util.tools.ArgHandlerFlag;
+
+/**
+ * Handles the -XdisableUpdateCheck command line flag.
+ */
+public final class ArgHandlerDisableUpdateCheck extends ArgHandlerFlag {
+
+ private final OptionDisableUpdateCheck option;
+
+ public ArgHandlerDisableUpdateCheck(OptionDisableUpdateCheck option) {
+ this.option = option;
+ }
+
+ @Override
+ public String getPurpose() {
+ return "Disable the check to see if an update version of GWT is available";
+ }
+
+ @Override
+ public String getTag() {
+ return "-XdisableUpdateCheck";
+ }
+
+ @Override
+ public boolean isUndocumented() {
+ return true;
+ }
+
+ @Override
+ public boolean setFlag() {
+ option.setDisableUpdateCheck(true);
+ return true;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionDisableUpdateCheck.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionDisableUpdateCheck.java
new file mode 100644
index 0000000..085d0d2
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionDisableUpdateCheck.java
@@ -0,0 +1,32 @@
+/*
+ * 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.util.arg;
+
+/**
+ * Option to set the compiler working directory.
+ */
+public interface OptionDisableUpdateCheck {
+
+ /**
+ * Check to see if update checks are disabled.
+ */
+ boolean isUpdateCheckDisabled();
+
+ /**
+ * Sets the disable update check flag.
+ */
+ void setDisableUpdateCheck(boolean disabled);
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameComparatorTest.java b/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameComparatorTest.java
index 630d438..3af1a6a 100644
--- a/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameComparatorTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameComparatorTest.java
@@ -1,3 +1,18 @@
+/*
+ * 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.dev.javac;
import junit.framework.TestCase;
@@ -38,8 +53,21 @@
}
public void testMixedNames() {
- String original[] = {"Foo", "Foo$1", "Foo$1xyz", "Foo$2", "Foo$xyz"};
- String expected[] = {"Foo", "Foo$1", "Foo$2", "Foo$1xyz", "Foo$xyz"};
+ String original[] = {
+ "Foo", "Foo$1", "Foo$1Bar", "Foo$2Bar", "Foo$2", "Foo$xyz"};
+ String expected[] = {
+ "Foo", "Foo$1", "Foo$2", "Foo$1Bar", "Foo$2Bar", "Foo$xyz"};
+ Arrays.sort(original, new GeneratedClassnameComparator());
+ for (int i = 0; i < original.length; i++) {
+ assertEquals("index = " + i, expected[i], original[i]);
+ }
+ }
+
+ public void testMultipleToplevelClasses() {
+ String original[] = {
+ "Foo$1", "Foo$2", "Bar$1", "Bar$3", "Foo$2$1", "Bar$2$1"};
+ String expected[] = {
+ "Bar$1", "Bar$3", "Foo$1", "Foo$2", "Bar$2$1", "Foo$2$1"};
Arrays.sort(original, new GeneratedClassnameComparator());
for (int i = 0; i < original.length; i++) {
assertEquals("index = " + i, expected[i], original[i]);
diff --git a/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java b/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java
new file mode 100644
index 0000000..0f428e2
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/GeneratedClassnameFinderTest.java
@@ -0,0 +1,371 @@
+/*
+ * 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.dev.javac;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.javac.CompilationUnit.GeneratedClassnameFinder;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+
+/**
+ * Test-cases to check that we indeed obtain the correct list of nested types
+ * with generated classNames by examining bytecodes using ASM.
+ *
+ */
+public class GeneratedClassnameFinderTest extends TestCase {
+ enum EnumClass {
+ A, B, C,
+ }
+
+ static class MainClass {
+ static class NestedClass {
+ void foo() {
+ TestInterface c = new TestInterface() {
+ public void foo() {
+ }
+ };
+ EnumClass et = EnumClass.A;
+ switch (et) {
+ case A:
+ break;
+ }
+ TestInterface d = new TestInterface() {
+ public void foo() {
+ }
+ };
+ }
+ }
+
+ void foo() {
+ TestInterface a = new TestInterface() {
+ public void foo() {
+ }
+ };
+ EnumClass et = EnumClass.A;
+ switch (et) {
+ case A:
+ break;
+ }
+ TestInterface b = new TestInterface() {
+ public void foo() {
+ }
+ };
+ }
+ }
+ interface TestInterface {
+ void foo();
+ }
+
+ static final TreeLogger logger = new PrintWriterTreeLogger();
+
+ public void test() {
+ String mainClassName = this.getClass().getName().replace('.', '/');
+ assertEquals(
+ 4,
+ new GeneratedClassnameFinder(logger, mainClassName).getClassNames().size());
+ assertEquals(0, new GeneratedClassnameFinder(logger, mainClassName
+ + "$EnumClass").getClassNames().size());
+ assertEquals(0, new GeneratedClassnameFinder(logger, mainClassName
+ + "$TestInterface").getClassNames().size());
+ assertEquals(4, new GeneratedClassnameFinder(logger, mainClassName
+ + "$MainClass").getClassNames().size());
+ assertEquals(2, new GeneratedClassnameFinder(logger, mainClassName
+ + "$MainClass$NestedClass").getClassNames().size());
+ }
+
+ public void testAnonymous() {
+ assertEquals(1, new AnonymousTester().getGeneratedClasses().size());
+ }
+
+ public void testEnum() {
+ assertEquals(0, new EnumTester().getGeneratedClasses().size());
+ }
+
+ public void testJavacWeirdness() {
+ List<String> classNames = new JavacWeirdnessTester().getGeneratedClasses();
+ assertEquals(3, classNames.size());
+ assertTrue(classNames.get(0) + " should not contain Foo",
+ classNames.get(0).indexOf("Foo") == -1);
+ assertTrue(classNames.get(1) + " should contain Foo",
+ classNames.get(1).indexOf("Foo") != -1);
+ assertTrue(classNames.get(2) + " should contain Foo",
+ classNames.get(2).indexOf("Foo") != -1);
+ }
+
+ public void testNamedLocal() {
+ assertEquals(2, new NamedLocalTester().getGeneratedClasses().size());
+ }
+
+ public void testNested() {
+ assertEquals(2, new NestedTester().getGeneratedClasses().size());
+ }
+
+ public void testStatic() {
+ assertEquals(0, new StaticTester().getGeneratedClasses().size());
+ }
+
+ public void testTopLevel() {
+ assertEquals(1, new TopLevelTester().getGeneratedClasses().size());
+ }
+
+}
+
+/**
+ * For testing a class containing an anonymous inner class.
+ */
+class AnonymousTester {
+ interface TestInterface {
+ void foo();
+ }
+
+ void foo() {
+ TestInterface a = new TestInterface() {
+ public void foo() {
+ }
+ };
+ a.foo();
+ }
+
+ List<String> getGeneratedClasses() {
+ return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+ this.getClass().getName().replace('.', '/'))).getClassNames();
+ }
+}
+
+/**
+ * For testing a class with an Enum (for which javac generates a synthetic
+ * class).
+ */
+class EnumTester {
+ enum EnumClass {
+ A, B, C,
+ }
+
+ void foo() {
+ EnumClass et = EnumClass.A;
+ switch (et) {
+ case A:
+ break;
+ }
+ }
+
+ List<String> getGeneratedClasses() {
+ return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+ this.getClass().getName().replace('.', '/'))).getClassNames();
+ }
+}
+
+/**
+ * Javac generates weird code for the following class. It passes a synthetic
+ * class ...Tester$1 as a first parameter to constructors of Fuji and Granny.
+ * Normally, it generates the synthetic class, but in this case, it decides not
+ * to generate the class. However, the bytecode still has reference to the
+ * synthetic class -- it just passes null for the synthetic class.
+ *
+ * This code also tests for an anonymous class extending a named local class.
+ */
+class JavacWeirdnessTester {
+ private abstract static class Apple implements Fruit {
+ }
+
+ private static interface Fruit {
+ }
+
+ private static class Fuji extends Apple {
+ }
+
+ private static class Granny extends Apple {
+ }
+
+ private static volatile boolean TRUE = true;
+
+ List<String> getGeneratedClasses() {
+ return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+ this.getClass().getName().replace('.', '/'))).getClassNames();
+ }
+
+ private void assertEquals(Object a, Object b) {
+ }
+
+ private void testArrayStore() {
+ Apple[] apple = TRUE ? new Granny[3] : new Apple[3];
+ Apple g = TRUE ? (Apple) new Granny() : (Apple) new Fuji();
+ Apple a = apple[0] = g;
+ assertEquals(g, a);
+ }
+
+ private void testDeadTypes() {
+ if (false) {
+ new Object() {
+ }.toString();
+
+ class Foo {
+ void a() {
+ }
+ }
+ new Foo().a();
+ }
+ }
+
+ private void testLocalClasses() {
+ class Foo {
+ public Foo(int j) {
+ assertEquals(1, j);
+ };
+ }
+ final int i;
+ new Foo(i = 1) {
+ {
+ assertEquals(1, i);
+ }
+ };
+ assertEquals(1, i);
+ }
+
+ private void testReturnStatementInCtor() {
+ class Foo {
+ int i;
+
+ Foo(int i) {
+ this.i = i;
+ if (i == 0) {
+ return;
+ } else if (i == 1) {
+ return;
+ }
+ return;
+ }
+ }
+ assertEquals(new Foo(0).i, 0);
+ }
+}
+
+/**
+ * For testing a class with a generated name like $1Foo.
+ */
+class NamedLocalTester {
+ void foo1() {
+ if (false) {
+ class Foo {
+ void foo() {
+ }
+ }
+ new Foo().foo();
+ }
+ }
+
+ void foo2() {
+ class Foo {
+ void foo() {
+ }
+ }
+ new Foo().foo();
+ }
+
+ void foo3() {
+ class Foo {
+ void foo() {
+ }
+ }
+ new Foo().foo();
+ }
+
+ List<String> getGeneratedClasses() {
+ return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+ this.getClass().getName().replace('.', '/'))).getClassNames();
+ }
+}
+
+/**
+ * For testing that nested classes are examined recursively for classes with
+ * generated names.
+ */
+class NestedTester {
+ class MainClass {
+ class NestedClass {
+ void foo() {
+ class Foo {
+ void bar() {
+ }
+ }
+ new Foo().bar();
+ }
+ }
+
+ void foo() {
+ class Foo {
+ void bar() {
+ }
+ }
+ new Foo().bar();
+ }
+ }
+
+ List<String> getGeneratedClasses() {
+ return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+ this.getClass().getName().replace('.', '/'))).getClassNames();
+ }
+}
+
+/**
+ * For testing classes with private static members (javac generates a synthetic
+ * class here but the jdt does not).
+ */
+class StaticTester {
+ private abstract static class Apple implements Fruit {
+ }
+
+ private static interface Fruit {
+ void bar();
+ }
+
+ private static class Fuji extends Apple {
+ public void bar() {
+ }
+ }
+
+ private static class Granny extends Apple {
+ public void bar() {
+ }
+ }
+
+ List<String> getGeneratedClasses() {
+ return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+ this.getClass().getName().replace('.', '/'))).getClassNames();
+ }
+
+}
+
+/**
+ * For testing that a class with a generated name inside another top-level class
+ * is found.
+ */
+class TopLevelTester {
+ public void foo() {
+ GeneratedClassnameFinderTest.TestInterface a = new GeneratedClassnameFinderTest.TestInterface() {
+ public void foo() {
+ }
+ };
+ }
+
+ List<String> getGeneratedClasses() {
+ return (new GeneratedClassnameFinder(GeneratedClassnameFinderTest.logger,
+ this.getClass().getName().replace('.', '/'))).getClassNames();
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java b/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
index c72d651..c42d98e 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/AbstractResourceOrientedTestBase.java
@@ -25,7 +25,8 @@
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
-import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
@@ -67,14 +68,14 @@
}
@Override
- public Set<AbstractResource> findApplicableResources(TreeLogger logger,
- PathPrefixSet pathPrefixSet) {
- Set<AbstractResource> results = new HashSet<AbstractResource>();
- Set<AbstractResource> rs = cpe.findApplicableResources(logger,
- pathPrefixSet);
- for (AbstractResource r : rs) {
+ public Map<AbstractResource, PathPrefix> findApplicableResources(
+ TreeLogger logger, PathPrefixSet pathPrefixSet) {
+ Map<AbstractResource, PathPrefix> results = new IdentityHashMap<AbstractResource, PathPrefix>();
+ Map<AbstractResource, PathPrefix> rs = cpe.findApplicableResources(
+ logger, pathPrefixSet);
+ for (AbstractResource r : rs.keySet()) {
if (r.getPath().indexOf(".svn/") < 0) {
- results.add(r);
+ results.put(r, rs.get(r));
}
}
return results;
@@ -114,6 +115,7 @@
addResource("com/google/gwt/i18n/rebind/LocalizableGenerator.java");
addResource("org/example/bar/client/BarClient2.txt");
addResource("org/example/bar/client/BarClient3.txt");
+ addResource("org/example/foo/client/BarClient1.txt");
}
}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/ClassPathEntryTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/ClassPathEntryTest.java
index 3454176..5bfddad 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/ClassPathEntryTest.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/ClassPathEntryTest.java
@@ -81,7 +81,7 @@
{
// Examine cpe1.
- Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps);
+ Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps).keySet();
assertEquals(3, r.size());
assertPathIncluded(r, "com/google/gwt/user/client/Command.java");
@@ -91,7 +91,7 @@
{
// Examine cpe2.
- Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps);
+ Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps).keySet();
assertEquals(1, r.size());
assertPathIncluded(r, "com/google/gwt/i18n/client/Messages.java");
@@ -106,7 +106,7 @@
PathPrefixSet pps = new PathPrefixSet();
pps.add(new PathPrefix("", null));
- Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps);
+ Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps).keySet();
assertEquals(9, r.size());
assertPathIncluded(r, "com/google/gwt/user/User.gwt.xml");
@@ -127,15 +127,16 @@
PathPrefixSet pps = new PathPrefixSet();
pps.add(new PathPrefix("", null));
- Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps);
+ Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps).keySet();
- assertEquals(5, r.size());
+ assertEquals(6, r.size());
assertPathIncluded(r, "com/google/gwt/i18n/I18N.gwt.xml");
assertPathIncluded(r, "com/google/gwt/i18n/client/Messages.java");
assertPathIncluded(r,
"com/google/gwt/i18n/rebind/LocalizableGenerator.java");
assertPathIncluded(r, "org/example/bar/client/BarClient2.txt");
assertPathIncluded(r, "org/example/bar/client/BarClient3.txt");
+ assertPathIncluded(r, "org/example/foo/client/BarClient1.txt");
}
private void testPathPrefixSetChanges(ClassPathEntry cpe1, ClassPathEntry cpe2) {
@@ -148,7 +149,7 @@
pps.add(new PathPrefix("com/google/gwt/i18n/", null));
// Examine cpe1 in the absence of the filter.
- Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps);
+ Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps).keySet();
assertEquals(4, r1.size());
assertPathIncluded(r1, "com/google/gwt/user/User.gwt.xml");
@@ -157,7 +158,7 @@
assertPathIncluded(r1, "com/google/gwt/user/client/ui/Widget.java");
// Examine cpe2 in the absence of the filter.
- Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps);
+ Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps).keySet();
assertEquals(3, r2.size());
assertPathIncluded(r2, "com/google/gwt/i18n/I18N.gwt.xml");
@@ -179,7 +180,7 @@
pps.add(new PathPrefix("com/google/gwt/i18n/", excludeXmlFiles));
// Examine cpe1 in the presence of the filter.
- Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps);
+ Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps).keySet();
assertEquals(3, r1.size());
assertPathNotIncluded(r1, "com/google/gwt/user/User.gwt.xml");
@@ -188,7 +189,7 @@
assertPathIncluded(r1, "com/google/gwt/user/client/ui/Widget.java");
// Examine cpe2 in the presence of the filter.
- Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps);
+ Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps).keySet();
assertEquals(2, r2.size());
assertPathNotIncluded(r1, "com/google/gwt/user/User.gwt.xml");
@@ -211,12 +212,12 @@
}));
// Examine cpe1 in the presence of the filter.
- Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps);
+ Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps).keySet();
assertEquals(0, r1.size());
// Examine cpe2 in the presence of the filter.
- Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps);
+ Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps).keySet();
assertEquals(0, r2.size());
}
@@ -238,7 +239,7 @@
{
// Examine cpe1.
- Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps);
+ Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps).keySet();
assertEquals(3, r.size());
// User.gwt.xml would be included but for the filter.
@@ -249,7 +250,7 @@
{
// Examine cpe2.
- Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps);
+ Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps).keySet();
assertEquals(2, r.size());
// I18N.gwt.xml would be included but for the filter.
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/MockClassPathEntry.java b/dev/core/test/com/google/gwt/dev/resource/impl/MockClassPathEntry.java
index 913b071..254c0f9 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/MockClassPathEntry.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/MockClassPathEntry.java
@@ -21,9 +21,8 @@
import junit.framework.Assert;
import java.util.HashMap;
-import java.util.HashSet;
+import java.util.IdentityHashMap;
import java.util.Map;
-import java.util.Set;
public class MockClassPathEntry extends ClassPathEntry {
@@ -46,14 +45,15 @@
}
@Override
- public Set<AbstractResource> findApplicableResources(TreeLogger logger,
- PathPrefixSet pathPrefixes) {
+ public Map<AbstractResource, PathPrefix> findApplicableResources(
+ TreeLogger logger, PathPrefixSet pathPrefixes) {
// Only include resources that have the prefix and pass its filter.
- HashSet<AbstractResource> results = new HashSet<AbstractResource>();
+ Map<AbstractResource, PathPrefix> results = new IdentityHashMap<AbstractResource, PathPrefix>();
for (Map.Entry<String, MockAbstractResource> entry : resourceMap.entrySet()) {
String path = entry.getKey();
- if (pathPrefixes.includesResource(path)) {
- results.add(entry.getValue());
+ PathPrefix prefix = null;
+ if ((prefix = pathPrefixes.includesResource(path)) != null) {
+ results.put(entry.getValue(), prefix);
}
}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/PathPrefixSetTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/PathPrefixSetTest.java
index e9d581c..8c73c99 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/PathPrefixSetTest.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/PathPrefixSetTest.java
@@ -24,154 +24,181 @@
public void testEmptyPrefixSet() {
PathPrefixSet pps = new PathPrefixSet();
- assertFalse(pps.includesResource("com/google/gwt/user/client/Command.java"));
+ assertNull(pps.includesResource("com/google/gwt/user/client/Command.java"));
}
- public void testNonOverlappingPrefixes() {
- {
- /*
- * Test with null filters to ensure nothing gets filtered out.
- */
- PathPrefixSet pps = new PathPrefixSet();
- pps.add(new PathPrefix("com/google/gwt/user/client/", null));
- pps.add(new PathPrefix("com/google/gwt/i18n/client/", null));
- pps.add(new PathPrefix("com/google/gwt/dom/client/", null));
+ public void testNonOverlappingPrefixesEmptyFilter() {
+ /*
+ * Test with null filters to ensure nothing gets filtered out.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ PathPrefix pp1 = new PathPrefix("com/google/gwt/user/client/", null);
+ PathPrefix pp2 = new PathPrefix("com/google/gwt/i18n/client/", null);
+ PathPrefix pp3 = new PathPrefix("com/google/gwt/dom/client/", null);
+ pps.add(pp1);
+ pps.add(pp2);
+ pps.add(pp3);
- assertTrue(pps.includesDirectory("com/"));
- assertTrue(pps.includesDirectory("com/google/"));
- assertTrue(pps.includesDirectory("com/google/gwt/"));
- assertTrue(pps.includesDirectory("com/google/gwt/user/"));
- assertTrue(pps.includesDirectory("com/google/gwt/user/client/"));
- assertTrue(pps.includesDirectory("com/google/gwt/user/client/ui/"));
+ assertTrue(pps.includesDirectory("com/"));
+ assertTrue(pps.includesDirectory("com/google/"));
+ assertTrue(pps.includesDirectory("com/google/gwt/"));
+ assertTrue(pps.includesDirectory("com/google/gwt/user/"));
+ assertTrue(pps.includesDirectory("com/google/gwt/user/client/"));
+ assertTrue(pps.includesDirectory("com/google/gwt/user/client/ui/"));
- assertFalse(pps.includesDirectory("org/"));
- assertFalse(pps.includesDirectory("org/example/"));
- assertFalse(pps.includesDirectory("com/google/gwt/user/server/"));
- assertFalse(pps.includesDirectory("com/google/gwt/xml/client/"));
+ assertFalse(pps.includesDirectory("org/"));
+ assertFalse(pps.includesDirectory("org/example/"));
+ assertFalse(pps.includesDirectory("com/google/gwt/user/server/"));
+ assertFalse(pps.includesDirectory("com/google/gwt/xml/client/"));
- assertTrue(pps.includesResource("com/google/gwt/user/client/Command.java"));
- assertTrue(pps.includesResource("com/google/gwt/user/client/Timer.java"));
- assertTrue(pps.includesResource("com/google/gwt/i18n/client/Messages.java"));
- assertTrue(pps.includesResource("com/google/gwt/dom/client/DivElement.java"));
+ assertEquals(pp1,
+ pps.includesResource("com/google/gwt/user/client/Command.java"));
+ assertEquals(pp1,
+ pps.includesResource("com/google/gwt/user/client/Timer.java"));
+ assertEquals(pp2,
+ pps.includesResource("com/google/gwt/i18n/client/Messages.java"));
+ assertEquals(pp3,
+ pps.includesResource("com/google/gwt/dom/client/DivElement.java"));
- assertFalse(pps.includesResource("com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java"));
- assertFalse(pps.includesResource("com/google/gwt/sample/hello/client/Hello.java"));
- assertFalse(pps.includesResource("com/google/gwt/user/public/clear.cache.gif"));
- }
-
- {
- /*
- * Test with a real filter to ensure it does have an effect.
- */
- PathPrefixSet pps = new PathPrefixSet();
- ResourceFilter allowsGifs = new ResourceFilter() {
- public boolean allows(String path) {
- return path.toLowerCase().endsWith(".gif");
- }
- };
-
- pps.add(new PathPrefix("com/google/gwt/user/public/", allowsGifs));
- pps.add(new PathPrefix("com/google/gwt/sample/mail/public/", allowsGifs));
-
- // Correct prefix, and filter should allow .
- assertTrue(pps.includesResource("com/google/gwt/user/public/clear.cache.gif"));
- assertTrue(pps.includesResource("com/google/gwt/sample/mail/public/inboxIcon.gif"));
-
- // Correct prefix, but filter should exclude.
- assertFalse(pps.includesResource("com/google/gwt/user/public/README.txt"));
- assertFalse(pps.includesResource("com/google/gwt/sample/mail/public/README.txt"));
-
- // Wrong prefix, and filter would have excluded.
- assertFalse(pps.includesResource("com/google/gwt/user/client/Command.java"));
- assertFalse(pps.includesResource("com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java"));
-
- // Wrong prefix, but filter would have allowed it.
- assertFalse(pps.includesResource("com/google/gwt/i18n/public/flags.gif"));
- }
+ assertNull(pps.includesResource("com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java"));
+ assertNull(pps.includesResource("com/google/gwt/sample/hello/client/Hello.java"));
+ assertNull(pps.includesResource("com/google/gwt/user/public/clear.cache.gif"));
}
- public void testOverlappingPrefixes() {
- {
- /*
- * Without a filter.
- */
- PathPrefixSet pps = new PathPrefixSet();
- pps.add(new PathPrefix("", null));
- pps.add(new PathPrefix("a/", null));
- pps.add(new PathPrefix("a/b/", null));
- pps.add(new PathPrefix("a/b/c/", null));
+ public void testNonOverlappingPrefixesNonEmptyFilter() {
+ /*
+ * Test with a real filter to ensure it does have an effect.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ ResourceFilter allowsGifs = new ResourceFilter() {
+ public boolean allows(String path) {
+ return path.toLowerCase().endsWith(".gif");
+ }
+ };
- assertTrue(pps.includesResource("W.java"));
- assertTrue(pps.includesResource("a/X.java"));
- assertTrue(pps.includesResource("a/b/Y.java"));
- assertTrue(pps.includesResource("a/b/c/Z.java"));
- assertTrue(pps.includesResource("a/b/c/d/V.java"));
- }
+ PathPrefix pp1 = new PathPrefix("com/google/gwt/user/public/", allowsGifs);
+ PathPrefix pp2 = new PathPrefix("com/google/gwt/sample/mail/public/",
+ allowsGifs);
+ pps.add(pp1);
+ pps.add(pp2);
- {
- /*
- * Ensure the right filter applies.
- */
- PathPrefixSet pps = new PathPrefixSet();
- pps.add(new PathPrefix("", null));
- pps.add(new PathPrefix("a/", null));
- pps.add(new PathPrefix("a/b/", new ResourceFilter() {
- public boolean allows(String path) {
- // Disallow anything ending with "FILTERMEOUT".
- return !path.endsWith("FILTERMEOUT");
- }
- }));
- pps.add(new PathPrefix("a/b/c/", null));
+ // Correct prefix, and filter should allow .
+ assertEquals(pp1,
+ pps.includesResource("com/google/gwt/user/public/clear.cache.gif"));
+ assertEquals(pp2,
+ pps.includesResource("com/google/gwt/sample/mail/public/inboxIcon.gif"));
- assertTrue(pps.includesResource("W.java"));
- assertTrue(pps.includesResource("a/X.java"));
- assertTrue(pps.includesResource("a/b/Y.java"));
- // This should be gone, since it is found in b.
- assertFalse(pps.includesResource("a/b/FILTERMEOUT"));
- /*
- * This should not be gone, because it is using c's (null) filter instead
- * of b's. The logic here is that the prefix including c is more specific
- * and seemed to want c's resources to be included.
- */
- assertTrue(pps.includesResource("a/b/c/DONT_FILTERMEOUT"));
- assertTrue(pps.includesResource("a/b/c/Z.java"));
- assertTrue(pps.includesResource("a/b/c/d/V.java"));
- }
+ // Correct prefix, but filter should exclude.
+ assertNull(pps.includesResource("com/google/gwt/user/public/README.txt"));
+ assertNull(pps.includesResource("com/google/gwt/sample/mail/public/README.txt"));
+
+ // Wrong prefix, and filter would have excluded.
+ assertNull(pps.includesResource("com/google/gwt/user/client/Command.java"));
+ assertNull(pps.includesResource("com/google/gwt/user/rebind/rpc/ServiceInterfaceProxyGenerator.java"));
+
+ // Wrong prefix, but filter would have allowed it.
+ assertNull(pps.includesResource("com/google/gwt/i18n/public/flags.gif"));
+ }
+
+ public void testOverlappingPrefixesEmptyFilter() {
+ /*
+ * Without a filter.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ PathPrefix pp1 = new PathPrefix("a/b/", null);
+ PathPrefix pp2 = new PathPrefix("a/", null);
+ PathPrefix pp3 = new PathPrefix("", null);
+ PathPrefix pp4 = new PathPrefix("a/b/c/", null);
+ PathPrefix pp5 = new PathPrefix("a/", null);
+ pps.add(pp1);
+ pps.add(pp2);
+ pps.add(pp3);
+ pps.add(pp4);
+ // pp5 now overrides pp2
+ pps.add(pp5);
+
+ assertEquals(pp3, pps.includesResource("W.java"));
+ assertEquals(pp5, pps.includesResource("a/X.java"));
+ assertEquals(pp1, pps.includesResource("a/b/Y.java"));
+ assertEquals(pp4, pps.includesResource("a/b/c/Z.java"));
+ assertEquals(pp4, pps.includesResource("a/b/c/d/V.java"));
+ }
+
+ public void testOverlappingPrefixesNonEmptyFilter() {
+ /*
+ * Ensure the right filter applies.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ PathPrefix pp1 = new PathPrefix("", null);
+ PathPrefix pp2 = new PathPrefix("a/", null);
+ PathPrefix pp3 = new PathPrefix("a/b/", new ResourceFilter() {
+ public boolean allows(String path) {
+ // Disallow anything ending with "FILTERMEOUT".
+ return !path.endsWith("FILTERMEOUT");
+ }
+ });
+ PathPrefix pp4 = new PathPrefix("a/b/c/", null);
+ PathPrefix pp5 = new PathPrefix("a/", new ResourceFilter() {
+ public boolean allows(String path) {
+ return !path.endsWith("X.java");
+ }
+ });
+ pps.add(pp1);
+ pps.add(pp2);
+ pps.add(pp3);
+ pps.add(pp4);
+ pps.add(pp5);
+
+ assertEquals(pp1, pps.includesResource("W.java"));
+
+ // see TODO in the implementation note for PathPrefixSet.java
+ // assertEquals(pp2, pps.includesResource("a/X.java"));
+ assertEquals(pp5, pps.includesResource("a/Y.java"));
+ assertEquals(pp3, pps.includesResource("a/b/Y.java"));
+ // This should be gone, since it is found in b.
+ assertNull(pps.includesResource("a/b/FILTERMEOUT"));
+ /*
+ * This should not be gone, because it is using c's (null) filter instead of
+ * b's. The logic here is that the prefix including c is more specific and
+ * seemed to want c's resources to be included.
+ */
+ assertEquals(pp4, pps.includesResource("a/b/c/DONT_FILTERMEOUT"));
+ assertEquals(pp4, pps.includesResource("a/b/c/Z.java"));
+ assertEquals(pp4, pps.includesResource("a/b/c/d/V.java"));
}
/**
- * In essense, this tests support for the default package in Java.
+ * In essence, this tests support for the default package in Java.
*/
- public void testZeroLengthPrefix() {
- {
- /*
- * Without a filter.
- */
- PathPrefixSet pps = new PathPrefixSet();
- pps.add(new PathPrefix("", null));
+ public void testZeroLengthPrefixEmptyFilter() {
+ /*
+ * Without a filter.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ PathPrefix pp1 = new PathPrefix("", null);
+ pps.add(pp1);
- assertTrue(pps.includesResource("W.java"));
- assertTrue(pps.includesResource("a/X.java"));
- assertTrue(pps.includesResource("a/b/Y.java"));
- assertTrue(pps.includesResource("a/b/c/Z.java"));
- }
+ assertEquals(pp1, pps.includesResource("W.java"));
+ assertEquals(pp1, pps.includesResource("a/X.java"));
+ assertEquals(pp1, pps.includesResource("a/b/Y.java"));
+ assertEquals(pp1, pps.includesResource("a/b/c/Z.java"));
+ }
- {
- /*
- * With a filter.
- */
- PathPrefixSet pps = new PathPrefixSet();
- pps.add(new PathPrefix("", new ResourceFilter() {
- public boolean allows(String path) {
- return path.endsWith("Y.java");
- }
- }));
+ public void testZeroLengthPrefixNonEmptyFilter() {
+ /*
+ * With a filter.
+ */
+ PathPrefixSet pps = new PathPrefixSet();
+ PathPrefix pp1 = new PathPrefix("", new ResourceFilter() {
+ public boolean allows(String path) {
+ return path.endsWith("Y.java");
+ }
+ });
+ pps.add(pp1);
- assertFalse(pps.includesResource("W.java"));
- assertFalse(pps.includesResource("a/X.java"));
- assertTrue(pps.includesResource("a/b/Y.java"));
- assertFalse(pps.includesResource("a/b/c/Z.java"));
-
- }
+ assertNull(pps.includesResource("W.java"));
+ assertNull(pps.includesResource("a/X.java"));
+ assertEquals(pp1, pps.includesResource("a/b/Y.java"));
+ assertNull(pps.includesResource("a/b/c/Z.java"));
}
}
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java b/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
index 8449d7d..560ed05 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/ResourceOracleImplTest.java
@@ -15,10 +15,6 @@
*/
package com.google.gwt.dev.resource.impl;
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.dev.resource.Resource;
-import com.google.gwt.util.tools.Utility;
-
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@@ -33,6 +29,10 @@
import java.util.Map;
import java.util.Set;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.resource.Resource;
+import com.google.gwt.util.tools.Utility;
+
/**
* Tests {@link ResourceOracleImpl}.
*
@@ -153,10 +153,10 @@
PathPrefix pathPrefixReroot = new PathPrefix("org/example/bar/client",
null, true);
- testClassPathOrderIsHonored(logger, resKeyNormal, cp12, pathPrefixNormal);
- testClassPathOrderIsHonored(logger, resKeyReroot, cp12, pathPrefixReroot);
- testClassPathOrderIsHonored(logger, resKeyNormal, cp21, pathPrefixNormal);
- testClassPathOrderIsHonored(logger, resKeyReroot, cp21, pathPrefixReroot);
+ testResourceInCPE(logger, resKeyNormal, cpe1jar, cp12, pathPrefixNormal);
+ testResourceInCPE(logger, resKeyReroot, cpe1jar, cp12, pathPrefixReroot);
+ testResourceInCPE(logger, resKeyNormal, cpe2jar, cp21, pathPrefixNormal);
+ testResourceInCPE(logger, resKeyReroot, cpe2jar, cp21, pathPrefixReroot);
}
public void testNoClassPathEntries() {
@@ -167,6 +167,41 @@
}
/**
+ * Test that ResourceOracleImpl prefers the order of path prefixes over
+ * ClassPathEntries.
+ * <p>
+ * cpe1 contains org/example/bar/client/BarClient1.txt and cpe2 contains
+ * org/example/foo/client/BarClient1.txt
+ *
+ * @throws URISyntaxException
+ * @throws IOException
+ */
+ public void testPathPrefixOrderPreferredOverClasspath() throws IOException,
+ URISyntaxException {
+ TreeLogger logger = createTestTreeLogger();
+ ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
+ ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
+
+ ClassPathEntry[] cp12 = new ClassPathEntry[] {cpe1jar, cpe2jar};
+ ClassPathEntry[] cp21 = new ClassPathEntry[] {cpe2jar, cpe1jar};
+
+ String keyReroot = "/BarClient1.txt";
+
+ PathPrefix pp1 = new PathPrefix("org/example/bar/client", null, true);
+ PathPrefix pp2 = new PathPrefix("org/example/foo/client", null, true);
+
+ // Resource in cpe2 wins because pp2 comes later.
+ testResourceInCPE(logger, keyReroot, cpe2jar, cp12, pp1, pp2);
+ // Order of specifying classpath is reversed, it still matches cpe2.
+ testResourceInCPE(logger, keyReroot, cpe2jar, cp21, pp1, pp2);
+
+ // Resource in cpe1 wins because pp1 comes later.
+ testResourceInCPE(logger, keyReroot, cpe1jar, cp12, pp2, pp1);
+ // Order of specifying classpath is reversed, it still matches cpe1.
+ testResourceInCPE(logger, keyReroot, cpe1jar, cp21, pp2, pp1);
+ }
+
+ /**
* Tests the actual reading of resources.
*
* @throws URISyntaxException
@@ -284,6 +319,49 @@
}
/**
+ * Ensure refresh is stable when multiple classpaths + multiple path prefixes
+ * all include the same resource.
+ */
+ public void testStableRefreshOnBlot() {
+ TreeLogger logger = createTestTreeLogger();
+ ClassPathEntry cpe1 = getClassPathEntry1AsMock();
+ ClassPathEntry cpe2 = getClassPathEntry2AsMock();
+ PathPrefix pp1 = new PathPrefix("org/example/bar/client", null, false);
+ PathPrefix pp2 = new PathPrefix("org/example/bar", null, false);
+ testResourceInCPE(logger, "org/example/bar/client/BarClient2.txt", cpe1,
+ new ClassPathEntry[] {cpe1, cpe2}, pp1, pp2);
+ }
+
+ /**
+ * Ensure refresh is stable when multiple classpaths + multiple path prefixes
+ * all include the same resource.
+ */
+ public void testSuperSourceSupercedesSource() {
+ TreeLogger logger = createTestTreeLogger();
+
+ MockClassPathEntry cpe1 = new MockClassPathEntry("/cpe1/");
+ cpe1.addResource("java/lang/Object.java");
+
+ MockClassPathEntry cpe2 = new MockClassPathEntry("/cpe2/");
+ cpe2.addResource("translatable/java/lang/Object.java");
+
+ PathPrefix pp1 = new PathPrefix("java/lang/", null, false);
+ PathPrefix pp2 = new PathPrefix("translatable/", null, true);
+
+ // Ensure the translatable overrides the basic despite swapping CPE order.
+ testResourceInCPE(logger, "java/lang/Object.java", cpe2,
+ new ClassPathEntry[] {cpe1, cpe2}, pp1, pp2);
+ testResourceInCPE(logger, "java/lang/Object.java", cpe2,
+ new ClassPathEntry[] {cpe2, cpe1}, pp1, pp2);
+
+ // Ensure the translatable overrides the basic despite swapping PPS order.
+ testResourceInCPE(logger, "java/lang/Object.java", cpe2,
+ new ClassPathEntry[] {cpe1, cpe2}, pp2, pp1);
+ testResourceInCPE(logger, "java/lang/Object.java", cpe2,
+ new ClassPathEntry[] {cpe2, cpe1}, pp2, pp1);
+ }
+
+ /**
* @param classPathEntry
* @param string
*/
@@ -318,17 +396,11 @@
private ResourceOracleSnapshot refreshAndSnapshot(TreeLogger logger,
ResourceOracleImpl oracle) {
oracle.refresh(logger);
- return new ResourceOracleSnapshot(oracle);
- }
-
- private void testClassPathOrderIsHonored(TreeLogger logger,
- String resourceKey, ClassPathEntry[] classPath, PathPrefix pathPrefix) {
- PathPrefixSet pps = new PathPrefixSet();
- pps.add(pathPrefix);
- ResourceOracleImpl oracle = new ResourceOracleImpl(Arrays.asList(classPath));
- oracle.setPathPrefixes(pps);
- ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
- s.assertPathIncluded(resourceKey, classPath[0]);
+ ResourceOracleSnapshot snapshot1 = new ResourceOracleSnapshot(oracle);
+ oracle.refresh(logger);
+ ResourceOracleSnapshot snapshot2 = new ResourceOracleSnapshot(oracle);
+ snapshot1.assertSameCollections(snapshot2);
+ return snapshot1;
}
private void testReadingResource(ClassPathEntry cpe1, ClassPathEntry cpe2)
@@ -337,7 +409,7 @@
ResourceOracleImpl oracle = createResourceOracle(cpe1, cpe2);
ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
- s.assertCollectionsConsistent(9);
+ s.assertCollectionsConsistent(10);
s.assertPathIncluded("com/google/gwt/user/client/Command.java", cpe1);
s.assertPathIncluded("com/google/gwt/i18n/client/Messages.java", cpe2);
@@ -395,7 +467,7 @@
* assumptions about the contents of each classpath entry.
*/
ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
- s.assertCollectionsConsistent(9);
+ s.assertCollectionsConsistent(10);
s.assertPathIncluded("com/google/gwt/user/client/Command.java");
s.assertPathIncluded("com/google/gwt/user/client/Timer.java");
s.assertPathIncluded("com/google/gwt/user/client/ui/Widget.java");
@@ -418,7 +490,7 @@
ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
- after.assertCollectionsConsistent(9);
+ after.assertCollectionsConsistent(10);
after.assertSameCollections(before);
}
@@ -431,7 +503,7 @@
ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
- after.assertCollectionsConsistent(10);
+ after.assertCollectionsConsistent(11);
after.assertNotSameCollections(before);
after.assertPathIncluded("com/google/gwt/i18n/client/Constants.java");
}
@@ -458,7 +530,7 @@
* assumptions about the contents of each classpath entry.
*/
ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
- s.assertCollectionsConsistent(10);
+ s.assertCollectionsConsistent(11);
s.assertPathIncluded("com/google/gwt/user/client/Command.java");
s.assertPathIncluded("com/google/gwt/user/client/Timer.java");
s.assertPathIncluded("com/google/gwt/user/client/ui/Widget.java");
@@ -481,7 +553,7 @@
ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
- after.assertCollectionsConsistent(10);
+ after.assertCollectionsConsistent(11);
after.assertSameCollections(before);
}
@@ -496,13 +568,26 @@
ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
ResourceOracleSnapshot after = refreshAndSnapshot(logger, oracle);
- after.assertCollectionsConsistent(10);
+ after.assertCollectionsConsistent(11);
after.assertNotSameCollections(before);
after.assertPathIncluded("com/google/gwt/user/client/Window.java");
after.assertPathNotIncluded("com/google/gwt/i18n/client/Constants.java");
}
}
+ private void testResourceInCPE(TreeLogger logger, String resourceKey,
+ ClassPathEntry expectedCPE, ClassPathEntry[] classPath,
+ PathPrefix... pathPrefixes) {
+ ResourceOracleImpl oracle = new ResourceOracleImpl(Arrays.asList(classPath));
+ PathPrefixSet pps = new PathPrefixSet();
+ for (PathPrefix pathPrefix : pathPrefixes) {
+ pps.add(pathPrefix);
+ }
+ oracle.setPathPrefixes(pps);
+ ResourceOracleSnapshot s = refreshAndSnapshot(logger, oracle);
+ s.assertPathIncluded(resourceKey, expectedCPE);
+ }
+
private void testResourceModification(ClassPathEntry cpe1, ClassPathEntry cpe2) {
TreeLogger logger = createTestTreeLogger();
@@ -538,7 +623,7 @@
* isn't observed.
*/
ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
- before.assertCollectionsConsistent(9);
+ before.assertCollectionsConsistent(10);
cpe3.updateResource("com/google/gwt/user/client/Timer.java");
@@ -552,7 +637,7 @@
* is observed.
*/
ResourceOracleSnapshot before = new ResourceOracleSnapshot(oracle);
- before.assertCollectionsConsistent(9);
+ before.assertCollectionsConsistent(10);
cpe0.updateResource("com/google/gwt/user/client/Command.java");
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1.jar b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1.jar
index 5045c12..c5127c9 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1.jar
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe1.jar
Binary files differ
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2.jar b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2.jar
index 08761bb..2e6663b 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2.jar
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2.jar
Binary files differ
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/org/example/foo/client/BarClient1.txt b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/org/example/foo/client/BarClient1.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/testdata/cpe2/org/example/foo/client/BarClient1.txt
@@ -0,0 +1 @@
+
diff --git a/dev/core/test/com/google/gwt/dev/shell/CheckForUpdatesTest.java b/dev/core/test/com/google/gwt/dev/shell/CheckForUpdatesTest.java
index c3255c1..dad4351 100644
--- a/dev/core/test/com/google/gwt/dev/shell/CheckForUpdatesTest.java
+++ b/dev/core/test/com/google/gwt/dev/shell/CheckForUpdatesTest.java
@@ -1,56 +1,80 @@
package com.google.gwt.dev.shell;
import junit.framework.TestCase;
+import com.google.gwt.dev.shell.CheckForUpdates.GwtVersion;
public class CheckForUpdatesTest extends TestCase {
/*
- * Test method for
- * 'com.google.gwt.dev.shell.CheckForUpdates.isServerVersionNewer(String,
- * String)'
+ * Test GwtVersion comparisons
*/
- public final void testIsServerVersionNewer() {
- assertFalse(CheckForUpdates.isServerVersionNewer(null, null));
+ public final void testVersionComparison() {
+ GwtVersion v1 = new GwtVersion(null);
+ assertEquals(0, v1.compareTo(v1));
- assertFalse(CheckForUpdates.isServerVersionNewer("1", "2"));
- assertFalse(CheckForUpdates.isServerVersionNewer("2", "1"));
+ v1 = new GwtVersion("1");
+ assertEquals(0, v1.compareTo(v1));
+ GwtVersion v2 = new GwtVersion("2");
+ assertTrue(v1.compareTo(v2) < 0);
+ assertTrue(v2.compareTo(v1) > 0);
- assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", null));
- assertFalse(CheckForUpdates.isServerVersionNewer(null, "1.2.3"));
+ v1 = new GwtVersion("1.2.3");
+ v2 = new GwtVersion(null);
+ assertTrue(v1.compareTo(v2) > 0);
+ assertTrue(v2.compareTo(v1) < 0);
- assertFalse(CheckForUpdates.isServerVersionNewer("2", "1.2.3"));
- assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "2"));
+ v1 = new GwtVersion("1.2.3");
+ v2 = new GwtVersion("2.0.0");
+ assertTrue(v1.compareTo(v2) < 0);
+ assertTrue(v2.compareTo(v1) > 0);
- assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "2.3.4.5"));
- assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3.4", "2.3.4"));
+ v1 = new GwtVersion("1.2.99");
+ v2 = new GwtVersion("2.0.0");
+ assertTrue(v1.compareTo(v2) < 0);
+ assertTrue(v2.compareTo(v1) > 0);
- assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "1.2.3"));
- assertFalse(CheckForUpdates.isServerVersionNewer("1000.2000.3000",
- "1000.2000.3000"));
- assertFalse(CheckForUpdates.isServerVersionNewer("001.002.003", "1.2.3"));
- assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "001.002.003"));
+ v1 = new GwtVersion("1.2.99");
+ v2 = new GwtVersion("1.3.0");
+ assertTrue(v1.compareTo(v2) < 0);
+ assertTrue(v2.compareTo(v1) > 0);
- assertTrue(CheckForUpdates.isServerVersionNewer("1.2.3", "2.2.3"));
- assertFalse(CheckForUpdates.isServerVersionNewer("2.2.3", "1.2.3"));
+ v1 = new GwtVersion("001.002.099");
+ v2 = new GwtVersion("1.2.99");
+ assertEquals(0, v1.compareTo(v2));
- assertTrue(CheckForUpdates.isServerVersionNewer("1.2.3", "1.3.3"));
- assertFalse(CheckForUpdates.isServerVersionNewer("1.3.3", "1.2.3"));
-
- assertTrue(CheckForUpdates.isServerVersionNewer("1.2.3", "1.2.4"));
- assertFalse(CheckForUpdates.isServerVersionNewer("1.2.4", "1.2.3"));
-
- assertTrue(CheckForUpdates.isServerVersionNewer("1000.2000.3000",
- "1000.2000.4000"));
- assertFalse(CheckForUpdates.isServerVersionNewer("1000.2000.4000",
- "1000.2000.3000"));
-
- assertTrue(CheckForUpdates.isServerVersionNewer("1000.2000.3000",
- "1000.2000.3001"));
- assertFalse(CheckForUpdates.isServerVersionNewer("1000.2000.3001",
- "1000.2000.3000"));
-
- assertTrue(CheckForUpdates.isServerVersionNewer("0.2.3", "1.1.3"));
- assertFalse(CheckForUpdates.isServerVersionNewer("1.1.3", "0.2.3"));
+ // TODO: more tests
+// assertFalse(CheckForUpdates.isServerVersionNewer("2", "1.2.3"));
+// assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "2"));
+//
+// assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "2.3.4.5"));
+// assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3.4", "2.3.4"));
+//
+// assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "1.2.3"));
+// assertFalse(CheckForUpdates.isServerVersionNewer("1000.2000.3000",
+// "1000.2000.3000"));
+// assertFalse(CheckForUpdates.isServerVersionNewer("001.002.003", "1.2.3"));
+// assertFalse(CheckForUpdates.isServerVersionNewer("1.2.3", "001.002.003"));
+//
+// assertTrue(CheckForUpdates.isServerVersionNewer("1.2.3", "2.2.3"));
+// assertFalse(CheckForUpdates.isServerVersionNewer("2.2.3", "1.2.3"));
+//
+// assertTrue(CheckForUpdates.isServerVersionNewer("1.2.3", "1.3.3"));
+// assertFalse(CheckForUpdates.isServerVersionNewer("1.3.3", "1.2.3"));
+//
+// assertTrue(CheckForUpdates.isServerVersionNewer("1.2.3", "1.2.4"));
+// assertFalse(CheckForUpdates.isServerVersionNewer("1.2.4", "1.2.3"));
+//
+// assertTrue(CheckForUpdates.isServerVersionNewer("1000.2000.3000",
+// "1000.2000.4000"));
+// assertFalse(CheckForUpdates.isServerVersionNewer("1000.2000.4000",
+// "1000.2000.3000"));
+//
+// assertTrue(CheckForUpdates.isServerVersionNewer("1000.2000.3000",
+// "1000.2000.3001"));
+// assertFalse(CheckForUpdates.isServerVersionNewer("1000.2000.3001",
+// "1000.2000.3000"));
+//
+// assertTrue(CheckForUpdates.isServerVersionNewer("0.2.3", "1.1.3"));
+// assertFalse(CheckForUpdates.isServerVersionNewer("1.1.3", "0.2.3"));
}
-
}
diff --git a/dev/core/test/com/google/gwt/dev/shell/GeneratedClassnameTest.java b/dev/core/test/com/google/gwt/dev/shell/GeneratedClassnameTest.java
index b5040c1..ecf7087 100644
--- a/dev/core/test/com/google/gwt/dev/shell/GeneratedClassnameTest.java
+++ b/dev/core/test/com/google/gwt/dev/shell/GeneratedClassnameTest.java
@@ -11,8 +11,8 @@
public void testGeneratedClassnames() {
String namesToAccept[] = {
"Test$1", "Test$10", "Test$Foo$1", "Test$1$Foo", "Test$10$Foo",
- "$$345", "Test$1$Foo$"};
- String namesToReject[] = {"Test1", "$345", "Test$2Foo", "Test$Foo$1Bar"};
+ "$$345", "Test$1$Foo$", "Test$1Foo", "Test$2Foo", "Test$Foo$1Bar"};
+ String namesToReject[] = {"Test1", "TestFoo", "Test$Foo$Bar", "$345"};
for (String name : namesToAccept) {
assertTrue("className = " + name + " should have been accepted",
diff --git a/dev/linux/src/com/google/gwt/dev/shell/moz/CheckForUpdatesMoz.java b/dev/linux/src/com/google/gwt/dev/shell/moz/CheckForUpdatesMoz.java
deleted file mode 100644
index a1ba73d..0000000
--- a/dev/linux/src/com/google/gwt/dev/shell/moz/CheckForUpdatesMoz.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2007 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.moz;
-
-import com.google.gwt.dev.shell.CheckForUpdates;
-
-/**
- * Mozilla specific implementation of CheckForUpdates.
- */
-public class CheckForUpdatesMoz extends CheckForUpdates {
-
- @Override
- protected byte[] doHttpGet(String userAgent, String url) {
- // Don't attempt to support proxies on Linux.
- //
- return httpGetNonNative(userAgent, url);
- }
-}
diff --git a/dev/mac/src/com/google/gwt/dev/shell/mac/CheckForUpdatesSaf.java b/dev/mac/src/com/google/gwt/dev/shell/mac/CheckForUpdatesSaf.java
deleted file mode 100644
index 34ad6e2..0000000
--- a/dev/mac/src/com/google/gwt/dev/shell/mac/CheckForUpdatesSaf.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2007 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.mac;
-
-import com.google.gwt.dev.shell.CheckForUpdates;
-
-/**
- * Safari specific implementation of CheckForUpdates.
- */
-public class CheckForUpdatesSaf extends CheckForUpdates {
-
- @Override
- protected byte[] doHttpGet(String userAgent, String url) {
- // Don't attempt to support proxies on Linux.
- //
- return httpGetNonNative(userAgent, url);
- }
-}
diff --git a/dev/windows/src/com/google/gwt/dev/shell/ie/CheckForUpdatesIE6.java b/dev/windows/src/com/google/gwt/dev/shell/ie/CheckForUpdatesIE6.java
index fd71509..cdd1637 100644
--- a/dev/windows/src/com/google/gwt/dev/shell/ie/CheckForUpdatesIE6.java
+++ b/dev/windows/src/com/google/gwt/dev/shell/ie/CheckForUpdatesIE6.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.shell.ie;
+import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.shell.CheckForUpdates;
/**
@@ -22,13 +23,15 @@
*/
public class CheckForUpdatesIE6 extends CheckForUpdates {
- public CheckForUpdatesIE6() {
+ public CheckForUpdatesIE6(TreeLogger logger, String entryPoint) {
+ super(logger, entryPoint);
LowLevelIE6.init();
}
@Override
- protected byte[] doHttpGet(String userAgent, String url) {
- byte[] response = LowLevelIE6.httpGet(userAgent, url);
+ protected byte[] doHttpGet(TreeLogger branch, String userAgent, String url) {
+ byte[] response = LowLevelIE6.httpGet(branch, userAgent, url,
+ System.getProperty(PROPERTY_DEBUG_HTTP_GET) != null);
return response;
}
diff --git a/dev/windows/src/com/google/gwt/dev/shell/ie/LowLevelIE6.java b/dev/windows/src/com/google/gwt/dev/shell/ie/LowLevelIE6.java
index 0a95c60..19b0613 100644
--- a/dev/windows/src/com/google/gwt/dev/shell/ie/LowLevelIE6.java
+++ b/dev/windows/src/com/google/gwt/dev/shell/ie/LowLevelIE6.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.shell.ie;
+import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.shell.LowLevel;
/**
@@ -32,15 +33,17 @@
* @return the bytes of the full response (including headers), or
* <code>null</code> if there's a problem
*/
- public static byte[] httpGet(String userAgent, String url) {
+ public static byte[] httpGet(TreeLogger branch, String userAgent, String url,
+ boolean debugFlag) {
init();
byte[][] out = new byte[1][];
int status = _httpGet(userAgent, url, out);
if (status == 0) {
return out[0];
} else {
- if (System.getProperty("gwt.debugLowLevelHttpGet") != null) {
- System.err.println("GET failed with status " + status + " for " + url);
+ if (debugFlag) {
+ branch.log(TreeLogger.ERROR, "GET failed with status " + status
+ + " for " + url);
}
return null;
}
diff --git a/distro-source/core/src/samples/build.xml b/distro-source/core/src/samples/build.xml
new file mode 100644
index 0000000..0a77f56
--- /dev/null
+++ b/distro-source/core/src/samples/build.xml
@@ -0,0 +1,30 @@
+<project name="samples" default="build" basedir=".">
+
+ <target name="-do">
+ <ant target="${target}" dir="DynaTable"/>
+ <ant target="${target}" dir="Hello"/>
+ <ant target="${target}" dir="I18N"/>
+ <ant target="${target}" dir="JSON"/>
+ <ant target="${target}" dir="Mail"/>
+ <ant target="${target}" dir="Showcase"/>
+ <ant target="${target}" dir="SimpleXML"/>
+ </target>
+
+ <target name="build" description="Build all samples">
+ <antcall target="-do">
+ <param name="target" value="build" />
+ </antcall>
+ </target>
+
+ <target name="eclipse.generate" description="Generate eclipse projects for all samples">
+ <antcall target="-do">
+ <param name="target" value="eclipse.generate" />
+ </antcall>
+ </target>
+
+ <target name="clean" description="Clean all samples">
+ <antcall target="-do">
+ <param name="target" value="clean" />
+ </antcall>
+ </target>
+</project>
diff --git a/doc/build.xml b/doc/build.xml
index 4974e02..8bfb704 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.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.dom.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.http.client;com.google.gwt.animation.client;com.google.gwt.event.dom.client;com.google.gwt.event.logical.shared;com.google.gwt.event.shared;com.google.gwt.debug.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.server.rpc;com.google.gwt.xml.client;com.google.gwt.user.datepicker.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/reference/code-museum/src/com/google/gwt/museum/client/common/SimpleLogger.java b/reference/code-museum/src/com/google/gwt/museum/client/common/SimpleLogger.java
index eeba505..4642cdd 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/common/SimpleLogger.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/common/SimpleLogger.java
@@ -25,13 +25,10 @@
import com.google.gwt.user.client.ui.VerticalPanel;
/**
- * Helper class to create visual tests.
- *
- * @param <V> value type
- * @param <T> target type
+ * Simple logging class.
*/
@SuppressWarnings("deprecation")
-public class SimpleLogger<V, T> extends Composite {
+public class SimpleLogger extends Composite {
private VerticalPanel panel = new VerticalPanel();
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1932.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1932.java
index e51c222..4a13b2f 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1932.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1932.java
@@ -16,6 +16,7 @@
package com.google.gwt.museum.client.defaultmuseum;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.museum.client.common.AbstractIssue;
@@ -120,15 +121,15 @@
Event.addNativePreviewHandler(new NativePreviewHandler() {
public void onPreviewNativeEvent(NativePreviewEvent event) {
// Ignore events outside of the sandbox
- Event nativeEvent = event.getNativeEvent();
+ NativeEvent nativeEvent = event.getNativeEvent();
Element target = nativeEvent.getTarget();
if (!sandbox.getElement().isOrHasChild(target)
&& !positioner.getElement().isOrHasChild(target)) {
positioner.removeFromParent();
return;
}
-
- switch (nativeEvent.getTypeInt()) {
+
+ switch (Event.as(nativeEvent).getTypeInt()) {
case Event.ONMOUSEMOVE:
int absX = nativeEvent.getClientX() + Window.getScrollLeft();
int absY = nativeEvent.getClientY() + Window.getScrollTop();
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForEventsFiring.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForEventsFiring.java
index 07efe27..cc82e43 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForEventsFiring.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForEventsFiring.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.museum.client.defaultmuseum;
+import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ChangeEvent;
@@ -134,7 +135,7 @@
prepMouseEvents();
prepKeyboardEvents();
- prepSrollAndMouseWheelEvents();
+ prepScrollAndMouseWheelEvents();
prepLoadEvents();
prepWindowEvents();
@@ -213,8 +214,8 @@
*
* @param event the event that was triggered
*/
- private void passTest(Event event) {
- passTest(event.getTypeInt());
+ private void passTest(NativeEvent event) {
+ passTest(Event.as(event).getTypeInt());
}
/**
@@ -247,7 +248,7 @@
// Add event handlers
textBox.addKeyDownHandler(new KeyDownHandler() {
public void onKeyDown(KeyDownEvent event) {
- event.isAutoRepeat();
+
event.isAltKeyDown();
event.isControlKeyDown();
event.isShiftKeyDown();
@@ -332,7 +333,7 @@
private void prepMouseEvents() {
// Create a button to trigger events
- Button button = new Button("Click me") {
+ final Button button = new Button("Click me, move over me") {
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
@@ -386,19 +387,28 @@
public void onMouseOut(MouseOutEvent event) {
assert event.getFromElement() != null;
assert event.getToElement() != null;
- passTest(event.getNativeEvent());
+ if (button.getElement().equals(event.getFromElement())
+ && button.getElement().getParentElement().equals(
+ event.getToElement())) {
+ passTest(event.getNativeEvent());
+ }
}
});
button.addMouseOverHandler(new MouseOverHandler() {
public void onMouseOver(MouseOverEvent event) {
assert event.getFromElement() != null;
assert event.getToElement() != null;
- passTest(event.getNativeEvent());
+
+ if (button.getElement().equals(event.getToElement())
+ && button.getElement().getParentElement().equals(
+ event.getFromElement())) {
+ passTest(event.getNativeEvent());
+ }
}
});
}
- private void prepSrollAndMouseWheelEvents() {
+ private void prepScrollAndMouseWheelEvents() {
// Create a widget to trigger events
String scrollableMessage = "Scroll to the bottom<br>(using mouse wheel<br>"
+ "if supported)";
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForTree.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForTree.java
index 8a280c1..c317aa2 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForTree.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForTree.java
@@ -76,9 +76,11 @@
TreeItem d = new TreeItem(new RadioButton("myradio",
"I should line up nicely"));
TreeItem e = new TreeItem(new CheckBox("I should line up nicely"));
+ TreeItem f = new TreeItem(new CheckBox("I should also line up nicely"));
+ f.addItem(new CheckBox("me to"));
SimplePanel panel = new SimplePanel();
panel.setWidget(new Label("There should not be any space above me"));
- TreeItem f = new TreeItem(panel);
+ TreeItem g = new TreeItem(panel);
tree.setSelectedItem(b);
tree.addItem(a);
@@ -87,6 +89,7 @@
tree.addItem(d);
tree.addItem(e);
tree.addItem(f);
+ tree.addItem(g);
b.addItem(ba);
b.addItem(bb);
bb.addItem(bba);
diff --git a/samples/common.ant.xml b/samples/common.ant.xml
index ef167f4..248acd2 100755
--- a/samples/common.ant.xml
+++ b/samples/common.ant.xml
@@ -77,6 +77,7 @@
<java classname="com.google.gwt.user.tools.WebAppCreator" classpath="${gwt.user.jar}:${gwt.dev.jar}" failonerror="true">
<!-- Relative path is important! Paths will be relative in final distro -->
<sysproperty key="gwt.devjar" value="../../gwt-dev-@{platform}.jar" />
+ <arg value="-XnoEclipse" />
<arg value="-overwrite" />
<arg value="-out" />
<arg file="${samples.scripts}/@{platform}/${sample.upper}" />
diff --git a/samples/dynatable/src/com/google/gwt/sample/dynatable/DynaTable.gwt.xml b/samples/dynatable/src/com/google/gwt/sample/dynatable/DynaTable.gwt.xml
index 137a008..93ee3a3 100644
--- a/samples/dynatable/src/com/google/gwt/sample/dynatable/DynaTable.gwt.xml
+++ b/samples/dynatable/src/com/google/gwt/sample/dynatable/DynaTable.gwt.xml
@@ -13,9 +13,10 @@
<!-- limitations under the License. -->
<module rename-to="dynatable">
- <inherits name='com.google.gwt.user.User'/>
- <entry-point class='com.google.gwt.sample.dynatable.client.DynaTable'/>
- <servlet path='/calendar' class='com.google.gwt.sample.dynatable.server.SchoolCalendarServiceImpl'/>
+ <inherits name='com.google.gwt.user.User' />
+ <entry-point class='com.google.gwt.sample.dynatable.client.DynaTable' />
+ <!--
+ Re-enable this when we have web.xml validation.
+ <servlet path='/calendar' class='com.google.gwt.sample.dynatable.server.SchoolCalendarServiceImpl'/>
+ -->
</module>
-
-
diff --git a/samples/dynatable/src/com/google/gwt/sample/dynatable/client/DayFilterWidget.java b/samples/dynatable/src/com/google/gwt/sample/dynatable/client/DayFilterWidget.java
index 674d739..efbf4e5 100644
--- a/samples/dynatable/src/com/google/gwt/sample/dynatable/client/DayFilterWidget.java
+++ b/samples/dynatable/src/com/google/gwt/sample/dynatable/client/DayFilterWidget.java
@@ -44,7 +44,7 @@
addClickHandler(dayCheckBoxHandler);
// Initialize based on the calendar's current value.
- setChecked(calendar.getDayIncluded(day));
+ setValue(calendar.getDayIncluded(day));
}
}
@@ -52,9 +52,9 @@
public void onClick(ClickEvent event) {
onClick((DayCheckBox) event.getSource());
}
-
+
public void onClick(DayCheckBox dayCheckBox) {
- calendar.setDayIncluded(dayCheckBox.day, dayCheckBox.isChecked());
+ calendar.setDayIncluded(dayCheckBox.day, dayCheckBox.getValue());
}
}
@@ -102,7 +102,7 @@
for (int i = 0, n = outer.getWidgetCount(); i < n; ++i) {
Widget w = outer.getWidget(i);
if (w instanceof DayCheckBox) {
- ((DayCheckBox) w).setChecked(checked);
+ ((DayCheckBox) w).setValue(checked);
dayCheckBoxHandler.onClick((DayCheckBox) w);
}
}
diff --git a/samples/dynatable/war/DynaTable.css b/samples/dynatable/war/DynaTable.css
index ab81abf..038e964 100644
--- a/samples/dynatable/war/DynaTable.css
+++ b/samples/dynatable/war/DynaTable.css
@@ -43,15 +43,15 @@
}
.DynaTable-DynaTableWidget .table td.name {
- width: 10em;
+ width: 20%;
}
.DynaTable-DynaTableWidget .table td.desc {
- width: 20em;
+ width: 30%;
}
.DynaTable-DynaTableWidget .table td.sched {
- width: 20em;
+ width: 50%;
}
.DynaTable-DynaTableWidget .table td {
diff --git a/samples/i18n/src/com/google/gwt/sample/i18n/client/AbstractFormatExampleConstants_fr.properties b/samples/i18n/src/com/google/gwt/sample/i18n/client/AbstractFormatExampleConstants_fr.properties
index 0149b32..efd7ffb 100644
--- a/samples/i18n/src/com/google/gwt/sample/i18n/client/AbstractFormatExampleConstants_fr.properties
+++ b/samples/i18n/src/com/google/gwt/sample/i18n/client/AbstractFormatExampleConstants_fr.properties
@@ -14,7 +14,7 @@
# the License.
#
-inputValue = Valeur a composer
+inputValue = Valeur à composer
formattedOutput = Valeur composée
pattern = Format
invalidPattern = Format invalide
diff --git a/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsExampleConstants_fr.properties b/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsExampleConstants_fr.properties
index 9c060ad..9bb9b45 100644
--- a/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsExampleConstants_fr.properties
+++ b/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsExampleConstants_fr.properties
@@ -16,7 +16,7 @@
firstName = Prénom
lastName = Nom
-favoriteColor = Coleur préférée
+favoriteColor = Couleur préférée
black = Noir
blue = Bleu
diff --git a/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsWithLookupExampleConstants_fr.properties b/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsWithLookupExampleConstants_fr.properties
index 96aa502..26f8d23 100644
--- a/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsWithLookupExampleConstants_fr.properties
+++ b/samples/i18n/src/com/google/gwt/sample/i18n/client/ConstantsWithLookupExampleConstants_fr.properties
@@ -15,6 +15,6 @@
#
input = Nom de méthode
-noInputResult = <Veuillez écrire un nom de méthode ci-dessus>
+noInputResult = <Veuillez tapez un des noms de méthodes ci-dessus>
noMatchingResult = <Non trouvé>
result = Resultat de cherche
diff --git a/samples/i18n/war/I18N.css b/samples/i18n/war/I18N.css
index d8d8033..09e2029 100644
--- a/samples/i18n/war/I18N.css
+++ b/samples/i18n/war/I18N.css
@@ -133,7 +133,7 @@
}
.col2 {
- width: 20em;
+ width: 32em;
}
.col2 * {
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java b/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java
index 92f8330..43fa86a 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java
@@ -21,6 +21,7 @@
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.HTMLTable.Cell;
/**
* A composite that displays a list of emails that can be selected.
@@ -91,9 +92,12 @@
}
} else if (sender == table) {
// Select the row that was clicked (-1 to account for header row).
- int row = table.getCellForEvent(event).getRowIndex();
- if (row > 0) {
- selectRow(row - 1);
+ Cell cell = table.getCellForEvent(event);
+ if (cell != null) {
+ int row = cell.getRowIndex();
+ if (row > 0) {
+ selectRow(row - 1);
+ }
}
}
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/Application.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/Application.java
index 2791dcc..27a7b0a 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/Application.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/Application.java
@@ -62,8 +62,7 @@
*
* <li>.Application-menu { The main menu }</li>
*
- * <li>.Application-content-wrapper { The scrollable element around the content
- * }</li>
+ * <li>.Application-content-wrapper { The scrollable element around the content }</li>
*
* </ul>
*/
@@ -293,8 +292,8 @@
protected void onWindowResizedImpl(int width) {
int menuWidth = mainMenu.getOffsetWidth();
- int contentWidth = width - menuWidth - 30;
- int contentWidthInner = contentWidth - 10;
+ int contentWidth = Math.max(width - menuWidth - 30, 1);
+ int contentWidthInner = Math.max(contentWidth - 10, 1);
bottomPanel.setCellWidth(mainMenu, menuWidth + "px");
bottomPanel.setCellWidth(contentDecorator, contentWidth + "px");
contentLayout.getCellFormatter().setWidth(0, 0, contentWidthInner + "px");
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java
index a4378e3..ee1f6a2 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ContentWidget.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.sample.showcase.client;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.http.client.Request;
@@ -323,7 +324,7 @@
/**
* Load the contents of a remote file into the specified widget.
*
- * @param url the URL of the file relative to the source directory in public
+ * @param url a partial path relative to the module base URL
* @param target the target Widget to place the contents
* @param callback the callback when the call completes
*/
@@ -331,14 +332,16 @@
final RequestCallback callback) {
// Show the loading image
if (loadingImage == null) {
- loadingImage = "<img src=\"images/loading.gif\">";
+ loadingImage = "<img src=\"" + GWT.getModuleBaseURL()
+ + "images/loading.gif\">";
}
target.setDirection(HasDirection.Direction.LTR);
DOM.setStyleAttribute(target.getElement(), "textAlign", "left");
target.setHTML(" " + loadingImage);
// Request the contents of the file
- RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
+ RequestBuilder builder = new RequestBuilder(RequestBuilder.GET,
+ GWT.getModuleBaseURL() + url);
RequestCallback realCallback = new RequestCallback() {
public void onError(Request request, Throwable exception) {
target.setHTML("Cannot find resource");
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwBasicText.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwBasicText.java
index 5d586d7..9829e3e 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwBasicText.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/text/CwBasicText.java
@@ -125,6 +125,7 @@
// Add a text area
TextArea textArea = new TextArea();
textArea.ensureDebugId("cwBasicText-textarea");
+ textArea.setVisibleLines(5);
vpanel.add(new HTML("<br><br>" + constants.cwBasicTextAreaLabel()));
vpanel.add(createTextExample(textArea, true));
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwHyperlink.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwHyperlink.java
index 2a9abfe..2ed3d5a 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwHyperlink.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwHyperlink.java
@@ -94,6 +94,7 @@
vPanel.add(getHyperlink(CwCustomButton.class,
allConstants.cwCustomButtonName()));
vPanel.add(getHyperlink(CwFileUpload.class, allConstants.cwFileUploadName()));
+ vPanel.add(getHyperlink(CwDatePicker.class, allConstants.cwDatePickerName()));
// Return the panel
return vPanel;
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwRadioButton.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwRadioButton.java
index dd5f1b8..c59aa79 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwRadioButton.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwRadioButton.java
@@ -111,7 +111,7 @@
radioButton.ensureDebugId("cwRadioButton-sport-"
+ sport.replaceAll(" ", ""));
if (i == 2) {
- radioButton.setChecked(true);
+ radioButton.setValue(true);
}
vPanel.add(radioButton);
}
diff --git a/tools/api-checker/config/gwt15_16userApi.conf b/tools/api-checker/config/gwt15_16userApi.conf
index 020f74a..922379c 100644
--- a/tools/api-checker/config/gwt15_16userApi.conf
+++ b/tools/api-checker/config/gwt15_16userApi.conf
@@ -98,6 +98,5 @@
# to be hard. Come back and fix this issue, if more such cases come up.
java.lang.StringBuilder::append(Ljava/lang/StringBuffer;) OVERRIDABLE_METHOD_ARGUMENT_TYPE_CHANGE
com.google.gwt.user.client.ui.Button::Button(Ljava/lang/String;Lcom/google/gwt/user/client/ui/ClickListener;) OVERLOADED_METHOD_CALL
-com.google.gwt.user.client.ui.MultiWordSuggestOracle::addAll(Ljava/util/Collection;) FINAL_ADDED
com.google.gwt.user.client.ui.ToggleButton::ToggleButton(Lcom/google/gwt/user/client/ui/Image;Lcom/google/gwt/user/client/ui/Image;Lcom/google/gwt/user/client/ui/ClickListener;) OVERLOADED_METHOD_CALL
com.google.gwt.user.client.ui.Tree::setImageBase(Ljava/lang/String;) MISSING
diff --git a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClass.java b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClass.java
index 4e04f5d..616a3f0 100644
--- a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClass.java
+++ b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClass.java
@@ -225,8 +225,7 @@
JField fields[] = getAccessibleFields();
for (JField field : fields) {
if (isApiMember(field)) {
- apiFields.put(ApiField.computeApiSignature(field), new ApiField(field,
- this));
+ apiFields.put(field.getName(), new ApiField(field, this));
} else {
notAddedFields.add(field.toString());
}
diff --git a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClassDiffGenerator.java b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClassDiffGenerator.java
index 9a2c5b1..59a65df 100644
--- a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClassDiffGenerator.java
+++ b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiClassDiffGenerator.java
@@ -190,21 +190,57 @@
return collection;
}
- private boolean isIncompatibileDueToMethodOverloading(
+ /**
+ * Attempts to find out if a methodName(null) call previously succeeded, and
+ * would fail with the new Api. Currently, this method is simple.
+ * TODO(amitmanjhi): generalize this method.
+ *
+ * @param methodsInNew Candidate methods in the new Api
+ * @param methodsInExisting Candidate methods in the existing Api.
+ * @return the possible incompatibilities due to method overloading.
+ */
+ private Map<ApiAbstractMethod, ApiChange> getOverloadedMethodIncompatibility(
Set<ApiAbstractMethod> methodsInNew,
Set<ApiAbstractMethod> methodsInExisting) {
if (!ApiCompatibilityChecker.API_SOURCE_COMPATIBILITY
|| methodsInExisting.size() != 1 || methodsInNew.size() <= 1) {
- return false;
+ return Collections.emptyMap();
}
- String signature = methodsInExisting.toArray(new ApiAbstractMethod[0])[0].getCoarseSignature();
- int numMatchingSignature = 0;
+ ApiAbstractMethod existingMethod = methodsInExisting.toArray(new ApiAbstractMethod[0])[0];
+ String signature = existingMethod.getCoarseSignature();
+ List<ApiAbstractMethod> matchingMethods = new ArrayList<ApiAbstractMethod>();
for (ApiAbstractMethod current : methodsInNew) {
if (current.getCoarseSignature().equals(signature)) {
- ++numMatchingSignature;
+ matchingMethods.add(current);
}
}
- return numMatchingSignature > 1;
+ if (isPairwiseCompatible(matchingMethods)) {
+ return Collections.emptyMap();
+ }
+ Map<ApiAbstractMethod, ApiChange> incompatibilities = new HashMap<ApiAbstractMethod, ApiChange>();
+ incompatibilities.put(existingMethod, new ApiChange(existingMethod,
+ ApiChange.Status.OVERLOADED_METHOD_CALL,
+ "Many methods in the new API with similar signatures. Methods = "
+ + methodsInNew + " This might break API source compatibility"));
+ return incompatibilities;
+ }
+
+ /**
+ * @return true if each pair of methods within the list is compatibile.
+ */
+ private boolean isPairwiseCompatible(List<ApiAbstractMethod> methods) {
+ int length = methods.size();
+ for (int i = 0; i < length - 1; i++) {
+ for (int j = i + 1; j < length; j++) {
+ ApiAbstractMethod firstMethod = methods.get(i);
+ ApiAbstractMethod secondMethod = methods.get(j);
+ if (!firstMethod.isCompatible(secondMethod)
+ && !secondMethod.isCompatible(firstMethod)) {
+ return false;
+ }
+ }
+ }
+ return true;
}
/**
@@ -230,12 +266,11 @@
elementName, methodType);
onlyInNew.addAll(methodsInNew);
onlyInExisting.addAll(methodsInExisting);
- if (isIncompatibileDueToMethodOverloading(methodsInNew, methodsInExisting)) {
- ApiAbstractMethod methodInExisting = methodsInExisting.toArray(new ApiAbstractMethod[0])[0];
- addProperty(intersectingElements, methodInExisting, new ApiChange(
- methodInExisting, ApiChange.Status.OVERLOADED_METHOD_CALL,
- "Many methods in the new API with similar signatures. Methods = "
- + methodsInNew + " This might break API source compatibility"));
+ Map<ApiAbstractMethod, ApiChange> incompatibilityMap = getOverloadedMethodIncompatibility(
+ methodsInNew, methodsInExisting);
+ for (ApiAbstractMethod existingMethod : incompatibilityMap.keySet()) {
+ addProperty(intersectingElements, existingMethod,
+ incompatibilityMap.get(existingMethod));
}
/*
diff --git a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiMethod.java b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiMethod.java
index d911d3a..1667a2d 100644
--- a/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiMethod.java
+++ b/tools/api-checker/src/com/google/gwt/tools/apichecker/ApiMethod.java
@@ -175,7 +175,8 @@
+ getApiSignature());
}
List<ApiChange.Status> statuses = new ArrayList<ApiChange.Status>();
- if (!oldjmethod.isFinal() && newjmethod.isFinal()) {
+ if (!oldjmethod.isFinal() && !apiClass.getClassObject().isFinal()
+ && newjmethod.isFinal()) {
statuses.add(ApiChange.Status.FINAL_ADDED);
}
if (!oldjmethod.isAbstract() && newjmethod.isAbstract()) {
diff --git a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityTest.java b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityTest.java
index 54117a9..5a2357e 100644
--- a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityTest.java
+++ b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityTest.java
@@ -38,6 +38,10 @@
* to both ApiClass, apiMethods.
*
* test white-list support.
+ *
+ * TODO(amitmanjhi): (1) Re-factor this code as much as possible into smaller
+ * separate components similar to the ApiCompatibilityUnit class. (2) Use
+ * MockApiElement instead of String comparisons.
*/
public class ApiCompatibilityTest extends TestCase {
@@ -76,8 +80,8 @@
StringBuffer sb = new StringBuffer();
sb.append("package test.apicontainer;\n");
sb.append("class NonApiClass extends java.lang.Object {\n");
- sb.append("\tpublic void methodInNonApiClass(java.lang.Object o) { };\n");
- sb.append("\tpublic void methodInNonApiClass(test.apicontainer.NonApiClass t) { };\n");
+ sb.append("\tpublic void methodInNonApiClass(ApiClassInNonApiClass o) { };\n");
+ sb.append("\tpublic void methodInNonApiClass(NonApiClass t) { };\n");
sb.append("\tpublic int fieldInNonApiClass = 3;\n");
sb.append("\tprotected abstract class ApiClassInNonApiClass {\n");
sb.append("\tprotected ApiClassInNonApiClass() { }\n");
@@ -246,7 +250,7 @@
assertEquals(2, countPresence(finalMethodSignature, strWithoutDuplicates));
// test method_overloading
- finalMethodSignature = "methodInNonApiClass(Ljava/lang/Object;)";
+ finalMethodSignature = "methodInNonApiClass(Ltest/apicontainer/NonApiClass;)";
assertEquals(1, countPresence(finalMethodSignature + delimiter
+ ApiChange.Status.OVERLOADED_METHOD_CALL, strWithoutDuplicates));
@@ -264,9 +268,6 @@
strWithoutDuplicates));
}
- assertEquals(1, countPresence(methodSignature + delimiter
- + ApiChange.Status.OVERLOADED_METHOD_CALL, strWithoutDuplicates));
-
// the method should be satisfied by the method in the super-class
methodSignature = "test.apicontainer.OneMoreApiClass::checkOverloadedMethodAccounted(Ltest/apicontainer/OneMoreApiClass;)";
assertEquals(0, countPresence(methodSignature + delimiter
diff --git a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityUnitTest.java b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityUnitTest.java
new file mode 100644
index 0000000..073b3ae
--- /dev/null
+++ b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiCompatibilityUnitTest.java
@@ -0,0 +1,300 @@
+/*
+ * 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.tools.apichecker;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.NotFoundException;
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.util.log.AbstractTreeLogger;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+import com.google.gwt.tools.apichecker.ApiCompatibilityChecker.StaticCompilationUnit;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Base class for all the ApiCompatibility Testing. Encapsulates two api
+ * containers and a test method.
+ *
+ */
+public class ApiCompatibilityUnitTest extends TestCase {
+
+ /**
+ * Mock class to test if the correct ApiChange(s) are being returned.
+ *
+ */
+ static class MockApiElement implements ApiElement {
+
+ final String signature;
+
+ public MockApiElement(String signature) {
+ this.signature = signature;
+ }
+
+ public String getRelativeSignature() {
+ return signature;
+ }
+ }
+
+ private static class FinalKeywordRefactoring {
+ private static String getFirstApiSourceForObject() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("package java.lang;\n");
+ sb.append("public final class Object {\n");
+ sb.append("\tpublic Object foo;\n");
+ sb.append("\tpublic void bar() {}\n");
+ sb.append("}\n");
+ return sb.toString();
+ }
+
+ private static String getSecondApiSourceForObject() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("package java.lang;\n");
+ sb.append("public class Object {\n");
+ sb.append("\tpublic final Object foo;\n");
+ sb.append("\tpublic final void bar() {}\n");
+ sb.append("}\n");
+ return sb.toString();
+ }
+
+ void testBothWays() throws NotFoundException, UnableToCompleteException {
+ Map<String, String> firstApi = new HashMap<String, String>();
+ firstApi.put("java.lang.Object", getFirstApiSourceForObject());
+ Map<String, String> secondApi = new HashMap<String, String>();
+ secondApi.put("java.lang.Object", getSecondApiSourceForObject());
+
+ // firstApi is the reference Api
+ Collection<ApiChange> apiChanges = getApiChanges(firstApi, secondApi);
+ assertEquals(Arrays.asList(new ApiChange[] {new ApiChange(
+ new MockApiElement("java.lang.Object::foo"),
+ ApiChange.Status.FINAL_ADDED),}), apiChanges);
+
+ // secondApi is the reference Api
+ apiChanges = getApiChanges(secondApi, firstApi);
+ assertEquals(
+ Arrays.asList(new ApiChange[] {new ApiChange(new MockApiElement(
+ "java.lang.Object"), ApiChange.Status.FINAL_ADDED),}), apiChanges);
+ }
+ }
+
+ /**
+ * Test when method overloading results in Api incompatibilities.
+ * <p>
+ * Imagine a class Foo had a method foo(String ..). If in the new Api, a
+ * method foo(Integer ..) is added, ApiChecker should output a
+ * OVERLOADED_METHOD_CALL Api change (because foo(null) cannot be compiled).
+ * However, if foo(Object ..) is added, it should be okay since JLS matches
+ * from the most specific to the least specific.
+ */
+ private static class OverloadedMethodRefactoring {
+ private static String getFirstApiSourceForObject() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("package java.lang;\n");
+ sb.append("public class Object {\n");
+ sb.append("\tstatic class Foo extends java.lang.Object {\n");
+ sb.append("\t}\n");
+ sb.append("\tstatic class Bar extends java.lang.Object {\n");
+ sb.append("\t}\n");
+ sb.append("\tpublic void fooObject(Foo x){}\n");
+ sb.append("\tpublic void fooBar(Foo y){}\n");
+ sb.append("}\n");
+ return sb.toString();
+ }
+
+ private static String getSecondApiSourceForObject() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("package java.lang;\n");
+ sb.append("public class Object {\n");
+ sb.append("\tstatic class Foo extends java.lang.Object {\n");
+ sb.append("\t}\n");
+ sb.append("\tstatic class Bar extends java.lang.Object {\n");
+ sb.append("\t}\n");
+ sb.append("\tpublic void fooObject(Foo x){}\n");
+ sb.append("\tpublic void fooObject(Object x){}\n");
+ sb.append("\tpublic void fooBar(Foo y){}\n");
+ sb.append("\tpublic void fooBar(Bar y){}\n");
+ sb.append("}\n");
+ return sb.toString();
+ }
+
+ void testBothWays() throws NotFoundException, UnableToCompleteException {
+ Map<String, String> firstApi = new HashMap<String, String>();
+ firstApi.put("java.lang.Object", getFirstApiSourceForObject());
+ Map<String, String> secondApi = new HashMap<String, String>();
+ secondApi.put("java.lang.Object", getSecondApiSourceForObject());
+
+ // firstApi is the reference Api
+ Collection<ApiChange> apiChanges = getApiChanges(firstApi, secondApi);
+ assertEquals(
+ Arrays.asList(new ApiChange[] {new ApiChange(new MockApiElement(
+ "java.lang.Object::fooBar(Ljava/lang/Object$Foo;)"),
+ ApiChange.Status.OVERLOADED_METHOD_CALL),}), apiChanges);
+
+ // secondApi is the reference Api
+ apiChanges = getApiChanges(secondApi, firstApi);
+ assertEquals(Arrays.asList(new ApiChange[] {
+ new ApiChange(new MockApiElement(
+ "java.lang.Object::fooBar(Ljava/lang/Object$Bar;)"),
+ ApiChange.Status.MISSING),
+ new ApiChange(new MockApiElement(
+ "java.lang.Object::fooObject(Ljava/lang/Object;)"),
+ ApiChange.Status.MISSING),}), apiChanges);
+ }
+ }
+
+ /**
+ * Test whether the ApiChecker correctly identifies moving fields and methods
+ * to a super class.
+ *
+ */
+ private static class SuperClassRefactoring {
+ private static String getFirstApiSourceForObject() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("package java.lang;\n");
+ sb.append("public class Object {\n");
+ sb.append("\t\tpublic static void staticMethod(){}\n");
+ sb.append("\t\tpublic static int staticField = 1;\n");
+ sb.append("\t\tpublic int instanceField = 2;\n");
+ sb.append("\tpublic static class Foo extends java.lang.Object {\n");
+ sb.append("\t}\n");
+ sb.append("}\n");
+ return sb.toString();
+ }
+
+ private static String getSecondApiSourceForObject() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("package java.lang;\n");
+ sb.append("public class Object {\n");
+ sb.append("\tpublic static class Foo extends java.lang.Object {\n");
+ sb.append("\t\tpublic static void staticMethod(){}\n");
+ sb.append("\t\tpublic static int staticField = 1;\n");
+ sb.append("\t\tpublic int instanceField = 2;\n");
+ sb.append("\t}\n");
+ sb.append("}\n");
+ return sb.toString();
+ }
+
+ void testBothWays() throws NotFoundException, UnableToCompleteException {
+ Map<String, String> firstApi = new HashMap<String, String>();
+ firstApi.put("java.lang.Object", getFirstApiSourceForObject());
+ Map<String, String> secondApi = new HashMap<String, String>();
+ secondApi.put("java.lang.Object", getSecondApiSourceForObject());
+
+ // firstApi is the reference Api
+ Collection<ApiChange> apiChanges = getApiChanges(firstApi, secondApi);
+ assertEquals(Arrays.asList(new ApiChange[] {
+ new ApiChange(new MockApiElement("java.lang.Object::instanceField"),
+ ApiChange.Status.MISSING),
+ new ApiChange(new MockApiElement("java.lang.Object::staticField"),
+ ApiChange.Status.MISSING),
+ new ApiChange(new MockApiElement("java.lang.Object::staticMethod()"),
+ ApiChange.Status.MISSING),}), apiChanges);
+
+ // secondApi is the reference Api
+ apiChanges = getApiChanges(secondApi, firstApi);
+ assertEquals(0, apiChanges.size());
+ }
+ }
+
+ /**
+ * Assert that two ApiChanges are equal.
+ */
+ static void assertEquals(ApiChange apiChange1, ApiChange apiChange2) {
+ assert apiChange1 != null;
+ assert apiChange2 != null;
+ assertEquals(apiChange1.getStatus(), apiChange2.getStatus());
+ assertEquals(apiChange1.getApiElement().getRelativeSignature(),
+ apiChange2.getApiElement().getRelativeSignature());
+ }
+
+ /**
+ * Assert that two sets of ApiChanges are equal.
+ */
+ static void assertEquals(Collection<ApiChange> collection1,
+ Collection<ApiChange> collection2) {
+ assertEquals(collection1.size(), collection2.size());
+
+ List<ApiChange> list1 = new ArrayList<ApiChange>();
+ list1.addAll(collection1);
+ Collections.sort(list1);
+
+ List<ApiChange> list2 = new ArrayList<ApiChange>();
+ list2.addAll(collection2);
+ Collections.sort(list2);
+
+ for (int i = 0; i < list1.size(); i++) {
+ assertEquals(list1.get(i), list2.get(i));
+ }
+ }
+
+ /**
+ * Returns the apiChanges from moving to an existing api to a new Api.
+ *
+ * @param existingTypesToSourcesMap existing Api
+ * @param newTypesToSourcesMap new Api
+ * @return A collection of ApiChange
+ */
+ static Collection<ApiChange> getApiChanges(
+ Map<String, String> existingTypesToSourcesMap,
+ Map<String, String> newTypesToSourcesMap)
+ throws UnableToCompleteException, NotFoundException {
+
+ AbstractTreeLogger logger = new PrintWriterTreeLogger();
+ logger.setMaxDetail(TreeLogger.ERROR);
+
+ Set<CompilationUnit> set1 = new HashSet<CompilationUnit>();
+ for (String type : existingTypesToSourcesMap.keySet()) {
+ set1.add(new StaticCompilationUnit(type,
+ existingTypesToSourcesMap.get(type)));
+ }
+ Set<String> emptyList = Collections.emptySet();
+ Set<CompilationUnit> set2 = new HashSet<CompilationUnit>();
+ for (String type : existingTypesToSourcesMap.keySet()) {
+ set2.add(new StaticCompilationUnit(type, newTypesToSourcesMap.get(type)));
+ }
+
+ ApiContainer existingApi = new ApiContainer("existingApi", set1, emptyList,
+ logger);
+ ApiContainer newApi = new ApiContainer("newApi", set2, emptyList, logger);
+ return ApiCompatibilityChecker.getApiDiff(newApi, existingApi, emptyList);
+ }
+
+ public void testFinalKeywordRefactoring() throws NotFoundException,
+ UnableToCompleteException {
+ new FinalKeywordRefactoring().testBothWays();
+ }
+
+ public void testMethodOverloading() throws NotFoundException,
+ UnableToCompleteException {
+ new OverloadedMethodRefactoring().testBothWays();
+ }
+
+ public void testSuperClassRefactoring() throws NotFoundException,
+ UnableToCompleteException {
+ new SuperClassRefactoring().testBothWays();
+ }
+
+}
diff --git a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java
index 90deed9..f21a63b 100644
--- a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java
+++ b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java
@@ -95,7 +95,7 @@
StringBuffer sb = new StringBuffer();
sb.append("package test.apicontainer;\n");
sb.append("class NonApiClass extends java.lang.Object {\n");
- sb.append("\tpublic void methodInNonApiClass(java.lang.Object a) { };\n");
+ sb.append("\tpublic void methodInNonApiClass(NonApiClass a) { };\n");
sb.append("\tpublic int fieldInNonApiClass = 3;\n");
sb.append("\tprotected class ApiClassInNonApiClass {\n");
sb.append("\tprotected ApiClassInNonApiClass() { }\n");
diff --git a/user/build.xml b/user/build.xml
index 31fe611..f18d8f7 100755
--- a/user/build.xml
+++ b/user/build.xml
@@ -12,6 +12,11 @@
<fileset id="default.emma.tests" dir="${javac.junit.out}"
includes="**/EmmaClassLoadingTest.class" />
+
+ <fileset id="default.hosted.emma.tests" dir="${javac.junit.out}"
+ excludes="**/CoverageTest.class" includes="**/*Test.class" />
+ <!-- everything succeeds except CoverageTest.java. It fails due to a javac bug in sun/OpenJDK's Java. See the file contents for details -->
+
<!--
Default web mode test cases
-->
@@ -96,6 +101,15 @@
</gwt.junit>
</target>
+ <target name="test.hosted.emma" depends="compile, compile.tests" description="Run all hosted-mode tests in emma mode.">
+ <gwt.junit test.args="${test.args}" test.out="${junit.out}/${build.host.platform}-hosted-mode" test.cases="default.hosted.emma.tests" >
+ <extraclasspaths>
+ <pathelement location="${gwt.build}/out/dev/core/bin-test" />
+ <pathelement location="${gwt.tools.redist}/emma/emma.jar" />
+ </extraclasspaths>
+ </gwt.junit>
+ </target>
+
<target name="test.hosted" depends="compile, compile.tests" description="Run only hosted-mode tests for this project.">
<gwt.junit test.args="${test.args}" test.out="${junit.out}/${build.host.platform}-hosted-mode" test.cases="default.hosted.tests" >
<extraclasspaths>
@@ -107,7 +121,7 @@
<pathelement location="${gwt.build}/out/dev/core/bin-test" />
<pathelement location="${gwt.tools.redist}/emma/emma.jar" />
</extraclasspaths>
- </gwt.junit>
+ </gwt.junit>
</target>
<target name="test.web" depends="compile, compile.tests" description="Run only web-mode tests for this project.">
@@ -150,5 +164,7 @@
<delete dir="${project.build}" />
<delete file="${project.lib}" />
</target>
-
+ <target name="presubmit" depends="test, checkstyle" description="runs the gwt api checker, user checkstyle, and user tests">
+ <gwt.ant dir=".." target="apicheck-nobuild"/>
+ </target>
</project>
diff --git a/user/src/com/google/gwt/dom/client/ButtonElement.java b/user/src/com/google/gwt/dom/client/ButtonElement.java
index 5823486..f5eb93a 100644
--- a/user/src/com/google/gwt/dom/client/ButtonElement.java
+++ b/user/src/com/google/gwt/dom/client/ButtonElement.java
@@ -40,9 +40,9 @@
/**
* Simulate a mouse-click.
*/
- public final native void click() /*-{
- this.click();
- }-*/;
+ public final void click() {
+ DOMImpl.impl.buttonClick(this);
+ }
/**
* A single character access key to give access to the form control.
diff --git a/user/src/com/google/gwt/dom/client/DOMImpl.java b/user/src/com/google/gwt/dom/client/DOMImpl.java
index c4a10d1..738849d 100644
--- a/user/src/com/google/gwt/dom/client/DOMImpl.java
+++ b/user/src/com/google/gwt/dom/client/DOMImpl.java
@@ -21,10 +21,17 @@
static final DOMImpl impl = GWT.create(DOMImpl.class);
+ public native void buttonClick(ButtonElement button) /*-{
+ button.click();
+ }-*/;
+
public native Element createElement(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");
e.type = type;
@@ -33,6 +40,15 @@
public abstract InputElement createInputRadioElement(String name);
+ public abstract NativeEvent createKeyEvent(Document doc, String type,
+ boolean canBubble, boolean cancelable, boolean ctrlKey, boolean altKey,
+ boolean shiftKey, boolean metaKey, int keyCode, int charCode);
+
+ public abstract NativeEvent createMouseEvent(Document doc, String type,
+ boolean canBubble, boolean cancelable, int detail, int screenX,
+ 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");
elem.setText(source);
@@ -47,6 +63,73 @@
return select;
}
+ public abstract void dispatchEvent(Element target, NativeEvent evt);
+
+ public native boolean eventGetAltKey(NativeEvent evt) /*-{
+ return !!evt.altKey;
+ }-*/;
+
+ public native int eventGetButton(NativeEvent evt) /*-{
+ return evt.button || 0;
+ }-*/;
+
+ public native int eventGetClientX(NativeEvent evt) /*-{
+ return evt.clientX || 0;
+ }-*/;
+
+ public native int eventGetClientY(NativeEvent evt) /*-{
+ return evt.clientY || 0;
+ }-*/;
+
+ public native boolean eventGetCtrlKey(NativeEvent evt) /*-{
+ return !!evt.ctrlKey;
+ }-*/;
+
+ public final native int eventGetKeyCode(NativeEvent evt) /*-{
+ // 'which' gives the right key value, except when it doesn't -- in which
+ // case, keyCode gives the right value on all browsers.
+ // If all else fails, return an error code
+ return evt.which || evt.keyCode || 0;
+ }-*/;
+
+ public native boolean eventGetMetaKey(NativeEvent evt) /*-{
+ return !!evt.metaKey;
+ }-*/;
+
+ public abstract int eventGetMouseWheelVelocityY(NativeEvent evt);
+
+ public abstract Element eventGetRelatedTarget(NativeEvent nativeEvent);
+
+ public native int eventGetScreenX(NativeEvent evt) /*-{
+ return evt.screenX || 0;
+ }-*/;
+
+ public native int eventGetScreenY(NativeEvent evt) /*-{
+ return evt.screenY || 0;
+ }-*/;
+
+ public native boolean eventGetShiftKey(NativeEvent evt) /*-{
+ return !!evt.shiftKey;
+ }-*/;
+
+ public abstract Element eventGetTarget(NativeEvent evt);
+
+ public final native String eventGetType(NativeEvent evt) /*-{
+ return evt.type;
+ }-*/;
+
+ public abstract void eventPreventDefault(NativeEvent evt);
+
+ public native void eventSetKeyCode(NativeEvent evt, char key) /*-{
+ evt.keyCode = key;
+ }-*/;
+
+ public native void eventStopPropagation(NativeEvent evt) /*-{
+ evt.stopPropagation();
+ }-*/;
+
+ public abstract String eventToString(NativeEvent evt);
+
public native int getAbsoluteLeft(Element elem) /*-{
var left = 0;
var curr = elem;
diff --git a/user/src/com/google/gwt/dom/client/DOMImplIE6.java b/user/src/com/google/gwt/dom/client/DOMImplIE6.java
index ba1dfaa..fa32bdb 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplIE6.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplIE6.java
@@ -22,8 +22,65 @@
class DOMImplIE6 extends DOMImpl {
@Override
+ public native NativeEvent createHtmlEvent(Document doc, String type, boolean canBubble,
+ boolean cancelable) /*-{
+ // NOTE: IE doesn't support changing bubbling and canceling behavior (this
+ // is documented publicly in Document.createHtmlEvent()).
+ var evt = doc.createEventObject();
+ evt.type = type;
+ return evt;
+ }-*/;
+
+ @Override
public native InputElement createInputRadioElement(String name) /*-{
return $doc.createElement("<INPUT type='RADIO' name='" + name + "'>");
+ }-*/;
+
+ @Override
+ public native NativeEvent createKeyEvent(Document doc, String type, boolean canBubble,
+ boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey,
+ boolean metaKey, int keyCode, int charCode) /*-{
+ // NOTE: IE doesn't support changing bubbling and canceling behavior (this
+ // is documented publicly in Document.createKeyEvent()).
+ var evt = doc.createEventObject();
+ evt.type = type;
+ evt.ctrlKey = ctrlKey;
+ evt.altKey = altKey;
+ evt.shiftKey = shiftKey;
+ evt.metaKey = metaKey;
+ evt.keyCode = keyCode;
+ evt.charCode = charCode;
+
+ return evt;
+ }-*/;
+
+ @Override
+ public native NativeEvent createMouseEvent(Document doc, String type, boolean canBubble,
+ boolean cancelable, int detail, int screenX, int screenY, int clientX,
+ int clientY, boolean ctrlKey, boolean altKey, boolean shiftKey,
+ boolean metaKey, int button, Element relatedTarget) /*-{
+ // NOTE: IE doesn't support changing bubbling and canceling behavior (this
+ // is documented publicly in Document.createMouseEvent()).
+ var evt = doc.createEventObject();
+ evt.type = type;
+ evt.detail = detail;
+ evt.screenX = screenX;
+ evt.screenY = screenY;
+ evt.clientX = clientX;
+ evt.clientY = clientY;
+ evt.ctrlKey = ctrlKey;
+ evt.altKey = altKey;
+ evt.shiftKey = shiftKey;
+ evt.metaKey = metaKey;
+ evt.button = button;
+
+ // It would make sense to set evt.[fromElement | toElement] here, because
+ // that's what IE uses. However, setting these properties has no effect for
+ // some reason. So instead we set releatedTarget, and explicitly check for
+ // its existence in eventGetFromElement() and eventGetToElement().
+ evt.relatedTarget = relatedTarget;
+
+ return evt;
}-*/;
/**
@@ -39,14 +96,52 @@
return $doc.createElement(html);
}-*/;
+ public native void dispatchEvent(Element target, NativeEvent evt) /*-{
+ target.fireEvent("on" + evt.type, evt);
+ }-*/;
+
+ @Override
+ public native int eventGetMouseWheelVelocityY(NativeEvent evt) /*-{
+ return Math.round(-evt.wheelDelta / 40) || 0;
+ }-*/;
+
+ @Override
+ public native Element eventGetRelatedTarget(NativeEvent evt) /*-{
+ // Prefer 'relatedTarget' if it's set (see createMouseEvent(), which
+ // explicitly sets relatedTarget when synthesizing mouse events).
+ return evt.relatedTarget ||
+ (evt.type == "mouseout" ? evt.toElement:evt.fromElement);
+ }-*/;
+
+ @Override
+ public native Element eventGetTarget(NativeEvent evt) /*-{
+ return evt.srcElement;
+ }-*/;
+
+ @Override
+ public native void eventPreventDefault(NativeEvent evt) /*-{
+ evt.returnValue = false;
+ }-*/;
+
+ @Override
+ public native void eventStopPropagation(NativeEvent evt) /*-{
+ evt.cancelBubble = true;
+ }-*/;
+
+ @Override
+ public native String eventToString(NativeEvent evt) /*-{
+ if (evt.toString) return evt.toString();
+ return "[event" + evt.type + "]";
+ }-*/;
+
@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 (elem.getBoundingClientRect().left /
+ return Math.floor((elem.getBoundingClientRect().left /
this.@com.google.gwt.dom.client.DOMImplIE6::getZoomMultiple()()) +
- @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollLeft;
+ @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollLeft);
} catch (e) {
return 0;
}
@@ -57,18 +152,20 @@
// 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 /
+ return Math.floor((elem.getBoundingClientRect().top /
this.@com.google.gwt.dom.client.DOMImplIE6::getZoomMultiple()()) +
- @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollTop;
+ @com.google.gwt.user.client.impl.DocumentRootImpl::documentRoot.scrollTop);
} catch (e) {
return 0;
}
}-*/;
+ @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;
}-*/;
@@ -128,8 +225,8 @@
}-*/;
/**
- * 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%.
+ * 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%.
*
* @return the zoom multiple
*/
diff --git a/user/src/com/google/gwt/dom/client/DOMImplMozilla.java b/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
index 0d1d36b..49519e0 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplMozilla.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
@@ -21,6 +21,11 @@
class DOMImplMozilla extends DOMImplStandard {
@Override
+ public native int eventGetMouseWheelVelocityY(NativeEvent evt) /*-{
+ return evt.detail || 0;
+ }-*/;
+
+ @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
@@ -67,13 +72,13 @@
var style = $wnd.getComputedStyle($doc.documentElement, '');
return parseInt(style.marginLeft) + parseInt(style.borderLeftWidth);
}-*/;
-
+
@Override
public native int getBodyOffsetTop() /*-{
var style = $wnd.getComputedStyle($doc.documentElement, '');
return parseInt(style.marginTop) + parseInt(style.borderTopWidth);
}-*/;
-
+
@Override
public native String getInnerText(Element elem) /*-{
return elem.textContent;
@@ -83,9 +88,9 @@
public native boolean isOrHasChild(Element parent, Element child) /*-{
// For more information about compareDocumentPosition, see:
// http://www.quirksmode.org/blog/archives/2006/01/contains_for_mo.html
- return (parent === child) || !!(parent.compareDocumentPosition(child) & 16);
+ return (parent === child) || !!(parent.compareDocumentPosition(child) & 16);
}-*/;
-
+
@Override
public native void setInnerText(Element elem, String text) /*-{
elem.textContent = text || '';
diff --git a/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java b/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java
index b4e375b..6b22e52 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java
@@ -24,6 +24,16 @@
*/
class DOMImplMozillaOld extends DOMImplMozilla {
+ public native void buttonClick(ButtonElement button) /*-{
+ var doc = button.ownerDocument;
+ if (doc != null) {
+ var evt = doc.createEvent('MouseEvents');
+ evt.initMouseEvent('click', true, true, null, 0, 0,
+ 0, 0, 0, false, false, false, false, 0, null);
+ button.dispatchEvent(evt);
+ }
+ }-*/;
+
@Override
public native int getAbsoluteLeft(Element elem) /*-{
var style = $doc.defaultView.getComputedStyle(elem, null);
diff --git a/user/src/com/google/gwt/dom/client/DOMImplOpera.java b/user/src/com/google/gwt/dom/client/DOMImplOpera.java
index e8c27e4..58f1d69 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplOpera.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplOpera.java
@@ -21,6 +21,11 @@
class DOMImplOpera extends DOMImplStandard {
@Override
+ public native int eventGetMouseWheelVelocityY(NativeEvent evt) /*-{
+ return evt.detail * 4 || 0;
+ }-*/;
+
+ @Override
public native int getAbsoluteLeft(Element elem) /*-{
var left = 0;
@@ -63,7 +68,7 @@
}
return top;
}-*/;
-
+
@Override
public native void scrollIntoView(Element elem) /*-{
elem.scrollIntoView();
diff --git a/user/src/com/google/gwt/dom/client/DOMImplSafari.java b/user/src/com/google/gwt/dom/client/DOMImplSafari.java
index 2265d48..34c50dd 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplSafari.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplSafari.java
@@ -19,6 +19,24 @@
* Safari implementation of {@link com.google.gwt.user.client.impl.DOMImpl}.
*/
class DOMImplSafari extends DOMImplStandard {
+
+ @Override
+ public native NativeEvent createKeyEvent(Document doc, String type, boolean canBubble,
+ boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey,
+ boolean metaKey, int keyCode, int charCode) /*-{
+ // The spec calls for KeyEvents/initKeyEvent(), but that doesn't exist on WebKit.
+ var evt = doc.createEvent('HTMLEvents');
+ evt.initEvent(type, canBubble, cancelable);
+ evt.ctrlKey = ctrlKey;
+ evt.altKey = altKey;
+ evt.shiftKey = shiftKey;
+ evt.metaKey = metaKey;
+ evt.keyCode = keyCode;
+ evt.charCode = charCode;
+
+ return evt;
+ }-*/;
+
/**
* Safari 2 does not support {@link ScriptElement#setText(String)}.
*/
@@ -30,6 +48,43 @@
}
@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;
+ }-*/;
+
+ @Override
public native int getAbsoluteLeft(Element elem) /*-{
// Unattached elements and elements (or their ancestors) with style
// 'display: none' have no offsetLeft.
@@ -68,7 +123,7 @@
}
return left;
}-*/;
-
+
@Override
public native int getAbsoluteTop(Element elem) /*-{
// Unattached elements and elements (or their ancestors) with style
diff --git a/user/src/com/google/gwt/dom/client/DOMImplStandard.java b/user/src/com/google/gwt/dom/client/DOMImplStandard.java
index 847b7d3..0536d46 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplStandard.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplStandard.java
@@ -23,6 +23,15 @@
abstract class DOMImplStandard extends DOMImpl {
@Override
+ public native NativeEvent createHtmlEvent(Document doc, String type, boolean canBubble,
+ boolean cancelable) /*-{
+ var evt = doc.createEvent('HTMLEvents');
+ evt.initEvent(type, canBubble, cancelable);
+
+ return evt;
+ }-*/;
+
+ @Override
public native InputElement createInputRadioElement(String name) /*-{
var elem = $doc.createElement("INPUT");
elem.type = 'radio';
@@ -31,7 +40,81 @@
}-*/;
@Override
+ public native NativeEvent createKeyEvent(Document doc, String type, boolean canBubble,
+ boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey,
+ boolean metaKey, int keyCode, int charCode) /*-{
+ // The spec calls for KeyEvents/initKeyEvent(), but that doesn't exist on WebKit.
+ var evt = doc.createEvent('KeyEvents');
+ evt.initKeyEvent(type, canBubble, cancelable, null, ctrlKey, altKey,
+ shiftKey, metaKey, keyCode, charCode);
+
+ return evt;
+ }-*/;
+
+ @Override
+ public native NativeEvent createMouseEvent(Document doc, String type, boolean canBubble,
+ boolean cancelable, int detail, int screenX, int screenY, int clientX,
+ int clientY, boolean ctrlKey, boolean altKey, boolean shiftKey,
+ boolean metaKey, int button, Element relatedTarget) /*-{
+ // Because Event.getButton() returns bitfield values [1, 4, 2] for [left,
+ // middle, right], we need to translate them to the standard [0, 1, 2]
+ // button constants.
+ if (button == 1) {
+ button = 0;
+ } else if (button == 4) {
+ button = 1;
+ } else {
+ button = 2;
+ }
+
+ var evt = doc.createEvent('MouseEvents');
+ evt.initMouseEvent(type, canBubble, cancelable, null, detail, screenX,
+ screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button,
+ relatedTarget);
+
+ return evt;
+ }-*/;
+
+ public native void dispatchEvent(Element target, NativeEvent evt) /*-{
+ target.dispatchEvent(evt);
+ }-*/;
+
+ @Override
+ public native int eventGetButton(NativeEvent evt) /*-{
+ // All modern browsers return 0, 1, and 2 for left, middle, and right,
+ // respectively. Because eventGetButton() is expected to return the IE
+ // bitfield norms of 1, 4, and 2, we translate them here.
+ var button = evt.button;
+ if (button == 1) {
+ return 4;
+ } else if (button == 2) {
+ return 2;
+ }
+ return 1;
+ }-*/;
+
+ @Override
+ public native Element eventGetRelatedTarget(NativeEvent evt) /*-{
+ return evt.relatedTarget;
+ }-*/;
+
+ @Override
+ public native Element eventGetTarget(NativeEvent evt) /*-{
+ return evt.target;
+ }-*/;
+
+ @Override
+ public native void eventPreventDefault(NativeEvent evt) /*-{
+ evt.preventDefault();
+ }-*/;
+
+ @Override
+ public native String eventToString(NativeEvent evt) /*-{
+ return evt.toString();
+ }-*/;
+
+ @Override
public native boolean isOrHasChild(Element parent, Element child) /*-{
- return parent.contains(child);
+ return parent.contains(child);
}-*/;
}
diff --git a/user/src/com/google/gwt/dom/client/Document.java b/user/src/com/google/gwt/dom/client/Document.java
index 3d10a25..b19540e 100644
--- a/user/src/com/google/gwt/dom/client/Document.java
+++ b/user/src/com/google/gwt/dom/client/Document.java
@@ -16,10 +16,9 @@
package com.google.gwt.dom.client;
/**
- * A Document is the root of the HTML hierarchy and holds the entire
- * content. Besides providing access to the hierarchy, it also provides some
- * convenience methods for accessing certain sets of information from the
- * document.
+ * A Document is the root of the HTML hierarchy and holds the entire content.
+ * Besides providing access to the hierarchy, it also provides some convenience
+ * methods for accessing certain sets of information from the document.
*/
public class Document extends Node {
@@ -73,6 +72,13 @@
}
/**
+ * Creates a 'blur' event.
+ */
+ public final NativeEvent createBlurEvent() {
+ return createHtmlEvent("blur", false, false);
+ }
+
+ /**
* Creates a <br> element.
*
* @return the newly created element
@@ -100,6 +106,13 @@
}
/**
+ * Creates a 'change' event.
+ */
+ public final NativeEvent createChangeEvent() {
+ return createHtmlEvent("change", false, true);
+ }
+
+ /**
* Creates an <input type='checkbox'> element.
*
* @return the newly created element
@@ -109,6 +122,35 @@
}
/**
+ * Creates a 'click' event.
+ *
+ * <p>
+ * Note that this method does not allow the event's 'button' field to be
+ * specified, because not all browsers support it reliably for click events.
+ * </p>
+ *
+ * @param detail the event's detail property
+ * @param screenX the event's screen-relative x-position
+ * @param screenY the event's screen-relative y-position
+ * @param clientX the event's client-relative x-position
+ * @param clientY the event's client-relative y-position
+ * @param ctrlKey <code>true</code> if the ctrl key is depressed
+ * @param altKey <code>true</code> if the alt key is depressed
+ * @param shiftKey <code>true</code> if the shift key is depressed
+ * @param metaKey <code>true</code> if the meta key is depressed
+ * @return the event object
+ */
+ public final NativeEvent createClickEvent(int detail, int screenX, int screenY,
+ int clientX, int clientY, boolean ctrlKey, boolean altKey,
+ boolean shiftKey, boolean metaKey) {
+ // We disallow setting the button here, because IE doesn't provide the
+ // button property for click events.
+ return createMouseEvent("click", true, true, detail, screenX, screenY,
+ clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
+ NativeEvent.BUTTON_LEFT, null);
+ }
+
+ /**
* Creates a <col> element.
*
* @return the newly created element
@@ -127,6 +169,52 @@
}
/**
+ * Creates a 'contextmenu' event.
+ *
+ * Note: Contextmenu events will not dispatch properly on Firefox 2 and
+ * earlier.
+ *
+ * @return the event object
+ */
+ public final NativeEvent createContextMenuEvent() {
+ return createHtmlEvent("contextmenu", true, true);
+ }
+
+ /**
+ * Creates a 'dblclick' event.
+ *
+ * <p>
+ * Note that this method does not allow the event's 'button' field to be
+ * specified, because not all browsers support it reliably for click events.
+ * </p>
+ *
+ * <p>
+ * Note that on some browsers, this may cause 'click' events to be synthesized
+ * as well.
+ * </p>
+ *
+ * @param detail the event's detail property
+ * @param screenX the event's screen-relative x-position
+ * @param screenY the event's screen-relative y-position
+ * @param clientX the event's client-relative x-position
+ * @param clientY the event's client-relative y-position
+ * @param ctrlKey <code>true</code> if the ctrl key is depressed
+ * @param altKey <code>true</code> if the alt key is depressed
+ * @param shiftKey <code>true</code> if the shift key is depressed
+ * @param metaKey <code>true</code> if the meta key is depressed
+ * @return the event object
+ */
+ public final NativeEvent createDblClickEvent(int detail, int screenX, int screenY,
+ int clientX, int clientY, boolean ctrlKey, boolean altKey,
+ boolean shiftKey, boolean metaKey) {
+ // We disallow setting the button here, because IE doesn't provide the
+ // button property for click events.
+ return createMouseEvent("dblclick", true, true, detail, screenX, screenY,
+ clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
+ NativeEvent.BUTTON_LEFT, null);
+ }
+
+ /**
* Creates a <del> element.
*
* @return the newly created element
@@ -164,6 +252,15 @@
}
/**
+ * Creates an 'error' event.
+ *
+ * @return the event object
+ */
+ public final NativeEvent createErrorEvent() {
+ return createHtmlEvent("error", false, false);
+ }
+
+ /**
* Creates a <fieldset> element.
*
* @return the newly created element
@@ -182,6 +279,15 @@
}
/**
+ * Creates a 'focus' event.
+ *
+ * @return the event object
+ */
+ public final NativeEvent createFocusEvent() {
+ return createHtmlEvent("focus", false, false);
+ }
+
+ /**
* Creates a <form> element.
*
* @return the newly created element
@@ -247,6 +353,31 @@
}
/**
+ * Creates an event.
+ *
+ * <p>
+ * While this method may be used to create events directly, it is generally
+ * preferable to use existing helper methods such as
+ * {@link #createFocusEvent()}.
+ * </p>
+ *
+ * <p>
+ * Also, note that on Internet Explorer the 'canBubble' and 'cancelable'
+ * arguments will be ignored (the event's behavior is inferred by the browser
+ * based upon its type).
+ * </p>
+ *
+ * @param type the type of event (e.g., "focus", "load", etc)
+ * @param canBubble <code>true</code> if the event should bubble
+ * @param cancelable <code>true</code> if the event should be cancelable
+ * @return the event object
+ */
+ public final NativeEvent createHtmlEvent(String type, boolean canBubble,
+ boolean cancelable) {
+ return DOMImpl.impl.createHtmlEvent(this, type, canBubble, cancelable);
+ }
+
+ /**
* Creates an <iframe> element.
*
* @return the newly created element
@@ -283,6 +414,91 @@
}
/**
+ * Creates a 'keydown' event.
+ *
+ * @param ctrlKey <code>true</code> if the ctrl key is depressed
+ * @param altKey <code>true</code> if the alt key is depressed
+ * @param shiftKey <code>true</code> if the shift key is depressed
+ * @param metaKey <code>true</code> if the meta key is depressed
+ * @param keyCode the key-code to be set on the event
+ * @param charCode the char-code to be set on the event
+ * @return the event object
+ */
+ public final NativeEvent createKeyDownEvent(boolean ctrlKey, boolean altKey,
+ boolean shiftKey, boolean metaKey, int keyCode, int charCode) {
+ return createKeyEvent("keydown", true, true, ctrlKey, altKey, shiftKey,
+ metaKey, keyCode, charCode);
+ }
+
+ /**
+ * Creates a key event.
+ *
+ * <p>
+ * While this method may be used to create events directly, it is generally
+ * preferable to use existing helper methods such as
+ * {@link #createKeyPressEvent(boolean, boolean, boolean, boolean, int, int)}
+ * .
+ * </p>
+ *
+ * <p>
+ * Also, note that on Internet Explorer the 'canBubble' and 'cancelable'
+ * arguments will be ignored (the event's behavior is inferred by the browser
+ * based upon its type).
+ * </p>
+ *
+ * @param type the type of event (e.g., "focus", "load", etc)
+ * @param canBubble <code>true</code> if the event should bubble
+ * @param cancelable <code>true</code> if the event should be cancelable
+ * @param ctrlKey <code>true</code> if the ctrl key is depressed
+ * @param altKey <code>true</code> if the alt key is depressed
+ * @param shiftKey <code>true</code> if the shift key is depressed
+ * @param metaKey <code>true</code> if the meta key is depressed
+ * @param keyCode the key-code to be set on the event
+ * @param charCode the char-code to be set on the event
+ * @return the event object
+ */
+ public final NativeEvent createKeyEvent(String type, boolean canBubble,
+ boolean cancelable, boolean ctrlKey, boolean altKey, boolean shiftKey,
+ boolean metaKey, int keyCode, int charCode) {
+ return DOMImpl.impl.createKeyEvent(this, type, canBubble, cancelable,
+ ctrlKey, altKey, shiftKey, metaKey, keyCode, charCode);
+ }
+
+ /**
+ * Creates a 'keypress' event.
+ *
+ * @param ctrlKey <code>true</code> if the ctrl key is depressed
+ * @param altKey <code>true</code> if the alt key is depressed
+ * @param shiftKey <code>true</code> if the shift key is depressed
+ * @param metaKey <code>true</code> if the meta key is depressed
+ * @param keyCode the key-code to be set on the event
+ * @param charCode the char-code to be set on the event
+ * @return the event object
+ */
+ public final NativeEvent createKeyPressEvent(boolean ctrlKey, boolean altKey,
+ boolean shiftKey, boolean metaKey, int keyCode, int charCode) {
+ return createKeyEvent("keypress", true, true, ctrlKey, altKey, shiftKey,
+ metaKey, keyCode, charCode);
+ }
+
+ /**
+ * Creates a 'keyup' event.
+ *
+ * @param ctrlKey <code>true</code> if the ctrl key is depressed
+ * @param altKey <code>true</code> if the alt key is depressed
+ * @param shiftKey <code>true</code> if the shift key is depressed
+ * @param metaKey <code>true</code> if the meta key is depressed
+ * @param keyCode the key-code to be set on the event
+ * @param charCode the char-code to be set on the event
+ * @return the event object
+ */
+ public final NativeEvent createKeyUpEvent(boolean ctrlKey, boolean altKey,
+ boolean shiftKey, boolean metaKey, int keyCode, int charCode) {
+ return createKeyEvent("keyup", true, true, ctrlKey, altKey, shiftKey,
+ metaKey, keyCode, charCode);
+ }
+
+ /**
* Creates a <label> element.
*
* @return the newly created element
@@ -319,6 +535,15 @@
}
/**
+ * Creates a 'load' event.
+ *
+ * @return the event object
+ */
+ public final NativeEvent createLoadEvent() {
+ return createHtmlEvent("load", false, false);
+ }
+
+ /**
* Creates a <map> element.
*
* @return the newly created element
@@ -337,6 +562,174 @@
}
/**
+ * Creates a 'mousedown' event.
+ *
+ * @param detail the event's detail property
+ * @param screenX the event's screen-relative x-position
+ * @param screenY the event's screen-relative y-position
+ * @param clientX the event's client-relative x-position
+ * @param clientY the event's client-relative y-position
+ * @param ctrlKey <code>true</code> if the ctrl key is depressed
+ * @param altKey <code>true</code> if the alt key is depressed
+ * @param shiftKey <code>true</code> if the shift key is depressed
+ * @param metaKey <code>true</code> if the meta key is depressed
+ * @param button the event's button property (values from
+ * {@link Event#BUTTON_LEFT} et al)
+ * @return the event object
+ */
+ public final NativeEvent createMouseDownEvent(int detail, int screenX, int screenY,
+ int clientX, int clientY, boolean ctrlKey, boolean altKey,
+ boolean shiftKey, boolean metaKey, int button) {
+ return createMouseEvent("mousedown", true, true, detail, screenX, screenY,
+ clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, null);
+ }
+
+ /**
+ * Creates an mouse event.
+ *
+ * <p>
+ * While this method may be used to create events directly, it is generally
+ * preferable to use existing helper methods such as
+ * {@link #createClickEvent(int, int, int, int, int, boolean, boolean, boolean, boolean)}
+ * .
+ * </p>
+ *
+ * <p>
+ * Also, note that on Internet Explorer the 'canBubble' and 'cancelable'
+ * arguments will be ignored (the event's behavior is inferred by the browser
+ * based upon its type).
+ * </p>
+ *
+ * @param type the type of event (e.g., "focus", "load", etc)
+ * @param canBubble <code>true</code> if the event should bubble
+ * @param cancelable <code>true</code> if the event should be cancelable
+ * @param detail the event's detail property
+ * @param screenX the event's screen-relative x-position
+ * @param screenY the event's screen-relative y-position
+ * @param clientX the event's client-relative x-position
+ * @param clientY the event's client-relative y-position
+ * @param ctrlKey <code>true</code> if the ctrl key is depressed
+ * @param altKey <code>true</code> if the alt key is depressed
+ * @param shiftKey <code>true</code> if the shift key is depressed
+ * @param metaKey <code>true</code> if the meta key is depressed
+ * @param button the event's button property (values from
+ * {@link Event#BUTTON_LEFT} et al)
+ * @param relatedTarget the event's related target (only relevant for
+ * mouseover and mouseout events)
+ * @return the event object
+ */
+ public final NativeEvent createMouseEvent(String type, boolean canBubble,
+ boolean cancelable, int detail, int screenX, int screenY, int clientX,
+ int clientY, boolean ctrlKey, boolean altKey, boolean shiftKey,
+ boolean metaKey, int button, Element relatedTarget) {
+ return DOMImpl.impl.createMouseEvent(this, type, canBubble, cancelable,
+ detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey,
+ metaKey, button, relatedTarget);
+ }
+
+ /**
+ * Creates a 'mousemove' event.
+ *
+ * @param detail the event's detail property
+ * @param screenX the event's screen-relative x-position
+ * @param screenY the event's screen-relative y-position
+ * @param clientX the event's client-relative x-position
+ * @param clientY the event's client-relative y-position
+ * @param ctrlKey <code>true</code> if the ctrl key is depressed
+ * @param altKey <code>true</code> if the alt key is depressed
+ * @param shiftKey <code>true</code> if the shift key is depressed
+ * @param metaKey <code>true</code> if the meta key is depressed
+ * @param button the event's button property (values from
+ * {@link Event#BUTTON_LEFT} et al)
+ * @return the event object
+ */
+ public final NativeEvent createMouseMoveEvent(int detail, int screenX, int screenY,
+ int clientX, int clientY, boolean ctrlKey, boolean altKey,
+ boolean shiftKey, boolean metaKey, int button) {
+ return createMouseEvent("mousemove", true, true, detail, screenX, screenY,
+ clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, null);
+ }
+
+ /**
+ * Creates a 'mouseout' event.
+ *
+ * Note: The 'relatedTarget' parameter will be ignored on Firefox 2 and
+ * earlier.
+ *
+ * @param detail the event's detail property
+ * @param screenX the event's screen-relative x-position
+ * @param screenY the event's screen-relative y-position
+ * @param clientX the event's client-relative x-position
+ * @param clientY the event's client-relative y-position
+ * @param ctrlKey <code>true</code> if the ctrl key is depressed
+ * @param altKey <code>true</code> if the alt key is depressed
+ * @param shiftKey <code>true</code> if the shift key is depressed
+ * @param metaKey <code>true</code> if the meta key is depressed
+ * @param button the event's button property (values from
+ * {@link Event#BUTTON_LEFT} et al)
+ * @param relatedTarget the event's related target
+ * @return the event object
+ */
+ public final NativeEvent createMouseOutEvent(int detail, int screenX, int screenY,
+ int clientX, int clientY, boolean ctrlKey, boolean altKey,
+ boolean shiftKey, boolean metaKey, int button, Element relatedTarget) {
+ return createMouseEvent("mouseout", true, true, detail, screenX, screenY,
+ clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button,
+ relatedTarget);
+ }
+
+ /**
+ * Creates a 'mouseover' event.
+ *
+ * Note: The 'relatedTarget' parameter will be ignored on Firefox 2 and
+ * earlier.
+ *
+ * @param detail the event's detail property
+ * @param screenX the event's screen-relative x-position
+ * @param screenY the event's screen-relative y-position
+ * @param clientX the event's client-relative x-position
+ * @param clientY the event's client-relative y-position
+ * @param ctrlKey <code>true</code> if the ctrl key is depressed
+ * @param altKey <code>true</code> if the alt key is depressed
+ * @param shiftKey <code>true</code> if the shift key is depressed
+ * @param metaKey <code>true</code> if the meta key is depressed
+ * @param button the event's button property (values from
+ * {@link Event#BUTTON_LEFT} et al)
+ * @param relatedTarget the event's related target
+ * @return the event object
+ */
+ public final NativeEvent createMouseOverEvent(int detail, int screenX, int screenY,
+ int clientX, int clientY, boolean ctrlKey, boolean altKey,
+ boolean shiftKey, boolean metaKey, int button, Element relatedTarget) {
+ return createMouseEvent("mouseover", true, true, detail, screenX, screenY,
+ clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button,
+ relatedTarget);
+ }
+
+ /**
+ * Creates a 'mouseup' event.
+ *
+ * @param detail the event's detail property
+ * @param screenX the event's screen-relative x-position
+ * @param screenY the event's screen-relative y-position
+ * @param clientX the event's client-relative x-position
+ * @param clientY the event's client-relative y-position
+ * @param ctrlKey <code>true</code> if the ctrl key is depressed
+ * @param altKey <code>true</code> if the alt key is depressed
+ * @param shiftKey <code>true</code> if the shift key is depressed
+ * @param metaKey <code>true</code> if the meta key is depressed
+ * @param button the event's button property (values from
+ * {@link Event#BUTTON_LEFT} et al)
+ * @return the event object
+ */
+ public final NativeEvent createMouseUpEvent(int detail, int screenX, int screenY,
+ int clientX, int clientY, boolean ctrlKey, boolean altKey,
+ boolean shiftKey, boolean metaKey, int button) {
+ return createMouseEvent("mouseup", true, true, detail, screenX, screenY,
+ clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, null);
+ }
+
+ /**
* Creates a <object> element.
*
* @return the newly created element
@@ -447,6 +840,18 @@
}
/**
+ * Creates a 'scroll' event.
+ *
+ * Note: Contextmenu events will not dispatch properly on Firefox 2 and
+ * earlier.
+ *
+ * @return the event object
+ */
+ public final NativeEvent createScrollEvent() {
+ return createHtmlEvent("scroll", false, false);
+ }
+
+ /**
* Creates a <select> element.
*
* @return the newly created element
@@ -628,6 +1033,7 @@
* For example, to position an element directly under the mouse cursor
* (assuming you are handling a mouse event), do the following:
* </p>
+ *
* <pre>
* Event event;
* Document doc;
@@ -743,8 +1149,8 @@
* that the two documents may have different DTDs in the XML case.
*
* @param node the node to import
- * @param deep If <code>true</code>, recursively import the subtree under
- * the specified node; if <code>false</code>, import only the node
+ * @param deep If <code>true</code>, recursively import the subtree under the
+ * specified node; if <code>false</code>, import only the node
* itself, as explained above
*/
public final native void importNode(Node node, boolean deep) /*-{
diff --git a/user/src/com/google/gwt/dom/client/Element.java b/user/src/com/google/gwt/dom/client/Element.java
index 54abf0b..0559099 100644
--- a/user/src/com/google/gwt/dom/client/Element.java
+++ b/user/src/com/google/gwt/dom/client/Element.java
@@ -33,6 +33,22 @@
}
/**
+ * Dispatched the given event with this element as its target. The event will
+ * go through all phases of the browser's normal event dispatch mechanism.
+ *
+ * Note: Because the browser's normal dispatch mechanism is used, exceptions
+ * thrown from within handlers triggered by this method cannot be caught by
+ * wrapping this method in a try/catch block. Such exceptions will be caught
+ * by the {@link GWT#setUncaughtExceptionHandler() uncaught exception handler}
+ * as usual.
+ *
+ * @param evt the event to be dispatched
+ */
+ public final void dispatchEvent(NativeEvent evt) {
+ DOMImpl.impl.dispatchEvent(this, evt);
+ }
+
+ /**
* Gets an element's absolute left coordinate in the document's coordinate
* system.
*/
diff --git a/user/src/com/google/gwt/dom/client/NativeEvent.java b/user/src/com/google/gwt/dom/client/NativeEvent.java
new file mode 100644
index 0000000..8109652
--- /dev/null
+++ b/user/src/com/google/gwt/dom/client/NativeEvent.java
@@ -0,0 +1,215 @@
+/*
+ * 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.dom.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+/**
+ * The native dom event.
+ */
+public class NativeEvent extends JavaScriptObject {
+
+ /**
+ * The left mouse button.
+ */
+ public static final int BUTTON_LEFT = 1;
+
+ /**
+ * The middle mouse button.
+ */
+ public static final int BUTTON_MIDDLE = 4;
+
+ /**
+ * The right mouse button.
+ */
+ public static final int BUTTON_RIGHT = 2;
+
+ /**
+ * Required constructor for GWT compiler to function.
+ */
+ protected NativeEvent() {
+ }
+
+ /**
+ * Gets whether the ALT key was depressed when the given event occurred.
+ *
+ * @return <code>true</code> if ALT was depressed when the event occurred
+ */
+ public final boolean getAltKey() {
+ return DOMImpl.impl.eventGetAltKey(this);
+ }
+
+ /**
+ * Gets the mouse buttons that were depressed when the given event occurred.
+ *
+ * @return a bit-field, defined by {@link NativeEvent#BUTTON_LEFT},
+ * {@link NativeEvent#BUTTON_MIDDLE}, and
+ * {@link NativeEvent#BUTTON_RIGHT}
+ */
+ public final int getButton() {
+ return DOMImpl.impl.eventGetButton(this);
+ }
+
+ /**
+ * Gets the mouse x-position within the browser window's client area.
+ *
+ * @return the mouse x-position
+ */
+ public final int getClientX() {
+ return DOMImpl.impl.eventGetClientX(this);
+ }
+
+ /**
+ * Gets the mouse y-position within the browser window's client area.
+ *
+ * @return the mouse y-position
+ */
+ public final int getClientY() {
+ return DOMImpl.impl.eventGetClientY(this);
+ }
+
+ /**
+ * Gets whether the CTRL key was depressed when the given event occurred.
+ *
+ * @return <code>true</code> if CTRL was depressed when the event occurred
+ */
+ public final boolean getCtrlKey() {
+ return DOMImpl.impl.eventGetCtrlKey(this);
+ }
+
+ /**
+ * Gets the key code associated with this event.
+ *
+ * <p>
+ * For key press events, this method returns the Unicode value of the
+ * character generated. For key down and key up events, it returns the code
+ * associated with the physical key.
+ * </p>
+ *
+ * @return the Unicode character or key code.
+ * @see com.google.gwt.event.dom.client.KeyCodes
+ */
+ public final int getKeyCode() {
+ return DOMImpl.impl.eventGetKeyCode(this);
+ }
+
+ /**
+ * Gets whether the META key was depressed when the given event occurred.
+ *
+ * @return <code>true</code> if META was depressed when the event occurred
+ */
+ public final boolean getMetaKey() {
+ return DOMImpl.impl.eventGetMetaKey(this);
+ }
+
+ /**
+ * Gets the velocity of the mouse wheel associated with the event along the Y
+ * axis.
+ * <p>
+ * The velocity of the event is an artifical measurement for relative
+ * comparisons of wheel activity. It is affected by some non-browser factors,
+ * including choice of input hardware and mouse acceleration settings. The
+ * sign of the velocity measurement agrees with the screen coordinate system;
+ * negative values are towards the origin and positive values are away from
+ * the origin. Standard scrolling speed is approximately ten units per event.
+ * </p>
+ *
+ * @return The velocity of the mouse wheel.
+ */
+ public final int getMouseWheelVelocityY() {
+ return DOMImpl.impl.eventGetMouseWheelVelocityY(this);
+ }
+
+ /**
+ * Gets the related target for this event.
+ *
+ * @return the related target
+ */
+ public final Element getRelatedTarget() {
+ return DOMImpl.impl.eventGetRelatedTarget(this);
+ }
+
+ /**
+ * Gets the mouse x-position on the user's display.
+ *
+ * @return the mouse x-position
+ */
+ public final int getScreenX() {
+ return DOMImpl.impl.eventGetScreenX(this);
+ }
+
+ /**
+ * Gets the mouse y-position on the user's display.
+ *
+ * @return the mouse y-position
+ */
+ public final int getScreenY() {
+ return DOMImpl.impl.eventGetScreenY(this);
+ }
+
+ /**
+ * Gets whether the shift key was depressed when the given event occurred.
+ *
+ * @return <code>true</code> if shift was depressed when the event occurred
+ */
+ public final boolean getShiftKey() {
+ return DOMImpl.impl.eventGetShiftKey(this);
+ }
+
+ /**
+ * Gets a string representation of this event.
+ *
+ * We do not override {@link #toString()} because it is final in
+ * {@link com.google.gwt.core.client.JavaScriptObject }.
+ *
+ * @return the string representation of this event
+ */
+ public final String getString() {
+ return DOMImpl.impl.eventToString(this);
+ }
+
+ /**
+ * Returns the element that was the actual target of the given event.
+ *
+ * @return the target element
+ */
+ public final Element getTarget() {
+ return DOMImpl.impl.eventGetTarget(this);
+ }
+
+ /**
+ * Gets the enumerated type of this event.
+ *
+ * @return the event's enumerated type
+ */
+ public final String getType() {
+ return DOMImpl.impl.eventGetType(this);
+ }
+
+ /**
+ * Prevents the browser from taking its default action for the given event.
+ */
+ public final void preventDefault() {
+ DOMImpl.impl.eventPreventDefault(this);
+ }
+
+ /**
+ * Stops the event from being propagated to parent elements.
+ */
+ public final void stopPropagation() {
+ DOMImpl.impl.eventStopPropagation(this);
+ }
+}
diff --git a/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml b/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml
index c5434ae..1e761c5 100644
--- a/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml
+++ b/user/src/com/google/gwt/event/dom/DomEvent.gwt.xml
@@ -1,6 +1,5 @@
<module>
<inherits name="com.google.gwt.event.EventBase" />
- <inherits name="com.google.gwt.user.DOM" />
-
+ <inherits name="com.google.gwt.dom.DOM" />
<source path="client"/>
</module>
diff --git a/user/src/com/google/gwt/event/dom/client/BlurEvent.java b/user/src/com/google/gwt/event/dom/client/BlurEvent.java
index acbd82c..db0d326 100644
--- a/user/src/com/google/gwt/event/dom/client/BlurEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/BlurEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native blur event.
*/
@@ -26,8 +24,8 @@
* Event type for blur events. Represents the meta-data associated with this
* event.
*/
- private static final Type<BlurHandler> TYPE = new Type<BlurHandler>(
- Event.ONBLUR, "blur", new BlurEvent());
+ private static final Type<BlurHandler> TYPE = new Type<BlurHandler>("blur",
+ new BlurEvent());
/**
* Gets the event type associated with blur events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire blur events.
*/
protected BlurEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/ChangeEvent.java b/user/src/com/google/gwt/event/dom/client/ChangeEvent.java
index f66f3cd..7a2ec49 100644
--- a/user/src/com/google/gwt/event/dom/client/ChangeEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/ChangeEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native change event.
*/
@@ -27,7 +25,7 @@
* event.
*/
private static final Type<ChangeHandler> TYPE = new Type<ChangeHandler>(
- Event.ONCHANGE, "change", new ChangeEvent());
+ "change", new ChangeEvent());
/**
* Gets the event type associated with change events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire change events.
*/
protected ChangeEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/ClickEvent.java b/user/src/com/google/gwt/event/dom/client/ClickEvent.java
index 805c956..74fc74e 100644
--- a/user/src/com/google/gwt/event/dom/client/ClickEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/ClickEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native click event.
*/
@@ -27,7 +25,7 @@
* event.
*/
private static final Type<ClickHandler> TYPE = new Type<ClickHandler>(
- Event.ONCLICK, "click", new ClickEvent());
+ "click", new ClickEvent());
/**
* Gets the event type associated with click events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire click events.
*/
protected ClickEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/ContextMenuEvent.java b/user/src/com/google/gwt/event/dom/client/ContextMenuEvent.java
index 513fd2b..ff801d3 100644
--- a/user/src/com/google/gwt/event/dom/client/ContextMenuEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/ContextMenuEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native context menu event.
*/
@@ -27,7 +25,7 @@
* with this event.
*/
private static final Type<ContextMenuHandler> TYPE = new Type<ContextMenuHandler>(
- Event.ONCONTEXTMENU, "contextmenu", new ContextMenuEvent());
+ "contextmenu", new ContextMenuEvent());
/**
* Gets the event type associated with context menu events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire context menu events.
*/
protected ContextMenuEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/DomEvent.java b/user/src/com/google/gwt/event/dom/client/DomEvent.java
index c4ff6f4..bf279db 100644
--- a/user/src/com/google/gwt/event/dom/client/DomEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/DomEvent.java
@@ -15,14 +15,13 @@
*/
package com.google.gwt.event.dom.client;
+import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HasHandlers;
-import com.google.gwt.user.client.Event;
/**
* {@link DomEvent} is a subclass of {@link GwtEvent} that provides events that
- * map to DOM Level 2 Events. It provides an additional method to access the
* underlying native browser event object as well as a subclass of {@link Type}
* that understands GWT event bits used by sinkEvents().
*
@@ -39,38 +38,25 @@
* @param <H> handler type
*/
public static class Type<H extends EventHandler> extends GwtEvent.Type<H> {
- private final int eventToSink;
private DomEvent<H> flyweight;
-
- /**
- * Constructor.
- *
- * @param eventToSink the native event type to sink
- *
- */
- public Type(int eventToSink) {
- this.eventToSink = eventToSink;
- }
+ private String name;
/**
* This constructor allows dom event types to be triggered by the
- * {@link DomEvent#fireNativeEvent(Event, HasHandlers)} method. It should
- * only be used by implementors supporting new dom events.
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, HasHandlers)}
+ * method. It should only be used by implementors supporting new dom events.
+ *
* <p>
* Any such dom event type must act as a flyweight around a native event
* object.
* </p>
*
- *
- * @param eventToSink the integer value used by sink events to set up event
- * handling for this dom type
* @param eventName the raw native event name
* @param flyweight the instance that will be used as a flyweight to wrap a
* native event
*/
- protected Type(int eventToSink, String eventName, DomEvent<H> flyweight) {
+ public Type(String eventName, DomEvent<H> flyweight) {
this.flyweight = flyweight;
- this.eventToSink = eventToSink;
// Until we have eager clinits implemented, we are manually initializing
// DomEvent here.
@@ -78,26 +64,16 @@
init();
}
registered.unsafePut(eventName, this);
- }
-
- Type(int nativeEventTypeInt, String eventName, DomEvent<H> cached,
- String... auxNames) {
- this(nativeEventTypeInt, eventName, cached);
- for (int i = 0; i < auxNames.length; i++) {
- registered.unsafePut(auxNames[i], this);
- }
+ name = eventName;
}
/**
- * Gets the integer defined by the native {@link Event} type needed to hook
- * up event handling when the user calls
- * {@link com.google.gwt.user.client.DOM#sinkEvents(com.google.gwt.user.client.Element, int)}
- * .
+ * Gets the name associated with this event type.
*
- * @return the native event type
+ * @return the name of this event typ
*/
- public int getEventToSink() {
- return eventToSink;
+ public String getName() {
+ return name;
}
}
@@ -107,19 +83,19 @@
* Fires the given native event on the specified handlers.
*
* @param nativeEvent the native event
- * @param handlers the event manager containing the handlers to fire (may be
- * null)
+ * @param handlerSource the source of the handlers to fire
*/
- public static void fireNativeEvent(Event nativeEvent, HasHandlers handlers) {
+ public static void fireNativeEvent(NativeEvent nativeEvent,
+ HasHandlers handlerSource) {
assert nativeEvent != null : "nativeEvent must not be null";
- if (registered != null && handlers != null) {
+ if (registered != null) {
final DomEvent.Type<?> typeKey = registered.unsafeGet(nativeEvent.getType());
if (typeKey != null) {
// Store and restore native event just in case we are in recursive
// loop.
- Event currentNative = typeKey.flyweight.nativeEvent;
+ NativeEvent currentNative = typeKey.flyweight.nativeEvent;
typeKey.flyweight.setNativeEvent(nativeEvent);
- handlers.fireEvent(typeKey.flyweight);
+ handlerSource.fireEvent(typeKey.flyweight);
typeKey.flyweight.setNativeEvent(currentNative);
}
}
@@ -130,12 +106,12 @@
registered = new PrivateMap<Type<?>>();
}
- private Event nativeEvent;
+ private NativeEvent nativeEvent;
@Override
public abstract DomEvent.Type<H> getAssociatedType();
- public final Event getNativeEvent() {
+ public final NativeEvent getNativeEvent() {
assertLive();
return nativeEvent;
}
@@ -154,7 +130,7 @@
*
* @param nativeEvent the native event
*/
- public final void setNativeEvent(Event nativeEvent) {
+ public final void setNativeEvent(NativeEvent nativeEvent) {
this.nativeEvent = nativeEvent;
}
@@ -163,6 +139,6 @@
*/
public void stopPropagation() {
assertLive();
- nativeEvent.cancelBubble(true);
+ nativeEvent.stopPropagation();
}
}
diff --git a/user/src/com/google/gwt/event/dom/client/DoubleClickEvent.java b/user/src/com/google/gwt/event/dom/client/DoubleClickEvent.java
index 972b645..20cdf8e 100644
--- a/user/src/com/google/gwt/event/dom/client/DoubleClickEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/DoubleClickEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native double click event.
*/
@@ -27,7 +25,7 @@
* with this event.
*/
private static final Type<DoubleClickHandler> TYPE = new Type<DoubleClickHandler>(
- Event.ONDBLCLICK, "dblclick", new DoubleClickEvent());
+ "dblclick", new DoubleClickEvent());
/**
* Gets the event type associated with double click events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire double click events.
*/
protected DoubleClickEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/ErrorEvent.java b/user/src/com/google/gwt/event/dom/client/ErrorEvent.java
index 0c9a007..40a3771 100644
--- a/user/src/com/google/gwt/event/dom/client/ErrorEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/ErrorEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native error event.
*/
@@ -27,7 +25,7 @@
* event.
*/
private static final Type<ErrorHandler> TYPE = new Type<ErrorHandler>(
- Event.ONERROR, "error", new ErrorEvent());
+ "error", new ErrorEvent());
/**
* Gets the event type associated with error events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire error events.
*/
protected ErrorEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/FocusEvent.java b/user/src/com/google/gwt/event/dom/client/FocusEvent.java
index c2ca7bd..16df375 100644
--- a/user/src/com/google/gwt/event/dom/client/FocusEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/FocusEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native focus event.
*/
@@ -27,7 +25,7 @@
* event.
*/
private static final Type<FocusHandler> TYPE = new Type<FocusHandler>(
- Event.ONFOCUS, "focus", new FocusEvent());
+ "focus", new FocusEvent());
/**
* Gets the event type associated with focus events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire focus events.
*/
protected FocusEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/HasNativeEvent.java b/user/src/com/google/gwt/event/dom/client/HasNativeEvent.java
index 510c273..88aaf36 100644
--- a/user/src/com/google/gwt/event/dom/client/HasNativeEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/HasNativeEvent.java
@@ -16,7 +16,7 @@
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
+import com.google.gwt.dom.client.NativeEvent;
/**
* An object that implements this interface has a native event associated with
@@ -28,5 +28,5 @@
*
* @return the native event
*/
- Event getNativeEvent();
+ NativeEvent getNativeEvent();
}
diff --git a/user/src/com/google/gwt/event/dom/client/KeyDownEvent.java b/user/src/com/google/gwt/event/dom/client/KeyDownEvent.java
index 1b58b03..d1175a2 100644
--- a/user/src/com/google/gwt/event/dom/client/KeyDownEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/KeyDownEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native key down event.
*/
@@ -27,7 +25,7 @@
* this event.
*/
private static final Type<KeyDownHandler> TYPE = new Type<KeyDownHandler>(
- Event.ONKEYDOWN, "keydown", new KeyDownEvent());
+ "keydown", new KeyDownEvent());
/**
* Gets the event type associated with key down events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire key down events.
*/
protected KeyDownEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/KeyEvent.java b/user/src/com/google/gwt/event/dom/client/KeyEvent.java
index c6367e2..535995f 100644
--- a/user/src/com/google/gwt/event/dom/client/KeyEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/KeyEvent.java
@@ -47,15 +47,6 @@
}
/**
- * Gets the key-repeat state of this event.
- *
- * @return <code>true</code> if this key event was an auto-repeat
- */
- public boolean isAutoRepeat() {
- return getNativeEvent().getRepeat();
- }
-
- /**
* Is the <code>control</code> key down?
*
* @return whether the control key is down
diff --git a/user/src/com/google/gwt/event/dom/client/KeyPressEvent.java b/user/src/com/google/gwt/event/dom/client/KeyPressEvent.java
index f955e3c..496aa6c 100644
--- a/user/src/com/google/gwt/event/dom/client/KeyPressEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/KeyPressEvent.java
@@ -15,7 +15,7 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
+import com.google.gwt.dom.client.NativeEvent;
/**
* Represents a native key press event.
@@ -27,7 +27,7 @@
* this event.
*/
private static final Type<KeyPressHandler> TYPE = new Type<KeyPressHandler>(
- Event.ONKEYPRESS, "keypress", new KeyPressEvent());
+ "keypress", new KeyPressEvent());
/**
* Gets the event type associated with key press events.
@@ -40,7 +40,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire key press events.
*/
protected KeyPressEvent() {
@@ -70,8 +70,8 @@
handler.onKeyPress(this);
}
- private native char getCharCode(Event e)/*-{
- return e.charCode || e.keyCode;
- }-*/;
+ private native char getCharCode(NativeEvent e)/*-{
+ return e.charCode || e.keyCode;
+ }-*/;
}
diff --git a/user/src/com/google/gwt/event/dom/client/KeyUpEvent.java b/user/src/com/google/gwt/event/dom/client/KeyUpEvent.java
index 5a07977..f728468 100644
--- a/user/src/com/google/gwt/event/dom/client/KeyUpEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/KeyUpEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native key up event.
*/
@@ -27,7 +25,7 @@
* event.
*/
private static final Type<KeyUpHandler> TYPE = new Type<KeyUpHandler>(
- Event.ONKEYUP, "keyup", new KeyUpEvent());
+ "keyup", new KeyUpEvent());
/**
* Gets the event type associated with key up events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire key up events.
*/
protected KeyUpEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/LoadEvent.java b/user/src/com/google/gwt/event/dom/client/LoadEvent.java
index 3255c4b..00397fb 100644
--- a/user/src/com/google/gwt/event/dom/client/LoadEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/LoadEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native load event.
*/
@@ -26,8 +24,8 @@
* Event type for load events. Represents the meta-data associated with this
* event.
*/
- private static final Type<LoadHandler> TYPE = new Type<LoadHandler>(
- Event.ONLOAD, "load", new LoadEvent());
+ private static final Type<LoadHandler> TYPE = new Type<LoadHandler>("load",
+ new LoadEvent());
/**
* Gets the event type associated with load events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire load events.
*/
protected LoadEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/LoseCaptureEvent.java b/user/src/com/google/gwt/event/dom/client/LoseCaptureEvent.java
index 857e8d0..eef6843 100644
--- a/user/src/com/google/gwt/event/dom/client/LoseCaptureEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/LoseCaptureEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native lose capture event.
*/
@@ -27,7 +25,7 @@
* with this event.
*/
private static final Type<LoseCaptureHandler> TYPE = new Type<LoseCaptureHandler>(
- Event.ONLOSECAPTURE, "losecapture", new LoseCaptureEvent());
+ "losecapture", new LoseCaptureEvent());
/**
* Gets the event type associated with lose capture events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire lose capture events.
*/
protected LoseCaptureEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/MouseDownEvent.java b/user/src/com/google/gwt/event/dom/client/MouseDownEvent.java
index dd36ec2..5dcfff6 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseDownEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseDownEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native mouse down event.
*/
@@ -27,7 +25,7 @@
* this event.
*/
private static final Type<MouseDownHandler> TYPE = new Type<MouseDownHandler>(
- Event.ONMOUSEDOWN, "mousedown", new MouseDownEvent());
+ "mousedown", new MouseDownEvent());
/**
* Gets the event type associated with mouse down events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire mouse down events.
*/
protected MouseDownEvent() {
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 424b138..1357261 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseEvent.java
@@ -15,10 +15,7 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.dom.client.Element;
import com.google.gwt.event.shared.EventHandler;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.Window;
/**
* Abstract class representing mouse events.
@@ -28,30 +25,6 @@
*/
public abstract class MouseEvent<H extends EventHandler> extends DomEvent<H> {
/**
- * Gets the x coordinate relative to the given element.
- *
- * @param nativeEvent the native event
- * @param relativeTo the relative element
- * @return the relative x
- */
- public static int getRelativeX(Event nativeEvent, Element relativeTo) {
- return nativeEvent.getClientX() - relativeTo.getAbsoluteLeft()
- + relativeTo.getScrollLeft() + Window.getScrollLeft();
- }
-
- /**
- * Gets the y coordinate relative to the given element.
- *
- * @param nativeEvent the native event
- * @param relativeTo the relative element
- * @return the relative y
- */
- public static int getRelativeY(Event nativeEvent, Element relativeTo) {
- return nativeEvent.getClientY() - relativeTo.getAbsoluteTop()
- + relativeTo.getScrollTop() + Window.getScrollTop();
- }
-
- /**
* Gets the mouse x-position within the browser window's client area.
*
* @return the mouse x-position
@@ -70,8 +43,10 @@
}
/**
- * Gets the button value. Compare it to {@link Event#BUTTON_LEFT},
- * {@link Event#BUTTON_RIGHT}, {@link Event#BUTTON_MIDDLE}
+ * Gets the button value. Compare it to
+ * {@link com.google.gwt.dom.client.NativeEvent#BUTTON_LEFT},
+ * {@link com.google.gwt.dom.client.NativeEvent#BUTTON_RIGHT},
+ * {@link com.google.gwt.dom.client.NativeEvent#BUTTON_MIDDLE}
*
* @return the button value
*/
@@ -80,27 +55,6 @@
}
/**
- * Gets the x coordinate relative to the given element.
- *
- * @param relativeTo the relative element
- * @return the relative x
- */
- public int getRelativeX(Element relativeTo) {
- return getRelativeX(getNativeEvent(), relativeTo);
- }
-
- /**
- * Gets the y coordinate relative to the given element.
- *
- *
- * @param relativeTo the relative element
- * @return the relative y
- */
- public int getRelativeY(Element relativeTo) {
- return getRelativeY(getNativeEvent(), relativeTo);
- }
-
- /**
* Gets the mouse x-position on the user's display.
*
* @return the mouse x-position
diff --git a/user/src/com/google/gwt/event/dom/client/MouseMoveEvent.java b/user/src/com/google/gwt/event/dom/client/MouseMoveEvent.java
index cafa24c..cefd26c 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseMoveEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseMoveEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native mouse move event.
*/
@@ -27,7 +25,7 @@
* this event.
*/
private static final Type<MouseMoveHandler> TYPE = new Type<MouseMoveHandler>(
- Event.ONMOUSEMOVE, "mousemove", new MouseMoveEvent());
+ "mousemove", new MouseMoveEvent());
/**
* Gets the event type associated with mouse move events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire mouse move events.
*/
protected MouseMoveEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/MouseOutEvent.java b/user/src/com/google/gwt/event/dom/client/MouseOutEvent.java
index 7b1d47e..9b89c91 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseOutEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseOutEvent.java
@@ -16,7 +16,6 @@
package com.google.gwt.event.dom.client;
import com.google.gwt.dom.client.Element;
-import com.google.gwt.user.client.Event;
/**
* Represents a native mouse out event.
@@ -28,7 +27,7 @@
* this event.
*/
private static final Type<MouseOutHandler> TYPE = new Type<MouseOutHandler>(
- Event.ONMOUSEOUT, "mouseout", new MouseOutEvent());
+ "mouseout", new MouseOutEvent());
/**
* Gets the event type associated with mouse out events.
@@ -41,7 +40,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire mouse out events.
*/
protected MouseOutEvent() {
@@ -58,8 +57,7 @@
* @return the element from which the mouse pointer was moved
*/
public Element getFromElement() {
- // Use a deferred binding instead of DOMImpl's inefficient switch statement
- return getNativeEvent().getFromElement();
+ return getNativeEvent().getTarget();
}
/**
@@ -69,7 +67,7 @@
*/
public Element getToElement() {
// Use a deferred binding instead of DOMImpl's inefficient switch statement
- return getNativeEvent().getToElement();
+ return getNativeEvent().getRelatedTarget();
}
@Override
diff --git a/user/src/com/google/gwt/event/dom/client/MouseOverEvent.java b/user/src/com/google/gwt/event/dom/client/MouseOverEvent.java
index 90a664c..3306151 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseOverEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseOverEvent.java
@@ -16,7 +16,6 @@
package com.google.gwt.event.dom.client;
import com.google.gwt.dom.client.Element;
-import com.google.gwt.user.client.Event;
/**
* Represents a native mouse over event.
@@ -28,7 +27,7 @@
* this event.
*/
private static final Type<MouseOverHandler> TYPE = new Type<MouseOverHandler>(
- Event.ONMOUSEOVER, "mouseover", new MouseOverEvent());
+ "mouseover", new MouseOverEvent());
/**
* Gets the event type associated with mouse over events.
@@ -41,7 +40,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire mouse over events.
*/
protected MouseOverEvent() {
@@ -58,8 +57,7 @@
* @return the element from which the mouse pointer was moved
*/
public Element getFromElement() {
- // Use a deferred binding instead of DOMImpl's inefficient switch statement
- return getNativeEvent().getFromElement();
+ return getNativeEvent().getRelatedTarget();
}
/**
@@ -68,8 +66,7 @@
* @return the element to which the mouse pointer was moved
*/
public Element getToElement() {
- // Use a deferred binding instead of DOMImpl's inefficient switch statement
- return getNativeEvent().getToElement();
+ return getNativeEvent().getTarget();
}
@Override
diff --git a/user/src/com/google/gwt/event/dom/client/MouseUpEvent.java b/user/src/com/google/gwt/event/dom/client/MouseUpEvent.java
index 9817f07..a098ff0 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseUpEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseUpEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native mouse up event.
*/
@@ -27,7 +25,7 @@
* this event.
*/
private static final Type<MouseUpHandler> TYPE = new Type<MouseUpHandler>(
- Event.ONMOUSEUP, "mouseup", new MouseUpEvent());
+ "mouseup", new MouseUpEvent());
/**
* Gets the event type associated with mouse up events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire mouse up events.
*/
protected MouseUpEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/MouseWheelEvent.java b/user/src/com/google/gwt/event/dom/client/MouseWheelEvent.java
index d8fed04..8120a1b 100644
--- a/user/src/com/google/gwt/event/dom/client/MouseWheelEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/MouseWheelEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native mouse wheel event.
*/
@@ -27,7 +25,7 @@
* this event.
*/
private static final Type<MouseWheelHandler> TYPE = new Type<MouseWheelHandler>(
- Event.ONMOUSEWHEEL, "mousewheel", new MouseWheelEvent(), "DOMMouseScroll");
+ "mousewheel", new MouseWheelEvent());
/**
* Gets the event type associated with mouse wheel events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire mouse wheel events.
*/
protected MouseWheelEvent() {
diff --git a/user/src/com/google/gwt/event/dom/client/PrivateMap.java b/user/src/com/google/gwt/event/dom/client/PrivateMap.java
index 2b136b3..9f264bf 100644
--- a/user/src/com/google/gwt/event/dom/client/PrivateMap.java
+++ b/user/src/com/google/gwt/event/dom/client/PrivateMap.java
@@ -89,12 +89,12 @@
public final V safeGet(String key) {
return unsafeGet(":" + key);
}
-
+
// ONLY use this for values that will be accessed with safeGet.
public final void safePut(String key, V value) {
unsafePut(":" + key, value);
}
-
+
// ONLY use this for values put with unsafePut.
public final V unsafeGet(String key) {
if (GWT.isScript()) {
@@ -103,7 +103,7 @@
return javaMap.get(key);
}
}
-
+
// ONLY use this for values that will be accessed with unsafeGet.
public final void unsafePut(String key, V value) {
if (GWT.isScript()) {
diff --git a/user/src/com/google/gwt/event/dom/client/ScrollEvent.java b/user/src/com/google/gwt/event/dom/client/ScrollEvent.java
index 21910e9..8451ce9 100644
--- a/user/src/com/google/gwt/event/dom/client/ScrollEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/ScrollEvent.java
@@ -15,8 +15,6 @@
*/
package com.google.gwt.event.dom.client;
-import com.google.gwt.user.client.Event;
-
/**
* Represents a native scroll event.
*/
@@ -27,7 +25,7 @@
* event.
*/
private static final Type<ScrollHandler> TYPE = new Type<ScrollHandler>(
- Event.ONSCROLL, "scroll", new ScrollEvent());
+ "scroll", new ScrollEvent());
/**
* Gets the event type associated with scroll events.
@@ -40,7 +38,7 @@
/**
* Protected constructor, use
- * {@link DomEvent#fireNativeEvent(Event, com.google.gwt.event.shared.HandlerManager)}
+ * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, com.google.gwt.event.shared.HasHandlers)}
* to fire scroll events.
*/
protected ScrollEvent() {
diff --git a/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java b/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
index a482ae6..3514c6a 100644
--- a/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
@@ -34,7 +34,6 @@
* manager.If no such handlers exist, this method will do nothing.
*
* @param <I> the selected item type
- * @param <S> The event source
* @param source the source of the handlers
* @param selectedItem the selected item
*/
diff --git a/user/src/com/google/gwt/event/shared/HandlerManager.java b/user/src/com/google/gwt/event/shared/HandlerManager.java
index 4123dab..f180f96 100644
--- a/user/src/com/google/gwt/event/shared/HandlerManager.java
+++ b/user/src/com/google/gwt/event/shared/HandlerManager.java
@@ -16,7 +16,6 @@
package com.google.gwt.event.shared;
import com.google.gwt.event.shared.GwtEvent.Type;
-import com.google.gwt.user.client.Command;
import java.util.ArrayList;
import java.util.HashMap;
@@ -28,6 +27,14 @@
* handlers on passed in events.
*/
public class HandlerManager {
+
+ /**
+ * Interface for queued add/remove operations.
+ */
+ private interface AddOrRemoveCommand {
+ public void execute();
+ }
+
/**
* Inner class used to actually contain the handlers.
*/
@@ -77,9 +84,16 @@
return l == null ? 0 : l.size();
}
+ private boolean isEventHandled(GwtEvent.Type<?> eventKey) {
+ return map.containsKey(eventKey);
+ }
+
private <H> void removeHandler(GwtEvent.Type<H> eventKey, H handler) {
ArrayList<H> l = get(eventKey);
boolean result = l.remove(handler);
+ if (l.size() == 0) {
+ map.remove(eventKey);
+ }
assert result : "Tried to remove unknown handler: " + handler + " from "
+ eventKey;
}
@@ -95,7 +109,7 @@
private final Object source;
// Add and remove operations received during dispatch.
- private List<Command> deferredDeltas;
+ private List<AddOrRemoveCommand> deferredDeltas;
/**
* Creates a handler manager with the given source. Handlers will be fired in
@@ -204,6 +218,16 @@
}
/**
+ * Does this handler manager handle the given event type?
+ *
+ * @param e the event type
+ * @return whether the given event type is handled
+ */
+ public boolean isEventHandled(Type<?> e) {
+ return registry.isEventHandled(e);
+ }
+
+ /**
* Removes the given handler from the specified event type. Normally,
* applications should call {@link HandlerRegistration#removeHandler()}
* instead.
@@ -236,9 +260,9 @@
return registry.map;
}
- private void defer(Command command) {
+ private void defer(AddOrRemoveCommand command) {
if (deferredDeltas == null) {
- deferredDeltas = new ArrayList<Command>();
+ deferredDeltas = new ArrayList<AddOrRemoveCommand>();
}
deferredDeltas.add(command);
}
@@ -255,7 +279,7 @@
private <H extends EventHandler> void enqueueAdd(final GwtEvent.Type<H> type,
final H handler) {
- defer(new Command() {
+ defer(new AddOrRemoveCommand() {
public void execute() {
doAdd(type, handler);
}
@@ -264,7 +288,7 @@
private <H extends EventHandler> void enqueueRemove(
final GwtEvent.Type<H> type, final H handler) {
- defer(new Command() {
+ defer(new AddOrRemoveCommand() {
public void execute() {
doRemove(type, handler);
}
@@ -274,7 +298,7 @@
private void handleQueuedAddsAndRemoves() {
if (deferredDeltas != null) {
try {
- for (Command c : deferredDeltas) {
+ for (AddOrRemoveCommand c : deferredDeltas) {
c.execute();
}
} finally {
diff --git a/user/src/com/google/gwt/i18n/I18N.gwt.xml b/user/src/com/google/gwt/i18n/I18N.gwt.xml
index 061a67f..e84868c 100644
--- a/user/src/com/google/gwt/i18n/I18N.gwt.xml
+++ b/user/src/com/google/gwt/i18n/I18N.gwt.xml
@@ -27,7 +27,7 @@
// Look for the locale as a url argument
if (locale == null) {
var args = location.search;
- var startLang = args.indexOf("locale");
+ var startLang = args.indexOf("locale=");
if (startLang >= 0) {
var language = args.substring(startLang);
var begin = language.indexOf("=") + 1;
@@ -45,6 +45,11 @@
}
if (locale == null) {
+ // Look for an override computed by other means in the selection script
+ locale = $wnd['__gwt_Locale'];
+ }
+
+ if (locale == null) {
return "default";
}
diff --git a/user/src/com/google/gwt/i18n/client/Constants.java b/user/src/com/google/gwt/i18n/client/Constants.java
index c5be987..8417853 100644
--- a/user/src/com/google/gwt/i18n/client/Constants.java
+++ b/user/src/com/google/gwt/i18n/client/Constants.java
@@ -64,7 +64,7 @@
*
* {@example com.google.gwt.examples.i18n.NumberFormatConstantsAnnot}
* </p>
- *
+ *
* <p>
* It is also possible to change the property name bound to a constant accessor
* using the {@code @Key} annotation. For example,
@@ -152,7 +152,8 @@
* the constant accessor <code>someMap()</code> would return a
* <code>Map</code> that maps <code>"a"</code> onto <code>"X"</code>,
* <code>"b"</code> onto <code>"Y"</code>, and <code>"c"</code> onto
- * <code>"Z"</code>.
+ * <code>"Z"</code>. Iterating through this <code>Map</code> will return
+ * the keys or entries in declaration order.
* </p>
*
* <p>The benefit of using annotations, aside from not having to switch to
diff --git a/user/src/com/google/gwt/i18n/client/impl/ConstantMap.java b/user/src/com/google/gwt/i18n/client/impl/ConstantMap.java
index 0ecec17..f683e97 100644
--- a/user/src/com/google/gwt/i18n/client/impl/ConstantMap.java
+++ b/user/src/com/google/gwt/i18n/client/impl/ConstantMap.java
@@ -20,10 +20,9 @@
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Set;
/**
@@ -33,10 +32,62 @@
*/
public class ConstantMap extends AbstractMap<String, String> {
- /**
- * A cache of a synthesized entry set.
- */
- private Set<Map.Entry<String, String>> entries;
+ private static final class EntryImpl implements Entry<String, String> {
+ private final String key;
+ private final String value;
+
+ private EntryImpl(String key, String value) {
+ assert (key != null);
+ assert (value != null);
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Map.Entry) {
+ Map.Entry<?, ?> other = (Map.Entry<?, ?>) o;
+ // Key and value known to be non-null.
+ if (key.equals(other.getKey()) && value.equals(other.getValue())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Calculate the hash code using Sun's specified algorithm.
+ */
+ @Override
+ public int hashCode() {
+ int keyHash = 0;
+ int valueHash = 0;
+ if (getKey() != null) {
+ keyHash = getKey().hashCode();
+ }
+ if (getValue() != null) {
+ valueHash = getValue().hashCode();
+ }
+ return keyHash ^ valueHash;
+ }
+
+ public String setValue(String value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return key + "=" + value;
+ }
+ }
/**
* The original set of keys.
@@ -56,6 +107,8 @@
init();
for (int i = 0; i < keys.length; ++i) {
+ assert keys[i] != null;
+ assert values[i] != null;
putImpl(keys[i], values[i]);
}
}
@@ -67,14 +120,48 @@
@Override
public Set<Map.Entry<String, String>> entrySet() {
- if (entries == null) {
- Map<String, String> copy = new HashMap<String, String>();
- for (String key : keys) {
- copy.put(key, get(key));
+ return new AbstractSet<Entry<String, String>>() {
+ @Override
+ public boolean contains(Object o) {
+ if (!(o instanceof Entry)) {
+ return false;
+ }
+ Entry<?, ?> other = (Entry<?, ?>) o;
+ String value = get(other.getKey());
+ if (value != null && value.equals(other.getValue())) {
+ return true;
+ }
+ return false;
}
- entries = Collections.unmodifiableMap(copy).entrySet();
- }
- return entries;
+
+ @Override
+ public Iterator<Map.Entry<String, String>> iterator() {
+ return new Iterator<Entry<String, String>>() {
+ private int next = 0;
+
+ public boolean hasNext() {
+ return next < ConstantMap.this.size();
+ }
+
+ public Entry<String, String> next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ String key = keys[next++];
+ return new EntryImpl(key, get(key));
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ return ConstantMap.this.size();
+ }
+ };
}
@Override
diff --git a/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java b/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java
index a192966..ee6fa28 100644
--- a/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/ConstantsMapMethodCreator.java
@@ -22,8 +22,8 @@
import com.google.gwt.i18n.rebind.AbstractResource.ResourceList;
import com.google.gwt.user.rebind.AbstractGeneratorClassCreator;
-import java.util.SortedMap;
-import java.util.TreeMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
/**
* Creator for methods of the form Map getX() .
@@ -81,7 +81,8 @@
String[] keys = ConstantsStringArrayMethodCreator.split(keyString);
ResourceList resources = getResources();
- SortedMap<String, String> map = new TreeMap<String, String>();
+ // Use a LinkedHashMap to preserve declaration order (but remove dups).
+ Map<String, String> map = new LinkedHashMap<String, String>();
for (String key : keys) {
if (key.length() == 0) {
continue;
diff --git a/user/src/com/google/gwt/json/client/JSONObject.java b/user/src/com/google/gwt/json/client/JSONObject.java
index 6fd985d..bb6867a 100644
--- a/user/src/com/google/gwt/json/client/JSONObject.java
+++ b/user/src/com/google/gwt/json/client/JSONObject.java
@@ -15,11 +15,14 @@
*/
package com.google.gwt.json.client;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
+import java.util.AbstractSet;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -39,7 +42,7 @@
private final JavaScriptObject jsObject;
public JSONObject() {
- jsObject = JavaScriptObject.createObject();
+ this(JavaScriptObject.createObject());
}
/**
@@ -107,12 +110,27 @@
}
/**
- * Returns the set of properties defined on this JSONObject.
+ * Returns the set of properties defined on this JSONObject. The returned set
+ * is immutable.
*/
public Set<String> keySet() {
- HashSet<String> keySet = new HashSet<String>();
- addAllKeys(keySet);
- return keySet;
+ final String[] keys = computeKeys();
+ return new AbstractSet<String>() {
+ @Override
+ public boolean contains(Object o) {
+ return (o instanceof String) && containsKey((String) o);
+ }
+
+ @Override
+ public Iterator<String> iterator() {
+ return Arrays.asList(keys).iterator();
+ }
+
+ @Override
+ public int size() {
+ return keys.length;
+ }
+ };
}
/**
@@ -138,7 +156,8 @@
* Determines the number of properties on this object.
*/
public int size() {
- return keySet().size();
+ // Must always recheck due to foreign changes. :(
+ return computeSize();
}
/**
@@ -152,8 +171,7 @@
StringBuffer sb = new StringBuffer();
sb.append("{");
boolean first = true;
- List<String> keys = new ArrayList<String>();
- addAllKeys(keys);
+ String[] keys = computeKeys();
for (String key : keys) {
if (first) {
first = false;
@@ -180,6 +198,34 @@
}
}-*/;
+ private String[] computeKeys() {
+ if (GWT.isScript()) {
+ return computeKeys0(new String[0]);
+ } else {
+ List<String> result = new ArrayList<String>();
+ addAllKeys(result);
+ return result.toArray(new String[result.size()]);
+ }
+ }
+
+ private native String[] computeKeys0(String[] result) /*-{
+ var jsObject = this.@com.google.gwt.json.client.JSONObject::jsObject;
+ var i = 0;
+ for (var key in jsObject) {
+ result[i++] = key;
+ }
+ return result;
+ }-*/;
+
+ private native int computeSize() /*-{
+ var jsObject = this.@com.google.gwt.json.client.JSONObject::jsObject;
+ var size = 0;
+ for (var key in jsObject) {
+ ++size;
+ }
+ return size;
+ }-*/;
+
private native JSONValue get0(String key) /*-{
var v = this.@com.google.gwt.json.client.JSONObject::jsObject[key];
var func = @com.google.gwt.json.client.JSONParser::typeMap[typeof v];
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index 41508b7..700acd4 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -28,6 +28,7 @@
import com.google.gwt.dev.cfg.Properties;
import com.google.gwt.dev.cfg.Property;
import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.shell.CheckForUpdates;
import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import com.google.gwt.junit.client.TimeoutException;
@@ -514,11 +515,11 @@
}
/**
- * Never check for updates in JUnit mode.
+ * Check for updates once a minute.
*/
@Override
- protected boolean doShouldCheckForUpdates() {
- return false;
+ protected long checkForUpdatesInterval() {
+ return CheckForUpdates.ONE_MINUTE;
}
@Override
diff --git a/user/src/com/google/gwt/user/client/BaseListenerWrapper.java b/user/src/com/google/gwt/user/client/BaseListenerWrapper.java
index 686cf20..a196bb2 100644
--- a/user/src/com/google/gwt/user/client/BaseListenerWrapper.java
+++ b/user/src/com/google/gwt/user/client/BaseListenerWrapper.java
@@ -63,7 +63,7 @@
// The legacy EventHandler should only fire if it is on the top of the
// stack (ie. the last one added).
if (event.isFirstHandler()) {
- if (!listener.onEventPreview(event.getNativeEvent())) {
+ if (!listener.onEventPreview(Event.as(event.getNativeEvent()))) {
event.cancel();
}
}
diff --git a/user/src/com/google/gwt/user/client/DOM.java b/user/src/com/google/gwt/user/client/DOM.java
index 7840ff3..c781bd1 100644
--- a/user/src/com/google/gwt/user/client/DOM.java
+++ b/user/src/com/google/gwt/user/client/DOM.java
@@ -32,7 +32,7 @@
public class DOM {
// The current event being fired
private static Event currentEvent = null;
- private static final DOMImpl impl = GWT.create(DOMImpl.class);
+ static final DOMImpl impl = GWT.create(DOMImpl.class);
private static Element sCaptureElem;
/**
@@ -393,7 +393,7 @@
* @return <code>true</code> if ALT was depressed when the event occurred
*/
public static boolean eventGetAltKey(Event evt) {
- return impl.eventGetAltKey(evt);
+ return evt.getAltKey();
}
/**
@@ -404,7 +404,7 @@
* {@link Event#BUTTON_MIDDLE}, and {@link Event#BUTTON_RIGHT}
*/
public static int eventGetButton(Event evt) {
- return impl.eventGetButton(evt);
+ return evt.getButton();
}
/**
@@ -414,7 +414,7 @@
* @return the mouse x-position
*/
public static int eventGetClientX(Event evt) {
- return impl.eventGetClientX(evt);
+ return evt.getClientX();
}
/**
@@ -424,7 +424,7 @@
* @return the mouse y-position
*/
public static int eventGetClientY(Event evt) {
- return impl.eventGetClientY(evt);
+ return evt.getClientY();
}
/**
@@ -434,7 +434,7 @@
* @return <code>true</code> if CTRL was depressed when the event occurred
*/
public static boolean eventGetCtrlKey(Event evt) {
- return impl.eventGetCtrlKey(evt);
+ return evt.getCtrlKey();
}
/**
@@ -467,6 +467,7 @@
* @param evt the event to be tested
* @return the element from which the mouse pointer was moved
*/
+
public static Element eventGetFromElement(Event evt) {
return impl.eventGetFromElement(evt);
}
@@ -485,7 +486,7 @@
* @see com.google.gwt.user.client.ui.KeyboardListener
*/
public static int eventGetKeyCode(Event evt) {
- return impl.eventGetKeyCode(evt);
+ return evt.getKeyCode();
}
/**
@@ -495,7 +496,7 @@
* @return <code>true</code> if META was depressed when the event occurred
*/
public static boolean eventGetMetaKey(Event evt) {
- return impl.eventGetMetaKey(evt);
+ return evt.getMetaKey();
}
/**
@@ -514,7 +515,7 @@
* @return The velocity of the mouse wheel.
*/
public static int eventGetMouseWheelVelocityY(Event evt) {
- return impl.eventGetMouseWheelVelocityY(evt);
+ return evt.getMouseWheelVelocityY();
}
/**
@@ -522,7 +523,9 @@
*
* @param evt the event to be tested
* @return <code>true</code> if this key event was an auto-repeat
+ * @deprecated not supported in any browser but IE
*/
+ @Deprecated
public static boolean eventGetRepeat(Event evt) {
return impl.eventGetRepeat(evt);
}
@@ -534,7 +537,7 @@
* @return the mouse x-position
*/
public static int eventGetScreenX(Event evt) {
- return impl.eventGetScreenX(evt);
+ return evt.getScreenX();
}
/**
@@ -544,7 +547,7 @@
* @return the mouse y-position
*/
public static int eventGetScreenY(Event evt) {
- return impl.eventGetScreenY(evt);
+ return evt.getScreenY();
}
/**
@@ -554,7 +557,7 @@
* @return <code>true</code> if shift was depressed when the event occurred
*/
public static boolean eventGetShiftKey(Event evt) {
- return impl.eventGetShiftKey(evt);
+ return evt.getShiftKey();
}
/**
@@ -564,7 +567,7 @@
* @return the target element
*/
public static Element eventGetTarget(Event evt) {
- return impl.eventGetTarget(evt);
+ return (Element) evt.getTarget();
}
/**
@@ -574,6 +577,7 @@
* @param evt the event to be tested
* @return the element to which the mouse pointer was moved
*/
+
public static Element eventGetToElement(Event evt) {
return impl.eventGetToElement(evt);
}
@@ -595,7 +599,7 @@
* @return the event's type name
*/
public static String eventGetTypeString(Event evt) {
- return impl.eventGetType(evt);
+ return evt.getType();
}
/**
@@ -604,7 +608,7 @@
* @param evt the event whose default action is to be prevented
*/
public static void eventPreventDefault(Event evt) {
- impl.eventPreventDefault(evt);
+ evt.preventDefault();
}
/**
@@ -628,7 +632,7 @@
* @return a string form of the event
*/
public static String eventToString(Event evt) {
- return impl.eventToString(evt);
+ return evt.getString();
}
/**
@@ -1264,7 +1268,6 @@
* @param evt a handle to the event being previewed
* @return <code>false</code> to cancel the event
*/
- @SuppressWarnings("deprecation")
static boolean previewEvent(Event evt) {
// Fire a NativePreviewEvent to NativePreviewHandlers
boolean ret = Event.fireNativePreviewEvent(evt);
diff --git a/user/src/com/google/gwt/user/client/Event.java b/user/src/com/google/gwt/user/client/Event.java
index 2a72281..0d633fd 100644
--- a/user/src/com/google/gwt/user/client/Event.java
+++ b/user/src/com/google/gwt/user/client/Event.java
@@ -15,8 +15,8 @@
*/
package com.google.gwt.user.client;
-import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.HasNativeEvent;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
@@ -33,7 +33,8 @@
* calling methods in the {@link com.google.gwt.user.client.DOM} class.
* </p>
*/
-public class Event extends JavaScriptObject {
+public class Event extends NativeEvent {
+
/**
* Represents a preview of a native {@link Event}.
*/
@@ -69,8 +70,8 @@
* @param nativeEvent the native event
* @return true to fire the event normally, false to cancel the event
*/
- private static boolean fire(HandlerManager handlers, Event nativeEvent) {
- if (TYPE != null && handlers != null) {
+ private static boolean fire(HandlerManager handlers, NativeEvent nativeEvent) {
+ if (TYPE != null && handlers != null && handlers.isEventHandled(TYPE)) {
// Revive the event
singleton.revive();
singleton.setNativeEvent(nativeEvent);
@@ -102,7 +103,7 @@
/**
* The event being previewed.
*/
- private Event nativeEvent;
+ private NativeEvent nativeEvent;
/**
* Cancel the native event and prevent it from firing. Note that the event
@@ -130,11 +131,21 @@
return TYPE;
}
- public Event getNativeEvent() {
+ public NativeEvent getNativeEvent() {
return nativeEvent;
}
/**
+ * Gets the type int corresponding to the native event that triggered this
+ * preview.
+ *
+ * @return the type int associated with this native event
+ */
+ public final int getTypeInt() {
+ return Event.as(getNativeEvent()).getTypeInt();
+ }
+
+ /**
* Has the event already been canceled? Note that {@link #isConsumed()} will
* still return true if the native event has also been consumed.
*
@@ -185,7 +196,7 @@
*
* @param nativeEvent the native {@link Event} being previewed.
*/
- private void setNativeEvent(Event nativeEvent) {
+ private void setNativeEvent(NativeEvent nativeEvent) {
this.nativeEvent = nativeEvent;
}
}
@@ -203,21 +214,6 @@
}
/**
- * The left mouse button (used in {@link DOM#eventGetButton(Event)}).
- */
- public static final int BUTTON_LEFT = 1;
-
- /**
- * The middle mouse button (used in {@link DOM#eventGetButton(Event)}).
- */
- public static final int BUTTON_MIDDLE = 4;
-
- /**
- * The right mouse button (used in {@link DOM#eventGetButton(Event)}).
- */
- public static final int BUTTON_RIGHT = 2;
-
- /**
* Fired when an element loses keyboard focus.
*/
public static final int ONBLUR = 0x01000;
@@ -398,6 +394,25 @@
}
/**
+ * Converts the {@link NativeEvent} to Event. This is always safe.
+ *
+ * @param event the event to downcast
+ */
+ public static Event as(NativeEvent event) {
+ return (Event) event;
+ }
+
+ /**
+ * Fire a {@link NativePreviewEvent} for the native event.
+ *
+ * @param nativeEvent the native event
+ * @return true to fire the event normally, false to cancel the event
+ */
+ public static boolean fireNativePreviewEvent(NativeEvent nativeEvent) {
+ return NativePreviewEvent.fire(handlers, nativeEvent);
+ }
+
+ /**
* Gets the current event that is being fired. The current event is only
* available within the lifetime of the onBrowserEvent function. Once the
* onBrowserEvent method returns, the current event is reset to null.
@@ -420,6 +435,40 @@
}
/**
+ * Gets the x coordinate relative to the given element.
+ *
+ * @param nativeEvent the native event
+ * @param relativeTo the relative element
+ * @return the relative x
+ */
+ public static int getRelativeX(NativeEvent nativeEvent, Element relativeTo) {
+ return nativeEvent.getClientX() - relativeTo.getAbsoluteLeft()
+ + relativeTo.getScrollLeft() + Window.getScrollLeft();
+ }
+
+ /**
+ * Gets the y coordinate relative to the given element.
+ *
+ * @param nativeEvent the native event
+ * @param relativeTo the relative element
+ * @return the relative y
+ */
+ public static int getRelativeY(NativeEvent nativeEvent, Element relativeTo) {
+ return nativeEvent.getClientY() - relativeTo.getAbsoluteTop()
+ + relativeTo.getScrollTop() + Window.getScrollTop();
+ }
+
+ /**
+ * Gets the enumerated type of this event given a valid event type name.
+ *
+ * @param typeName the typeName to be tested
+ * @return the event's enumerated type
+ */
+ public static int getTypeInt(String typeName) {
+ return DOM.impl.eventGetTypeInt(typeName);
+ }
+
+ /**
* Releases mouse capture on the given element. Calling this method has no
* effect if the element does not currently have mouse capture.
*
@@ -454,6 +503,17 @@
}
/**
+ * Sets the {@link EventListener} to 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
+ * @param listener the listener to receive {@link Event events}
+ */
+ public static void setEventListener(Element elem, EventListener listener) {
+ DOM.setEventListener((com.google.gwt.user.client.Element) elem, listener);
+ }
+
+ /**
* Sets the current set of events sunk by a given element. These events will
* be fired to the nearest {@link EventListener} specified on any of the
* element's parents.
@@ -467,16 +527,6 @@
}
/**
- * Fire a {@link NativePreviewEvent} for the native event.
- *
- * @param nativeEvent the native event
- * @return true to fire the event normally, false to cancel the event
- */
- static boolean fireNativePreviewEvent(Event nativeEvent) {
- return NativePreviewEvent.fire(handlers, nativeEvent);
- }
-
- /**
* Not directly instantiable. Subclasses should also define a protected no-arg
* constructor to prevent client code from directly instantiating the class.
*/
@@ -494,52 +544,6 @@
}
/**
- * Gets whether the ALT key was depressed when the given event occurred.
- *
- * @return <code>true</code> if ALT was depressed when the event occurred
- */
- public final boolean getAltKey() {
- return DOM.eventGetAltKey(this);
- }
-
- /**
- * Gets the mouse buttons that were depressed when the given event occurred.
- *
- * @return a bit-field, defined by {@link Event#BUTTON_LEFT},
- * {@link Event#BUTTON_MIDDLE}, and {@link Event#BUTTON_RIGHT}
- */
- public final int getButton() {
- return DOM.eventGetButton(this);
- }
-
- /**
- * Gets the mouse x-position within the browser window's client area.
- *
- * @return the mouse x-position
- */
- public final int getClientX() {
- return DOM.eventGetClientX(this);
- }
-
- /**
- * Gets the mouse y-position within the browser window's client area.
- *
- * @return the mouse y-position
- */
- public final int getClientY() {
- return DOM.eventGetClientY(this);
- }
-
- /**
- * Gets whether the CTRL key was depressed when the given event occurred.
- *
- * @return <code>true</code> if CTRL was depressed when the event occurred
- */
- public final boolean getCtrlKey() {
- return DOM.eventGetCtrlKey(this);
- }
-
- /**
* Gets the current target element of this event. This is the element whose
* listener fired last, not the element which fired the event initially.
*
@@ -553,132 +557,38 @@
* Gets the element from which the mouse pointer was moved (only valid for
* {@link Event#ONMOUSEOVER}).
*
+ * @deprecated use {@link NativeEvent#getRelatedTarget()} instead
* @return the element from which the mouse pointer was moved
*/
+ @Deprecated
public final Element getFromElement() {
return DOM.eventGetFromElement(this);
}
/**
- * Gets the key code associated with this event.
- *
- * <p>
- * For {@link Event#ONKEYPRESS}, this method returns the Unicode value of the
- * character generated. For {@link Event#ONKEYDOWN} and {@link Event#ONKEYUP},
- * it returns the code associated with the physical key.
- * </p>
- *
- * @return the Unicode character or key code.
- * @see com.google.gwt.event.dom.client.KeyCodes
- */
- public final int getKeyCode() {
- return DOM.eventGetKeyCode(this);
- }
-
- /**
- * Gets whether the META key was depressed when the given event occurred.
- *
- * @return <code>true</code> if META was depressed when the event occurred
- */
- public final boolean getMetaKey() {
- return DOM.eventGetMetaKey(this);
- }
-
- /**
- * Gets the velocity of the mouse wheel associated with the event along the Y
- * axis.
- * <p>
- * The velocity of the event is an artifical measurement for relative
- * comparisons of wheel activity. It is affected by some non-browser factors,
- * including choice of input hardware and mouse acceleration settings. The
- * sign of the velocity measurement agrees with the screen coordinate system;
- * negative values are towards the origin and positive values are away from
- * the origin. Standard scrolling speed is approximately ten units per event.
- * </p>
- *
- * @return The velocity of the mouse wheel.
- */
- public final int getMouseWheelVelocityY() {
- return DOM.eventGetMouseWheelVelocityY(this);
- }
-
- /**
* Gets the key-repeat state of this event.
*
* @return <code>true</code> if this key event was an auto-repeat
+ * @deprecated not supported on all browsers
*/
+ @Deprecated
public final boolean getRepeat() {
return DOM.eventGetRepeat(this);
}
/**
- * Gets the mouse x-position on the user's display.
- *
- * @return the mouse x-position
- */
- public final int getScreenX() {
- return DOM.eventGetScreenX(this);
- }
-
- /**
- * Gets the mouse y-position on the user's display.
- *
- * @return the mouse y-position
- */
- public final int getScreenY() {
- return DOM.eventGetScreenY(this);
- }
-
- /**
- * Gets whether the shift key was depressed when the given event occurred.
- *
- * @return <code>true</code> if shift was depressed when the event occurred
- */
- public final boolean getShiftKey() {
- return DOM.eventGetShiftKey(this);
- }
-
- /**
- * Gets a string representation of this event.
- *
- * We do not override {@link #toString()} because it is final in
- * {@link JavaScriptObject}.
- *
- * @return the string representation of this event
- */
- public final String getString() {
- return DOM.eventToString(this);
- }
-
- /**
- * Returns the element that was the actual target of the given event.
- *
- * @return the target element
- */
- public final Element getTarget() {
- return DOM.eventGetTarget(this);
- }
-
- /**
* Gets the element to which the mouse pointer was moved (only valid for
* {@link Event#ONMOUSEOUT}).
*
+ * @deprecated use {@link NativeEvent#getRelatedTarget()} instead
* @return the element to which the mouse pointer was moved
*/
+ @Deprecated
public final Element getToElement() {
return DOM.eventGetToElement(this);
}
/**
- * Gets the enumerated type of this event (as defined in {@link Event}).
- *
- * @return the event's enumerated type
- */
- public final String getType() {
- return DOM.eventGetTypeString(this);
- }
-
- /**
* Gets the enumerated type of this event, as defined by {@link #ONCLICK},
* {@link #ONMOUSEDOWN}, and so forth.
*
@@ -687,11 +597,4 @@
public final int getTypeInt() {
return DOM.eventGetType(this);
}
-
- /**
- * Prevents the browser from taking its default action for the given event.
- */
- public final void preventDefault() {
- DOM.eventPreventDefault(this);
- }
}
diff --git a/user/src/com/google/gwt/user/client/Timer.java b/user/src/com/google/gwt/user/client/Timer.java
index 4cbceed..dadf6c8 100644
--- a/user/src/com/google/gwt/user/client/Timer.java
+++ b/user/src/com/google/gwt/user/client/Timer.java
@@ -17,7 +17,8 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
-import com.google.gwt.user.client.Window.ClosingEvent;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
import java.util.ArrayList;
@@ -64,9 +65,9 @@
private static void hookWindowClosing() {
// Catch the window closing event.
- Window.addWindowClosingHandler(new Window.ClosingHandler() {
+ Window.addCloseHandler(new CloseHandler<Window>() {
- public void onWindowClosing(ClosingEvent event) {
+ public void onClose(CloseEvent<Window> event) {
while (timers.size() > 0) {
timers.get(0).cancel();
}
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 09ffb25..a42eaa5 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImpl.java
@@ -28,8 +28,8 @@
protected static boolean eventSystemIsInitialized;
/**
- * Returns <code>true</code>if the object is an instance of EventListener
- * and the object belongs to this module.
+ * Returns <code>true</code>if the object is an instance of EventListener and
+ * the object belongs to this module.
*/
protected static boolean isMyListener(Object object) {
/*
@@ -47,104 +47,53 @@
public native void eventCancelBubble(Event evt, boolean cancel) /*-{
evt.cancelBubble = cancel;
- }-*/;
-
- public native boolean eventGetAltKey(Event evt) /*-{
- return !!evt.altKey;
- }-*/;
-
- public native int eventGetButton(Event evt) /*-{
- return evt.button || 0;
- }-*/;
-
- public native int eventGetClientX(Event evt) /*-{
- return evt.clientX || 0;
- }-*/;
-
- public native int eventGetClientY(Event evt) /*-{
- return evt.clientY || 0;
- }-*/;
-
- public native boolean eventGetCtrlKey(Event evt) /*-{
- return !!evt.ctrlKey;
- }-*/;
-
+ }-*/;
+
public native Element eventGetCurrentTarget(Event evt) /*-{
return evt.currentTarget;
- }-*/;
+ }-*/;
public abstract Element eventGetFromElement(Event evt);
-
- public native int eventGetKeyCode(Event evt) /*-{
- // 'which' gives the right key value, except when it doesn't -- in which
- // case, keyCode gives the right value on all browsers.
- // If all else fails, return an error code
- return evt.which || evt.keyCode || 0;
- }-*/;
-
- public native boolean eventGetMetaKey(Event evt) /*-{
- return !!evt.metaKey;
- }-*/;
-
- public abstract int eventGetMouseWheelVelocityY(Event evt);
-
+
public native boolean eventGetRepeat(Event evt) /*-{
return !!evt.repeat;
- }-*/;
-
- public native int eventGetScreenX(Event evt) /*-{
- return evt.screenX || 0;
- }-*/;
-
- public native int eventGetScreenY(Event evt) /*-{
- return evt.screenY || 0;
- }-*/;
-
- public native boolean eventGetShiftKey(Event evt) /*-{
- return !!evt.shiftKey;
- }-*/;
-
- public abstract Element eventGetTarget(Event evt);
-
+ }-*/;
+
public abstract Element eventGetToElement(Event evt);
- public native String eventGetType(Event evt) /*-{
- return evt.type;
- }-*/;
-
- public native int eventGetTypeInt(Event evt) /*-{
- switch (evt.type) {
- case "blur": return 0x01000;
- case "change": return 0x00400;
- case "click": return 0x00001;
- case "dblclick": return 0x00002;
- case "focus": return 0x00800;
- case "keydown": return 0x00080;
- case "keypress": return 0x00100;
- case "keyup": return 0x00200;
- case "load": return 0x08000;
- case "losecapture": return 0x02000;
- case "mousedown": return 0x00004;
- case "mousemove": return 0x00040;
- case "mouseout": return 0x00020;
- case "mouseover": return 0x00010;
- case "mouseup": return 0x00008;
- case "scroll": return 0x04000;
- case "error": return 0x10000;
- case "mousewheel": return 0x20000;
- case "DOMMouseScroll": return 0x20000;
- case "contextmenu": return 0x40000;
- }
- }-*/;
-
- public abstract void eventPreventDefault(Event evt);
-
+ public final int eventGetTypeInt(Event evt) {
+ return eventGetTypeInt(evt.getType());
+ }
+
+ public native int eventGetTypeInt(String eventType) /*-{
+ switch (eventType) {
+ case "blur": return 0x01000;
+ case "change": return 0x00400;
+ case "click": return 0x00001;
+ case "dblclick": return 0x00002;
+ case "focus": return 0x00800;
+ case "keydown": return 0x00080;
+ case "keypress": return 0x00100;
+ case "keyup": return 0x00200;
+ case "load": return 0x08000;
+ case "losecapture": return 0x02000;
+ case "mousedown": return 0x00004;
+ case "mousemove": return 0x00040;
+ case "mouseout": return 0x00020;
+ case "mouseover": return 0x00010;
+ case "mouseup": return 0x00008;
+ case "scroll": return 0x04000;
+ case "error": return 0x10000;
+ case "mousewheel": return 0x20000;
+ case "DOMMouseScroll": return 0x20000;
+ case "contextmenu": return 0x40000;
+ }
+ }-*/;
+
public native void eventSetKeyCode(Event evt, char key) /*-{
- evt.keyCode = key;
- }-*/;
-
- public abstract String eventToString(Event evt);
-
+ evt.keyCode = key;
+ }-*/;
+
public abstract Element getChild(Element elem, int index);
public abstract int getChildCount(Element elem);
@@ -152,8 +101,8 @@
public abstract int getChildIndex(Element parent, Element child);
public native int getEventsSunk(Element elem) /*-{
- return elem.__eventBits || 0;
- }-*/;
+ return elem.__eventBits || 0;
+ }-*/;
public abstract void insertChild(Element parent, Element child, int index);
@@ -169,8 +118,8 @@
public abstract void setCapture(Element elem);
public native void setEventListener(Element elem, EventListener listener) /*-{
- elem.__listener = listener;
- }-*/;
+ elem.__listener = listener;
+ }-*/;
public abstract void sinkEvents(Element elem, int eventBits);
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java b/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
index 8cd05bf..d071853 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
@@ -41,33 +41,16 @@
@Override
public native Element eventGetFromElement(Event evt) /*-{
- return evt.fromElement;
- }-*/;
-
- @Override
- public native int eventGetMouseWheelVelocityY(Event evt) /*-{
- return Math.round(-evt.wheelDelta / 40) || 0;
- }-*/;
-
- @Override
- public native Element eventGetTarget(Event evt) /*-{
- return evt.srcElement;
+ // Prefer 'relatedTarget' if it's set (see createMouseEvent(), which
+ // explicitly sets relatedTarget when synthesizing mouse events).
+ return evt.relatedTarget || evt.fromElement;
}-*/;
@Override
public native Element eventGetToElement(Event evt) /*-{
- return evt.toElement;
- }-*/;
-
- @Override
- public native void eventPreventDefault(Event evt) /*-{
- evt.returnValue = false;
- }-*/;
-
- @Override
- public native String eventToString(Event evt) /*-{
- if (evt.toString) return evt.toString();
- return "[object Event]";
+ // Prefer 'relatedTarget' if it's set (see createMouseEvent(), which
+ // explicitly sets relatedTarget when synthesizing mouse events).
+ return evt.relatedTarget || evt.toElement;
}-*/;
@Override
@@ -125,7 +108,7 @@
@com.google.gwt.user.client.impl.DOMImplIE6::dispatchDblClickEvent = function() {
var newEvent = $doc.createEventObject();
- this.fireEvent('onclick', newEvent);
+ $wnd.event.srcElement.fireEvent('onclick', newEvent);
if (this.__eventBits & 2) {
@com.google.gwt.user.client.impl.DOMImplIE6::dispatchEvent.call(this);
}
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java b/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
index 20892b7..a647aa1 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
@@ -16,7 +16,6 @@
package com.google.gwt.user.client.impl;
import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
/**
* Mozilla implementation of StandardBrowser.
@@ -24,11 +23,6 @@
class DOMImplMozilla extends DOMImplStandard {
@Override
- public native int eventGetMouseWheelVelocityY(Event evt) /*-{
- return evt.detail || 0;
- }-*/;
-
- @Override
public void sinkEvents(Element elem, int bits) {
super.sinkEvents(elem, bits);
sinkEventsMozilla(elem, bits);
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java b/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java
index d94dbc8..8261d77 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplOpera.java
@@ -16,18 +16,11 @@
package com.google.gwt.user.client.impl;
import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
/**
* Opera implementation of {@link com.google.gwt.user.client.impl.DOMImpl}.
*/
public class DOMImplOpera extends DOMImplStandard {
-
- @Override
- public native int eventGetMouseWheelVelocityY(Event evt) /*-{
- return evt.detail * 4 || 0;
- }-*/;
-
/**
* As Opera sinks events very quickly, adding guards to prevent the sinking of
* events actually slows Opera down.
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java b/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java
index 1b7e3b55..16ab0ed 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplSafari.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplSafari.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,47 +15,8 @@
*/
package com.google.gwt.user.client.impl;
-import com.google.gwt.user.client.Event;
-
/**
* Safari implementation of {@link com.google.gwt.user.client.impl.DOMImpl}.
*/
class DOMImplSafari extends DOMImplStandard {
-
- @Override
- public native int eventGetClientX(Event 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(Event 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(Event evt) /*-{
- return Math.round(-evt.wheelDelta / 40) || 0;
- }-*/;
}
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
index 5d2be3c..3fa1553 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
@@ -39,19 +39,6 @@
private static JavaScriptObject dispatchEvent;
@Override
- public native int eventGetButton(Event evt) /*-{
- // Standard browsers and IE disagree on what the button codes for buttons
- // should be. Translating to match IE standard.
- var button = evt.which;
- if(button == 2) {
- return 4;
- } else if (button == 3) {
- return 2;
- }
- return button || 0;
- }-*/;
-
- @Override
public native Element eventGetFromElement(Event evt) /*-{
if (evt.type == "mouseover")
return evt.relatedTarget;
@@ -59,12 +46,7 @@
return evt.target;
return null;
}-*/;
-
- @Override
- public native Element eventGetTarget(Event evt) /*-{
- return evt.target;
- }-*/;
-
+
@Override
public native Element eventGetToElement(Event evt) /*-{
if (evt.type == "mouseover")
@@ -73,17 +55,7 @@
return evt.relatedTarget;
return null;
}-*/;
-
- @Override
- public native void eventPreventDefault(Event evt) /*-{
- evt.preventDefault();
- }-*/;
-
- @Override
- public native String eventToString(Event evt) /*-{
- return evt.toString();
- }-*/;
-
+
@Override
public native Element getChild(Element elem, int index) /*-{
var count = 0, child = elem.firstChild;
diff --git a/user/src/com/google/gwt/user/client/ui/Button.java b/user/src/com/google/gwt/user/client/ui/Button.java
index e571bbd..33d17f4 100644
--- a/user/src/com/google/gwt/user/client/ui/Button.java
+++ b/user/src/com/google/gwt/user/client/ui/Button.java
@@ -18,6 +18,7 @@
import com.google.gwt.dom.client.ButtonElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.ButtonElement;
import com.google.gwt.event.dom.client.ClickHandler;
/**
@@ -71,10 +72,6 @@
}
}-*/;
- static native void click(Element button) /*-{
- button.click();
- }-*/;
-
/**
* Creates a button with no caption.
*/
@@ -133,6 +130,11 @@
* Programmatic equivalent of the user clicking the button.
*/
public void click() {
- click(getElement());
+ getButtonElement().click();
+ }
+
+ private ButtonElement getButtonElement() {
+ return getElement().cast();
}
}
+
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 7aad9ba..40386ff 100644
--- a/user/src/com/google/gwt/user/client/ui/CheckBox.java
+++ b/user/src/com/google/gwt/user/client/ui/CheckBox.java
@@ -303,11 +303,12 @@
throw new IllegalArgumentException("value must not be null");
}
- if (value.equals(getValue())) {
- return;
- }
+ Boolean oldValue = getValue();
inputElem.setChecked(value);
inputElem.setDefaultChecked(value);
+ if (value.equals(oldValue)) {
+ return;
+ }
if (fireEvents) {
ValueChangeEvent.fire(this, value);
}
diff --git a/user/src/com/google/gwt/user/client/ui/CustomButton.java b/user/src/com/google/gwt/user/client/ui/CustomButton.java
index 89efb9b..a59978a 100644
--- a/user/src/com/google/gwt/user/client/ui/CustomButton.java
+++ b/user/src/com/google/gwt/user/client/ui/CustomButton.java
@@ -16,6 +16,8 @@
package com.google.gwt.user.client.ui;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM;
@@ -316,6 +318,12 @@
private boolean isFocusing;
/**
+ * Used to decide whether to allow clicks to propagate up to the superclass
+ * or container elements.
+ */
+ private boolean allowClick;
+
+ /**
* Constructor for <code>CustomButton</code>.
*
* @param upImage image for the default (up) face of the button
@@ -575,6 +583,14 @@
int type = DOM.eventGetType(event);
switch (type) {
+ case Event.ONCLICK:
+ // If clicks are currently disallowed, keep it from bubbling or being
+ // passed to the superclass.
+ if (!allowClick) {
+ event.stopPropagation();
+ return;
+ }
+ break;
case Event.ONMOUSEDOWN:
if (event.getButton() == Event.BUTTON_LEFT) {
setFocus(true);
@@ -618,9 +634,6 @@
}
}
break;
- case Event.ONCLICK:
- // we handle clicks ourselves
- return;
case Event.ONBLUR:
if (isFocusing) {
isFocusing = false;
@@ -748,7 +761,18 @@
* widget display.
*/
protected void onClick() {
- fireClickListeners(null);
+ // Allow the click we're about to synthesize to pass through to the
+ // superclass and containing elements. Element.dispatchEvent() is
+ // synchronous, so we simply set and clear the flag within this method.
+ allowClick = true;
+
+ // Mouse coordinates are not always available (e.g., when the click is
+ // caused by a keyboard event).
+ NativeEvent evt = Document.get().createClickEvent(1, 0, 0, 0, 0, false,
+ false, false, false);
+ getElement().dispatchEvent(evt);
+
+ allowClick = false;
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/DialogBox.java b/user/src/com/google/gwt/user/client/ui/DialogBox.java
index e1d3e34..a5bde38 100644
--- a/user/src/com/google/gwt/user/client/ui/DialogBox.java
+++ b/user/src/com/google/gwt/user/client/ui/DialogBox.java
@@ -16,6 +16,7 @@
package com.google.gwt.user.client.ui;
import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.HasAllMouseHandlers;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
@@ -45,10 +46,11 @@
* <img class='gallery' src='DialogBox.png'/>
* </p>
* <h3>CSS Style Rules</h3>
- * <ul class='css'>
+ *
+ * <ul>
* <li>.gwt-DialogBox { the outside of the dialog }</li>
* <li>.gwt-DialogBox .Caption { the caption }</li>
- * <li>.gwt-DialogBox .dialogContent { the wrapepr around the content }</li>
+ * <li>.gwt-DialogBox .dialogContent { the wrapper around the content }</li>
* <li>.gwt-DialogBox .dialogTopLeft { the top left cell }</li>
* <li>.gwt-DialogBox .dialogTopLeftInner { the inner element of the cell }</li>
* <li>.gwt-DialogBox .dialogTopCenter { the top center cell, where the caption
@@ -60,15 +62,18 @@
* <li>.gwt-DialogBox .dialogMiddleLeftInner { the inner element of the cell }</li>
* <li>.gwt-DialogBox .dialogMiddleCenter { the middle center cell, where the
* content is located }</li>
- * <li>.gwt-DialogBox .dialogMiddleCenterInner { the inner element of the cell }</li>
+ * <li>.gwt-DialogBox .dialogMiddleCenterInner { the inner element of the cell }
+ * </li>
* <li>.gwt-DialogBox .dialogMiddleRight { the middle right cell }</li>
* <li>.gwt-DialogBox .dialogMiddleRightInner { the inner element of the cell }</li>
* <li>.gwt-DialogBox .dialogBottomLeft { the bottom left cell }</li>
* <li>.gwt-DialogBox .dialogBottomLeftInner { the inner element of the cell }</li>
* <li>.gwt-DialogBox .dialogBottomCenter { the bottom center cell }</li>
- * <li>.gwt-DialogBox .dialogBottomCenterInner { the inner element of the cell }</li>
+ * <li>.gwt-DialogBox .dialogBottomCenterInner { the inner element of the cell }
+ * </li>
* <li>.gwt-DialogBox .dialogBottomRight { the bottom right cell }</li>
* <li>.gwt-DialogBox .dialogBottomRightInner { the inner element of the cell }</li>
+ * </ul>
* <p>
* <h3>Example</h3>
* {@example com.google.gwt.examples.DialogBoxExample}
@@ -79,7 +84,7 @@
MouseListener {
/**
* Set of characteristic interfaces supported by the {@link DialogBox} caption
- *
+ *
* Note that this set might expand over time, so implement this interface at
* your own risk.
*/
@@ -141,7 +146,7 @@
* {@link #add(Widget)}.
*
* @param autoHide <code>true</code> if the dialog should be automatically
- * hidden when the user clicks outside of it
+ * hidden when the user clicks outside of it
*/
public DialogBox(boolean autoHide) {
this(autoHide, true);
@@ -153,9 +158,9 @@
* {@link #add(Widget)}.
*
* @param autoHide <code>true</code> if the dialog should be automatically
- * hidden when the user clicks outside of it
+ * hidden when the user clicks outside of it
* @param modal <code>true</code> if keyboard and mouse events for widgets not
- * contained by the dialog should be ignored
+ * contained by the dialog should be ignored
*/
public DialogBox(boolean autoHide, boolean modal) {
super(autoHide, modal, "dialog");
@@ -184,10 +189,10 @@
/**
* Provides access to the dialog's caption.
- *
+ *
* This method is final because the Caption interface will expand. Therefore
- * it is highly likely that subclasses which implemented this method would end up
- * breaking.
+ * it is highly likely that subclasses which implemented this method would end
+ * up breaking.
*
* @return the logical caption for this dialog box
*/
@@ -232,7 +237,7 @@
/**
* @deprecated Use {@link #beginDragging} instead and {@link #getCaption}
- * instead
+ * instead
*/
@Deprecated
public void onMouseDown(Widget sender, int x, int y) {
@@ -324,8 +329,8 @@
* @param event the mouse down event that triggered dragging
*/
protected void beginDragging(MouseDownEvent event) {
- onMouseDown(caption, event.getRelativeX(getElement()),
- event.getRelativeY(getElement()));
+ onMouseDown(caption, Event.getRelativeX(event.getNativeEvent(),
+ getElement()), Event.getRelativeY(event.getNativeEvent(), getElement()));
}
/**
@@ -337,8 +342,8 @@
* @param event the mouse move event that continues dragging
*/
protected void continueDragging(MouseMoveEvent event) {
- onMouseMove(caption, event.getRelativeX(getElement()),
- event.getRelativeY(getElement()));
+ onMouseMove(caption, Event.getRelativeX(event.getNativeEvent(),
+ getElement()), Event.getRelativeY(event.getNativeEvent(), getElement()));
}
@Override
@@ -363,15 +368,17 @@
/**
* Called on mouse up in the caption area, ends dragging by ending event
* capture.
- * @param event the mouse up event that ended dragging
+ *
+ * @param event the mouse up event that ended dragging
*
* @see DOM#releaseCapture
* @see #beginDragging
* @see #endDragging
*/
protected void endDragging(MouseUpEvent event) {
- onMouseUp(caption, event.getRelativeX(getElement()),
- event.getRelativeY(getElement()));
+ onMouseUp(caption,
+ Event.getRelativeX(event.getNativeEvent(), getElement()),
+ Event.getRelativeY(event.getNativeEvent(), getElement()));
}
/**
@@ -395,8 +402,10 @@
// We need to preventDefault() on mouseDown events (outside of the
// DialogBox content) to keep text from being selected when it
// is dragged.
- Event nativeEvent = event.getNativeEvent();
- if (!event.isCanceled() && nativeEvent.getTypeInt() == Event.ONMOUSEDOWN
+ NativeEvent nativeEvent = event.getNativeEvent();
+
+ if (!event.isCanceled()
+ && (event.getTypeInt() == Event.ONMOUSEDOWN)
&& isCaptionEvent(nativeEvent)) {
nativeEvent.preventDefault();
}
@@ -404,7 +413,7 @@
super.onPreviewNativeEvent(event);
}
- private boolean isCaptionEvent(Event event) {
+ private boolean isCaptionEvent(NativeEvent event) {
return getCellElement(0, 1).getParentElement().isOrHasChild(
event.getTarget());
}
diff --git a/user/src/com/google/gwt/user/client/ui/FlexTable.java b/user/src/com/google/gwt/user/client/ui/FlexTable.java
index b2ecb0a..402bf81 100644
--- a/user/src/com/google/gwt/user/client/ui/FlexTable.java
+++ b/user/src/com/google/gwt/user/client/ui/FlexTable.java
@@ -98,7 +98,7 @@
var cell = $doc.createElement("td");
rowElem.appendChild(cell);
}
- }-*/;
+ }-*/;
public FlexTable() {
super();
@@ -172,9 +172,6 @@
return super.insertRow(beforeRow);
}
- /**
- * @see com.google.gwt.user.client.ui.HTMLTable#removeCell(int, int)
- */
@Override
public void removeCell(int row, int col) {
super.removeCell(row, col);
diff --git a/user/src/com/google/gwt/user/client/ui/HTMLTable.java b/user/src/com/google/gwt/user/client/ui/HTMLTable.java
index 51eb0a3..41066ff 100644
--- a/user/src/com/google/gwt/user/client/ui/HTMLTable.java
+++ b/user/src/com/google/gwt/user/client/ui/HTMLTable.java
@@ -700,7 +700,7 @@
* @param listener listener to add
* @deprecated add a click handler instead and use
* {@link HTMLTable#getCellForEvent(ClickEvent)} to get the cell
- * information
+ * information (remember to check for a null return value)
*/
@Deprecated
public void addTableListener(TableListener listener) {
@@ -748,13 +748,14 @@
/**
* Given a click event, return the Cell that was clicked, or null if the event
- * did not hit this table.
+ * did not hit this table. The cell can also be null if the click event does
+ * not occur on a specific cell.
*
* @param event A click event of indeterminate origin
* @return The appropriate cell, or null
*/
public Cell getCellForEvent(ClickEvent event) {
- Element td = getEventTargetCell(event.getNativeEvent());
+ Element td = getEventTargetCell(Event.as(event.getNativeEvent()));
if (td == null) {
return null;
}
diff --git a/user/src/com/google/gwt/user/client/ui/Image.java b/user/src/com/google/gwt/user/client/ui/Image.java
index ee62223..e3bc47e 100644
--- a/user/src/com/google/gwt/user/client/ui/Image.java
+++ b/user/src/com/google/gwt/user/client/ui/Image.java
@@ -42,8 +42,6 @@
import com.google.gwt.event.dom.client.MouseWheelEvent;
import com.google.gwt.event.dom.client.MouseWheelHandler;
import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.impl.ClippedImageImpl;
@@ -66,10 +64,7 @@
* will be lost.
* </p>
*
- * <h3>CSS Style Rules</h3>
- * <ul class="css">
- * <li>.gwt-Image { }</li>
- * </ul>
+ * <h3>CSS Style Rules</h3> <ul class="css"> <li>.gwt-Image { }</li> </ul>
*
* Tranformations between clipped and unclipped state will result in a loss of
* any style names that were set/added; the only style names that are preserved
@@ -113,8 +108,8 @@
image.replaceElement(impl.createStructure(url, left, top, width, height));
// Todo(ecc) This is wrong, we should not be sinking these here on such a
// common widget.After the branch is stable, this should be fixed.
- image.sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.ONMOUSEWHEEL);
- fireSyntheticLoadEvent(image);
+ image.sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.ONMOUSEWHEEL
+ | Event.ONLOAD);
}
@Override
@@ -160,7 +155,7 @@
this.height = height;
impl.adjust(image.getElement(), url, left, top, width, height);
- fireSyntheticLoadEvent(image);
+ impl.fireSyntheticLoadEvent(image);
}
}
@@ -181,7 +176,7 @@
this.height = height;
impl.adjust(image.getElement(), url, left, top, width, height);
- fireSyntheticLoadEvent(image);
+ impl.fireSyntheticLoadEvent(image);
}
}
@@ -190,30 +185,6 @@
protected String getStateName() {
return "clipped";
}
-
- private void fireSyntheticLoadEvent(final Image image) {
- /*
- * We need to synthesize a load event, because the native events that are
- * fired would correspond to the loading of clear.cache.gif, which is
- * incorrect. A native event would not even fire in Internet Explorer,
- * because the root element is a wrapper element around the <img> element.
- * Since we are synthesizing a load event, we do not need to sink the
- * onload event.
- *
- * We use a deferred command here to simulate the native version of the
- * load event as closely as possible. In the native event case, it is
- * unlikely that a second load event would occur while you are in the load
- * event handler.
- */
- DeferredCommand.addCommand(new Command() {
- public void execute() {
- // TODO(ecc) once event triggering is committed, this call should
- // fire a native load event instead.
- image.fireEvent(new LoadEvent() {
- });
- }
- });
- }
}
/**
@@ -251,16 +222,20 @@
private static class UnclippedState extends State {
UnclippedState(Element element) {
- // Todo(ecc) This is wrong, we should not be sinking these here on such a
- // common widget.After the branch is stable, this should be fixed.
+ // This case is relatively unusual, in that we swapped a clipped image
+ // out, so does not need to be efficient.
Event.sinkEvents(element, Event.ONCLICK | Event.MOUSEEVENTS
| Event.ONLOAD | Event.ONERROR | Event.ONMOUSEWHEEL);
}
UnclippedState(Image image) {
image.replaceElement(Document.get().createImageElement());
- // Todo(ecc) This is wrong, we should not be sinking these here on such a
- // common widget.After the branch is stable, this should be fixed.
+ // We are working around an IE race condition that can make the image
+ // incorrectly cache itself if the load event is assigned at the same time
+ // as the image is added to the dom.
+ Event.sinkEvents(image.getElement(), Event.ONLOAD);
+
+ // Todo(ecc) this could be more efficient overall.
image.sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.ONLOAD
| Event.ONERROR | Event.ONMOUSEWHEEL);
}
diff --git a/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java b/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
index ed2aff7..a3a5435 100644
--- a/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
+++ b/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
@@ -80,6 +80,7 @@
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.GwtEvent.Type;
import com.google.gwt.user.client.BaseListenerWrapper;
+import com.google.gwt.user.client.Event;
import java.util.EventListener;
@@ -98,8 +99,8 @@
/**
* Wrapper for a {@link LoadListener}.
*/
- public static class WrappedLoadListener extends ListenerWrapper<LoadListener> implements
- LoadHandler, ErrorHandler {
+ public static class WrappedLoadListener extends ListenerWrapper<LoadListener>
+ implements LoadHandler, ErrorHandler {
/**
* Adds the wrapped listener.
@@ -341,14 +342,14 @@
getListener().onKeyDown(
getSource(event),
(char) event.getNativeKeyCode(),
- KeyboardListenerCollection.getKeyboardModifiers(event.getNativeEvent()));
+ KeyboardListenerCollection.getKeyboardModifiers(Event.as(event.getNativeEvent())));
}
public void onKeyPress(KeyPressEvent event) {
getListener().onKeyPress(
getSource(event),
(char) event.getNativeEvent().getKeyCode(),
- KeyboardListenerCollection.getKeyboardModifiers(event.getNativeEvent()));
+ KeyboardListenerCollection.getKeyboardModifiers(Event.as(event.getNativeEvent())));
}
public void onKeyUp(KeyUpEvent event) {
@@ -356,7 +357,7 @@
getListener().onKeyUp(
getSource(event),
(char) event.getNativeKeyCode(),
- KeyboardListenerCollection.getKeyboardModifiers(event.getNativeEvent()));
+ KeyboardListenerCollection.getKeyboardModifiers(Event.as(event.getNativeEvent())));
}
}
@@ -463,15 +464,17 @@
public void onMouseDown(MouseDownEvent event) {
Widget source = getSource(event);
Element elem = source.getElement();
- getListener().onMouseDown(source, event.getRelativeX(elem),
- event.getRelativeY(elem));
+ getListener().onMouseDown(source,
+ Event.getRelativeX(event.getNativeEvent(), elem),
+ Event.getRelativeY(event.getNativeEvent(), elem));
}
public void onMouseMove(MouseMoveEvent event) {
Widget source = getSource(event);
Element elem = source.getElement();
- getListener().onMouseMove(source, event.getRelativeX(elem),
- event.getRelativeY(elem));
+ getListener().onMouseMove(source,
+ Event.getRelativeX(event.getNativeEvent(), elem),
+ Event.getRelativeY(event.getNativeEvent(), elem));
}
public void onMouseOut(MouseOutEvent event) {
@@ -485,8 +488,9 @@
public void onMouseUp(MouseUpEvent event) {
Widget source = getSource(event);
Element elem = source.getElement();
- getListener().onMouseUp(source, event.getRelativeX(elem),
- event.getRelativeY(elem));
+ getListener().onMouseUp(source,
+ Event.getRelativeX(event.getNativeEvent(), elem),
+ Event.getRelativeY(event.getNativeEvent(), elem));
}
}
/**
@@ -530,7 +534,7 @@
public void onMouseWheel(MouseWheelEvent event) {
getListener().onMouseWheel(getSource(event),
- new MouseWheelVelocity(event.getNativeEvent()));
+ new MouseWheelVelocity(Event.as(event.getNativeEvent())));
}
}
/**
@@ -708,8 +712,10 @@
public void onClick(ClickEvent event) {
HTMLTable table = (HTMLTable) event.getSource();
HTMLTable.Cell cell = table.getCellForEvent(event);
- getListener().onCellClicked(table, cell.getRowIndex(),
- cell.getCellIndex());
+ if (cell != null) {
+ getListener().onCellClicked(table, cell.getRowIndex(),
+ cell.getCellIndex());
+ }
}
}
diff --git a/user/src/com/google/gwt/user/client/ui/MenuBar.java b/user/src/com/google/gwt/user/client/ui/MenuBar.java
index 0bf2173..a9fa5b3 100644
--- a/user/src/com/google/gwt/user/client/ui/MenuBar.java
+++ b/user/src/com/google/gwt/user/client/ui/MenuBar.java
@@ -979,8 +979,7 @@
// clear the selection; a keyboard user can cursor down to the first item
selectItem(null);
}
-
- @SuppressWarnings("deprecation")
+
private void openPopup(final MenuItem item) {
// Only the last popup to be opened should preview all event
if (parentMenu != null && parentMenu.popup != null) {
@@ -1002,12 +1001,12 @@
// Hook the popup panel's event preview. We use this to keep it from
// auto-hiding when the parent menu is clicked.
if (!event.isCanceled()) {
- Event nativeEvent = event.getNativeEvent();
- switch (nativeEvent.getTypeInt()) {
+
+ switch (event.getTypeInt()) {
case Event.ONMOUSEDOWN:
// If the event target is part of the parent menu, suppress the
// event altogether.
- com.google.gwt.dom.client.Element target = nativeEvent.getTarget();
+ com.google.gwt.dom.client.Element target = event.getNativeEvent().getTarget();
Element parentMenuElement = item.getParentMenu().getElement();
if (parentMenuElement.isOrHasChild(target)) {
event.cancel();
diff --git a/user/src/com/google/gwt/user/client/ui/PopupPanel.java b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
index 986f45a..8155ae4 100644
--- a/user/src/com/google/gwt/user/client/ui/PopupPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
@@ -19,6 +19,7 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.HasCloseHandlers;
@@ -462,14 +463,10 @@
* {@link CloseHandler#onClose(CloseEvent)} when the popup is closed
*/
public void hide(boolean autoClosed) {
- if (!showing) {
+ if (!isShowing()) {
return;
}
- showing = false;
- if (nativePreviewHandlerRegistration != null) {
- nativePreviewHandlerRegistration.removeHandler();
- nativePreviewHandlerRegistration = null;
- }
+ cleanup();
// Hide the popup
resizeAnimation.setState(false);
@@ -588,6 +585,14 @@
return true;
}
+ @Override
+ protected void onUnload() {
+ // Just to be sure, we perform cleanup when the popup is unloaded (i.e.
+ // removed from the DOM). This is normally taken care of in hide(), but it
+ // can be missed if someone removes the popup directly from the RootPanel.
+ cleanup();
+ }
+
/**
* Remove an autoHide partner.
*
@@ -822,14 +827,11 @@
protected com.google.gwt.user.client.Element getStyleElement() {
return impl.getStyleElement(getPopupImplElement());
}
-
- /**
- * @see NativePreviewHandler#onPreviewNativeEvent(NativePreviewEvent)
- */
- @SuppressWarnings("deprecation")
+
protected void onPreviewNativeEvent(NativePreviewEvent event) {
// Cancel the event based on the deprecated onEventPreview() method
- if (event.isFirstHandler() && !onEventPreview(event.getNativeEvent())) {
+ if (event.isFirstHandler()
+ && !onEventPreview(Event.as(event.getNativeEvent()))) {
event.cancel();
}
}
@@ -892,13 +894,23 @@
}
}-*/;
+ private void cleanup() {
+ // Clear the 'showing' flag and make sure that the event preview is cleaned
+ // up.
+ showing = false;
+ if (nativePreviewHandlerRegistration != null) {
+ nativePreviewHandlerRegistration.removeHandler();
+ nativePreviewHandlerRegistration = null;
+ }
+ }
+
/**
* Does the event target one of the partner elements?
*
* @param event the native event
* @return true if the event targets a partner
*/
- private boolean eventTargetsPartner(Event event) {
+ private boolean eventTargetsPartner(NativeEvent event) {
if (autoHidePartners == null) {
return false;
}
@@ -918,7 +930,7 @@
* @param event the native event
* @return true if the event targets the popup
*/
- private boolean eventTargetsPopup(Event event) {
+ private boolean eventTargetsPopup(NativeEvent event) {
return getElement().isOrHasChild(event.getTarget());
}
@@ -1087,7 +1099,7 @@
}
// If the event targets the popup or the partner, consume it
- Event nativeEvent = event.getNativeEvent();
+ Event nativeEvent = Event.as(event.getNativeEvent());
boolean eventTargetsPopupOrPartner = eventTargetsPopup(nativeEvent)
|| eventTargetsPartner(nativeEvent);
if (eventTargetsPopupOrPartner) {
diff --git a/user/src/com/google/gwt/user/client/ui/PushButton.java b/user/src/com/google/gwt/user/client/ui/PushButton.java
index 3872d11..daad75d 100644
--- a/user/src/com/google/gwt/user/client/ui/PushButton.java
+++ b/user/src/com/google/gwt/user/client/ui/PushButton.java
@@ -96,6 +96,17 @@
*
* @param upImage image for the default(up) face of the button
* @param downImage image for the down face of the button
+ * @param handler the click handler
+ */
+ public PushButton(Image upImage, Image downImage, ClickHandler handler) {
+ super(upImage, downImage, handler);
+ }
+
+ /**
+ * Constructor for <code>PushButton</code>.
+ *
+ * @param upImage image for the default(up) face of the button
+ * @param downImage image for the down face of the button
* @param listener clickListener
*/
@Deprecated
diff --git a/user/src/com/google/gwt/user/client/ui/SourcesKeyboardEvents.java b/user/src/com/google/gwt/user/client/ui/SourcesKeyboardEvents.java
index 37f0ff2..78e1052 100644
--- a/user/src/com/google/gwt/user/client/ui/SourcesKeyboardEvents.java
+++ b/user/src/com/google/gwt/user/client/ui/SourcesKeyboardEvents.java
@@ -20,7 +20,7 @@
* {@link com.google.gwt.user.client.ui.KeyboardListener} interface.
*
* @deprecated use
- * {@link com.google.gwt.com.google.gwt.event.dom.client.HasAllKeyHandlers}
+ * {@link com.google.gwt.event.dom.client.HasAllKeyHandlers}
* instead
*/
@Deprecated
diff --git a/user/src/com/google/gwt/user/client/ui/TextBoxBase.java b/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
index 9fbad0c..d143c8b 100644
--- a/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
+++ b/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
@@ -19,6 +19,7 @@
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
+import com.google.gwt.event.dom.client.HasChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
@@ -31,7 +32,7 @@
*/
@SuppressWarnings("deprecation")
public class TextBoxBase extends FocusWidget implements SourcesChangeEvents,
- HasText, HasName, HasValue<String> {
+ HasChangeHandlers, HasText, HasName, HasValue<String> {
/**
* Text alignment constant, used in
@@ -88,9 +89,13 @@
super(elem);
}
+ public HandlerRegistration addChangeHandler(ChangeHandler handler) {
+ return addDomHandler(handler, ChangeEvent.getType());
+ }
+
@Deprecated
public void addChangeListener(ChangeListener listener) {
- addDomHandler(new ListenerWrapper.WrappedChangeListener(listener), ChangeEvent.getType());
+ addChangeHandler(new ListenerWrapper.WrappedChangeListener(listener));
}
public HandlerRegistration addValueChangeHandler(
@@ -98,11 +103,11 @@
// Initialization code
if (!valueChangeHandlerInitialized) {
valueChangeHandlerInitialized = true;
- addDomHandler(new ChangeHandler() {
+ addChangeHandler(new ChangeHandler() {
public void onChange(ChangeEvent event) {
ValueChangeEvent.fire(TextBoxBase.this, getText());
}
- }, ChangeEvent.getType());
+ });
}
return addHandler(handler, ValueChangeEvent.getType());
}
diff --git a/user/src/com/google/gwt/user/client/ui/Tree.java b/user/src/com/google/gwt/user/client/ui/Tree.java
index 9dff280..0f96566 100644
--- a/user/src/com/google/gwt/user/client/ui/Tree.java
+++ b/user/src/com/google/gwt/user/client/ui/Tree.java
@@ -516,8 +516,7 @@
// The click event should have given focus to this element already.
// Avoid moving focus back up to the tree (so that focusable widgets
// attached to TreeItems can receive keyboard events).
- } else if (curSelection != null
- && curSelection.getContentElem().isOrHasChild(e)) {
+ } else if (curSelection != null) {
setFocus(true);
}
break;
@@ -929,7 +928,7 @@
DOM.setIntStyleAttribute(focusable, "zIndex", -1);
DOM.appendChild(getElement(), focusable);
- sinkEvents(Event.MOUSEEVENTS | Event.ONCLICK | Event.KEYEVENTS);
+ sinkEvents(Event.ONMOUSEDOWN | Event.ONCLICK | Event.KEYEVENTS);
DOM.sinkEvents(focusable, Event.FOCUSEVENTS);
// The 'root' item is invisible and serves only as a container
@@ -1154,9 +1153,10 @@
}
curSelection = item;
- if (moveFocus && curSelection != null) {
- moveFocus();
-
+ if (curSelection != null) {
+ if (moveFocus) {
+ moveFocus();
+ }
// Select the item and fire the selection event.
curSelection.setSelected(true);
if (fireEvents) {
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 2bcf44a..5933672 100644
--- a/user/src/com/google/gwt/user/client/ui/Widget.java
+++ b/user/src/com/google/gwt/user/client/ui/Widget.java
@@ -77,22 +77,18 @@
case Event.ONMOUSEOVER:
// Only fire the mouse over event if it's coming from outside this
// widget.
- Element from = event.getFromElement();
- if (from != null && getElement().isOrHasChild(from)) {
+ case Event.ONMOUSEOUT:
+ // Only fire the mouse out event if it's leaving this
+ // widget.
+ Element related = event.getRelatedTarget();
+ if (related != null && getElement().isOrHasChild(related)) {
return;
}
break;
- case Event.ONMOUSEOUT:
- // Only fire the mouse out event if it's actually leaving this
- // widget.
- Element to = event.getToElement();
- if (to != null && getElement().isOrHasChild(to)) {
- return;
- }
}
DomEvent.fireNativeEvent(event, this);
}
-
+
/**
* Removes this widget from its parent widget. If it has no parent, this
* method does nothing.
@@ -113,7 +109,8 @@
* Overridden to defer the call to super.sinkEvents until the first time this
* widget is attached to the dom, as a performance enhancement. Subclasses
* wishing to customize sinkEvents can preserve this deferred sink behavior by
- * putting their implementation behind a check of <code>isOrWasAttached()</code>:
+ * putting their implementation behind a check of
+ * <code>isOrWasAttached()</code>:
*
* <pre>
* {@literal @}Override
@@ -148,7 +145,7 @@
final H handler, DomEvent.Type<H> type) {
assert handler != null : "handler must not be null";
assert type != null : "type must not be null";
- sinkEvents(type.getEventToSink());
+ sinkEvents(Event.getTypeInt(type.getName()));
return ensureHandlers().addHandler(type, handler);
}
diff --git a/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java b/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java
index 5a835f3..4e78056 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImpl.java
@@ -18,6 +18,10 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.ui.Image;
/**
* Uses a combination of a clear image and a background image to clip all except
@@ -54,4 +58,26 @@
return clippedImgHtml;
}
+
+ public void fireSyntheticLoadEvent(final Image image) {
+ /*
+ * We need to synthesize a load event, because the native events that are
+ * fired would correspond to the loading of clear.cache.gif, which is
+ * incorrect. A native event would not even fire in Internet Explorer,
+ * because the root element is a wrapper element around the <img> element.
+ * Since we are synthesizing a load event, we do not need to sink the
+ * onload event.
+ *
+ * We use a deferred command here to simulate the native version of the
+ * load event as closely as possible. In the native event case, it is
+ * unlikely that a second load event would occur while you are in the load
+ * event handler.
+ */
+ DeferredCommand.addCommand(new Command() {
+ public void execute() {
+ NativeEvent evt = Document.get().createLoadEvent();
+ image.getElement().dispatchEvent(evt);
+ }
+ });
+ }
}
diff --git a/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java b/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java
index 6c83175..3666ce8 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/ClippedImageImplIE6.java
@@ -16,7 +16,13 @@
package com.google.gwt.user.client.ui.impl;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Image;
/**
* Implements the clipped image as a IMG inside a custom tag because we can't
@@ -65,6 +71,31 @@
}
@Override
+ public Element createStructure(String url, int left, int top, int width,
+ int height) {
+ // We need to explicitly sink ONLOAD on the child image element, because it
+ // can't be fired on the clipper.
+ Element clipper = super.createStructure(url, left, top, width, height);
+ Element img = clipper.getFirstChildElement();
+ Event.sinkEvents(img, Event.ONLOAD);
+ return clipper;
+ }
+
+ public void fireSyntheticLoadEvent(final Image image) {
+ // This is the same as the superclass' implementation, except that it
+ // explicitly checks for the 'clipper' element, and dispatches the event
+ // on the img (you can't dispatch events on the clipper).
+ DeferredCommand.addCommand(new Command() {
+ public void execute() {
+ NativeEvent evt = Document.get().createLoadEvent();
+ Element clipper = image.getElement();
+ Element img = clipper.getFirstChildElement();
+ img.dispatchEvent(evt);
+ }
+ });
+ }
+
+ @Override
public String getHTML(String url, int left, int top, int width, int height) {
String clipperStyle = "overflow: hidden; width: " + width + "px; height: "
+ height + "px; padding: 0px; zoom: 1";
diff --git a/user/src/com/google/gwt/user/tools/.classpathsrc b/user/src/com/google/gwt/user/tools/.classpathsrc
index d2b73b6..570ab72 100644
--- a/user/src/com/google/gwt/user/tools/.classpathsrc
+++ b/user/src/com/google/gwt/user/tools/.classpathsrc
@@ -2,6 +2,7 @@
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="lib" path="@gwtUserPath"/>
+ <classpathentry kind="lib" path="@gwtDevPath"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
<classpathentry kind="output" path="war/WEB-INF/classes"/>
diff --git a/user/src/com/google/gwt/user/tools/App.launchsrc b/user/src/com/google/gwt/user/tools/App.launchsrc
index 92200c3..b5ea711 100644
--- a/user/src/com/google/gwt/user/tools/App.launchsrc
+++ b/user/src/com/google/gwt/user/tools/App.launchsrc
@@ -6,7 +6,6 @@
<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER" javaProject="@moduleShortName" path="1" type="4"/> "/>
<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry internalArchive="/@moduleShortName/src" path="3" type="2"/> "/>
<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento project="@moduleShortName"/> </runtimeClasspathEntry> "/>
-<listEntry value="<?xml version="1.0" encoding="UTF-8"?> <runtimeClasspathEntry externalArchive="@gwtDevPath" path="3" type="2"/> "/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx256M@vmargs"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-startupUrl @startupUrl @moduleName"/>
diff --git a/user/src/com/google/gwt/user/tools/WebAppCreator.java b/user/src/com/google/gwt/user/tools/WebAppCreator.java
index d324a83..552d454 100644
--- a/user/src/com/google/gwt/user/tools/WebAppCreator.java
+++ b/user/src/com/google/gwt/user/tools/WebAppCreator.java
@@ -24,6 +24,7 @@
import com.google.gwt.user.tools.util.ArgHandlerOverwrite;
import com.google.gwt.user.tools.util.CreatorUtilities;
import com.google.gwt.util.tools.ArgHandlerExtra;
+import com.google.gwt.util.tools.ArgHandlerFlag;
import com.google.gwt.util.tools.ArgHandlerOutDir;
import com.google.gwt.util.tools.Utility;
@@ -55,6 +56,8 @@
registerHandler(new ArgHandlerIgnoreExtension());
registerHandler(new ArgHandlerModuleName());
registerHandler(new ArgHandlerOutDirExtension());
+ registerHandler(new ArgHandlerNoEclipse());
+ registerHandler(new ArgHandlerOnlyEclipse());
}
@Override
@@ -75,10 +78,6 @@
}
}
- /*
- * Arguments for the application creator.
- */
-
private final class ArgHandlerModuleName extends ArgHandlerExtra {
@Override
public boolean addExtraArg(String arg) {
@@ -114,6 +113,52 @@
}
}
+ private final class ArgHandlerNoEclipse extends ArgHandlerFlag {
+ @Override
+ public String getPurpose() {
+ return "Do not generate eclipse files";
+ }
+
+ @Override
+ public String getTag() {
+ return "-XnoEclipse";
+ }
+
+ @Override
+ public boolean isUndocumented() {
+ return true;
+ }
+
+ @Override
+ public boolean setFlag() {
+ noEclipse = true;
+ return true;
+ }
+ }
+
+ private final class ArgHandlerOnlyEclipse extends ArgHandlerFlag {
+ @Override
+ public String getPurpose() {
+ return "Generate only eclipse files";
+ }
+
+ @Override
+ public String getTag() {
+ return "-XonlyEclipse";
+ }
+
+ @Override
+ public boolean isUndocumented() {
+ return true;
+ }
+
+ @Override
+ public boolean setFlag() {
+ onlyEclipse = true;
+ return true;
+ }
+ }
+
private final class ArgHandlerOverwriteExtension extends ArgHandlerOverwrite {
@Override
public boolean setFlag() {
@@ -127,8 +172,8 @@
}
private static final class FileCreator {
- private final String destName;
private final File destDir;
+ private final String destName;
private final String sourceName;
public FileCreator(File destDir, String destName, String sourceName) {
@@ -149,16 +194,19 @@
System.exit(1);
}
+ private boolean ignore = false;
+ private String moduleName;
+ private boolean noEclipse;
+ private boolean onlyEclipse;
+ private File outDir;
+ private boolean overwrite = false;
+
/**
- * @param moduleName name of the fully-qualified GWT module to create as an
- * Application.
- * @param outDir Where to put the output files
- * @param overwrite Overwrite an existing files if they exist.
- * @param ignore Ignore existing files if they exist.
- * @throws IOException
+ * Create the sample app.
+ *
+ * @throws IOException if any disk write fails
*/
- static void createApplication(String moduleName, File outDir,
- boolean overwrite, boolean ignore) throws IOException {
+ protected void doRun() throws IOException {
// Figure out the installation directory
String installPath = Utility.getInstallPath();
@@ -213,24 +261,51 @@
replacements.put("@vmargs", isMacOsX ? " -XstartOnFirstThread" : "");
replacements.put("@renameTo", moduleShortName.toLowerCase());
+ String antEclipseRule = "";
+ if (noEclipse) {
+ /*
+ * Generate a rule into the build file that allows for the generation of
+ * an eclipse project later on. This is primarily for distro samples. This
+ * is a quick and dirty way to inject a build rule, but it works.
+ */
+ antEclipseRule = "\n\n"
+ + " <target name=\"eclipse.generate\" depends=\"libs\" description=\"Generate eclipse project\">\n"
+ + " <java failonerror=\"true\" fork=\"true\" classname=\""
+ + this.getClass().getName() + "\">\n" + " <classpath>\n"
+ + " <path refid=\"project.class.path\"/>\n"
+ + " </classpath>\n" + " <arg value=\"-XonlyEclipse\"/>\n"
+ + " <arg value=\"-ignore\"/>\n" + " <arg value=\""
+ + moduleName + "\"/>\n" + " </java>\n" + " </target>";
+ } else {
+ antEclipseRule = "";
+ }
+ replacements.put("@antEclipseRule", antEclipseRule);
+
List<FileCreator> files = new ArrayList<FileCreator>();
- files.add(new FileCreator(moduleDir, moduleShortName + ".gwt.xml",
- "Module.gwt.xml"));
- files.add(new FileCreator(warDir, moduleShortName + ".html", "AppHtml.html"));
- files.add(new FileCreator(warDir, moduleShortName + ".css", "AppCss.css"));
- files.add(new FileCreator(webInfDir, "web.xml", "web.xml"));
- files.add(new FileCreator(clientDir, moduleShortName + ".java",
- "AppClassTemplate.java"));
- files.add(new FileCreator(clientDir, "EchoService" + ".java",
- "RpcClientTemplate.java"));
- files.add(new FileCreator(clientDir, "EchoServiceAsync" + ".java",
- "RpcAsyncClientTemplate.java"));
- files.add(new FileCreator(serverDir, "EchoServiceImpl" + ".java",
- "RpcServerTemplate.java"));
- files.add(new FileCreator(outDir, "build.xml", "project.ant.xml"));
- files.add(new FileCreator(outDir, ".project", ".project"));
- files.add(new FileCreator(outDir, ".classpath", ".classpath"));
- files.add(new FileCreator(outDir, moduleShortName + ".launch", "App.launch"));
+ if (!onlyEclipse) {
+ files.add(new FileCreator(moduleDir, moduleShortName + ".gwt.xml",
+ "Module.gwt.xml"));
+ files.add(new FileCreator(warDir, moduleShortName + ".html",
+ "AppHtml.html"));
+ files.add(new FileCreator(warDir, moduleShortName + ".css", "AppCss.css"));
+ files.add(new FileCreator(webInfDir, "web.xml", "web.xml"));
+ files.add(new FileCreator(clientDir, moduleShortName + ".java",
+ "AppClassTemplate.java"));
+ files.add(new FileCreator(clientDir, "EchoService" + ".java",
+ "RpcClientTemplate.java"));
+ files.add(new FileCreator(clientDir, "EchoServiceAsync" + ".java",
+ "RpcAsyncClientTemplate.java"));
+ files.add(new FileCreator(serverDir, "EchoServiceImpl" + ".java",
+ "RpcServerTemplate.java"));
+ files.add(new FileCreator(outDir, "build.xml", "project.ant.xml"));
+ }
+ if (!noEclipse) {
+ assert new File(gwtDevPath).isAbsolute();
+ files.add(new FileCreator(outDir, ".project", ".project"));
+ files.add(new FileCreator(outDir, ".classpath", ".classpath"));
+ files.add(new FileCreator(outDir, moduleShortName + ".launch",
+ "App.launch"));
+ }
for (FileCreator fileCreator : files) {
File file = Utility.createNormalFile(fileCreator.destDir,
@@ -247,14 +322,9 @@
}
}
- private boolean ignore = false;
- private String moduleName;
- private File outDir;
- private boolean overwrite = false;
-
protected boolean run() {
try {
- createApplication(moduleName, outDir, overwrite, ignore);
+ doRun();
return true;
} catch (IOException e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
diff --git a/user/src/com/google/gwt/user/tools/project.ant.xmlsrc b/user/src/com/google/gwt/user/tools/project.ant.xmlsrc
index 9b6e4a9..b050e83 100644
--- a/user/src/com/google/gwt/user/tools/project.ant.xmlsrc
+++ b/user/src/com/google/gwt/user/tools/project.ant.xmlsrc
@@ -4,6 +4,7 @@
<path id="project.class.path">
<pathelement location="war/WEB-INF/classes"/>
<pathelement location="@gwtUserPath"/>
+ <pathelement location="@gwtDevPath"/>
<!-- Add any additional non-server libs (such as JUnit) -->
<fileset dir="war/WEB-INF/lib">
<include name="**/*.jar"/>
@@ -32,7 +33,6 @@
<classpath>
<pathelement location="src"/>
<path refid="project.class.path"/>
- <pathelement location="@gwtDevPath"/>
</classpath>
<!-- add jvmarg -Xss16M or similar if you see a StackOverflowError -->
<jvmarg value="-Xmx256M"/>@antVmargs
@@ -45,7 +45,6 @@
<classpath>
<pathelement location="src"/>
<path refid="project.class.path"/>
- <pathelement location="@gwtDevPath"/>
</classpath>
<jvmarg value="-Xmx256M"/>@antVmargs
<arg value="-startupUrl"/>
@@ -53,7 +52,7 @@
<arg value="@moduleName"/>
<!-- Additional arguments like -style PRETTY or -logLevel DEBUG -->
</java>
- </target>
+ </target>@antEclipseRule
<target name="build" depends="gwtc" description="Build this project" />
diff --git a/user/super/com/google/gwt/emul/java/util/Arrays.java b/user/super/com/google/gwt/emul/java/util/Arrays.java
index ed22899..56d1778 100644
--- a/user/super/com/google/gwt/emul/java/util/Arrays.java
+++ b/user/super/com/google/gwt/emul/java/util/Arrays.java
@@ -493,8 +493,10 @@
hash = hashCode((float[]) obj);
} else if (obj instanceof double[]) {
hash = hashCode((double[]) obj);
- } else {
+ } else if (obj != null) {
hash = obj.hashCode();
+ } else {
+ hash = 0;
}
// nasty trick related to JS and lack of integer rollover
diff --git a/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java b/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java
index a975fc4..9d161ce 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java
@@ -95,6 +95,12 @@
new InnerSub().new InnerSubSub().fda();
new SecondMain().new FunkyInner();
+ /*
+ * The statement below causes a javac bug in openJdk and sun's java 6. It
+ * produces incorrect bytecode that fails with a java.lang.VerifyError --
+ * see Google's internal issue 1628473. This is likely to be an hindrance
+ * if and when GWT attempts to read bytecode directly.
+ */
new NamedLocal().new NamedLocalSub().foo();
}
diff --git a/user/test/com/google/gwt/dev/shell/rewrite/client/EmmaClassLoadingTest.java b/user/test/com/google/gwt/dev/shell/rewrite/client/EmmaClassLoadingTest.java
index 35250a3..8d6eb5b 100644
--- a/user/test/com/google/gwt/dev/shell/rewrite/client/EmmaClassLoadingTest.java
+++ b/user/test/com/google/gwt/dev/shell/rewrite/client/EmmaClassLoadingTest.java
@@ -16,6 +16,9 @@
package com.google.gwt.dev.shell.rewrite.client;
import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.Timer;
+
+import junit.framework.TestCase;
/**
* Test-case to check if the jsni blocks are mapped correctly between the
@@ -31,7 +34,7 @@
*/
public class EmmaClassLoadingTest extends GWTTestCase {
- enum EnumTest {
+ enum EnumClass {
A, B, C,
}
@@ -40,7 +43,7 @@
}
private static String messages[] = {
- "a foo", "b foo", "enum A", "d foo", "e foo"};
+ "1a foo", "1b foo", "1enum A", "1d foo", "1e foo"};
private static int logCount = 0;
@@ -56,14 +59,14 @@
public void test1() {
TestInterface a = new TestInterface() {
public void foo() {
- log("a foo");
+ log("1a foo");
}
};
a.foo();
TestInterface b = new TestInterface() {
public native void foo() /*-{
- @com.google.gwt.dev.shell.rewrite.client.EmmaClassLoadingTest::log(Ljava/lang/String;)("b foo");
+ @com.google.gwt.dev.shell.rewrite.client.EmmaClassLoadingTest::log(Ljava/lang/String;)("1b foo");
}-*/;
};
b.foo();
@@ -75,10 +78,10 @@
}-*/;
};
}
- EnumTest et = EnumTest.A;
+ EnumClass et = EnumClass.A;
switch (et) {
case A:
- log("enum A");
+ log("1enum A");
break;
case B:
log("ANY_FOO_2");
@@ -90,7 +93,7 @@
TestInterface d = new TestInterface() {
public native void foo() /*-{
- @com.google.gwt.dev.shell.rewrite.client.EmmaClassLoadingTest::log(Ljava/lang/String;)("d foo");
+ @com.google.gwt.dev.shell.rewrite.client.EmmaClassLoadingTest::log(Ljava/lang/String;)("1d foo");
}-*/;
};
d.foo();
@@ -103,8 +106,193 @@
*/
TestInterface e = new TestInterface() {
public native void foo() /*-{
- @com.google.gwt.dev.shell.rewrite.client.EmmaClassLoadingTest::log(Ljava/lang/String;)("e foo");
+ @com.google.gwt.dev.shell.rewrite.client.EmmaClassLoadingTest::log(Ljava/lang/String;)("1e foo");
}-*/;
};
- }
+ }
+
+ public void test2() {
+ SecondTopLevelClass second = new SecondTopLevelClass();
+ SecondTopLevelClass.InnerClass.test();
+ }
+
+ public void test3() {
+ ThirdTopLevelClass third = new ThirdTopLevelClass();
+ third.test();
+ }
+
+ public void test4() {
+ FourthTopLevelClass fourth = new FourthTopLevelClass();
+ fourth.test();
+ }
+
+}
+
+/**
+ * Check that the algorithm correctly maps named inner classes. In this example,
+ * jdt generates $1Foo and $2Foo whereas javac generates $2Foo and $3Foo.
+ *
+ */
+class FourthTopLevelClass extends TestCase {
+ private static String messages[] = {"4a foo"};
+
+ private static int logCount = 0;
+
+ private static void log(String msg) {
+ assertEquals(messages[logCount++], msg);
+ }
+
+ void test() {
+ test1();
+ test2();
+ };
+
+ private void test1() {
+ if (false) {
+ class Foo {
+ public native void foo() /*-{
+ @com.google.gwt.dev.shell.rewrite.client.FourthTopLevelClass::log(Ljava/lang/String;)("ANY_FOO");
+ }-*/;
+ }
+ new Foo().foo();
+ }
+ }
+
+ private void test2() {
+ class Foo {
+ public native void foo() /*-{
+ @com.google.gwt.dev.shell.rewrite.client.FourthTopLevelClass::log(Ljava/lang/String;)("4a foo");
+ }-*/;
+ }
+ new Foo().foo();
+ }
+
+ /*
+ * Added a test3() method so that when the test fails, it fails quickly.
+ * Instead of timing out, the AssertEquals fails
+ */
+ private void test3() {
+ class Foo {
+ public native void foo() /*-{
+ @com.google.gwt.dev.shell.rewrite.client.FourthTopLevelClass::log(Ljava/lang/String;)("4b foo");
+ }-*/;
+ }
+ new Foo().foo();
+ }
+}
+
+/**
+ * Check if GWT is able to correctly compile cases when there are multiple
+ * top-level classes and when there is a need to traverse inner classes. This
+ * class's test method simply mirrors the test methods of EmmaClassLoadingTest.
+ *
+ */
+class SecondTopLevelClass extends TestCase {
+
+ static class InnerClass {
+ /**
+ * Test that mapping is constructed for something which is not in the main
+ * unit as well.
+ */
+ static void test() {
+ EmmaClassLoadingTest.TestInterface a = new EmmaClassLoadingTest.TestInterface() {
+ public void foo() {
+ log("2a foo");
+ }
+ };
+ a.foo();
+
+ EmmaClassLoadingTest.TestInterface b = new EmmaClassLoadingTest.TestInterface() {
+ public native void foo() /*-{
+ @com.google.gwt.dev.shell.rewrite.client.SecondTopLevelClass::log(Ljava/lang/String;)("2b foo");
+ }-*/;
+ };
+ b.foo();
+
+ if (false) {
+ EmmaClassLoadingTest.TestInterface c = new EmmaClassLoadingTest.TestInterface() {
+ public native void foo() /*-{
+ @com.google.gwt.dev.shell.rewrite.client.SecondTopLevelClass::log(Ljava/lang/String;)("ANY_FOO_1");
+ }-*/;
+ };
+ }
+ EmmaClassLoadingTest.EnumClass et = EmmaClassLoadingTest.EnumClass.A;
+ switch (et) {
+ case A:
+ log("2enum A");
+ break;
+ case B:
+ log("ANY_FOO_2");
+ break;
+ case C:
+ log("ANY_FOO_3");
+ break;
+ }
+
+ EmmaClassLoadingTest.TestInterface d = new EmmaClassLoadingTest.TestInterface() {
+ public native void foo() /*-{
+ @com.google.gwt.dev.shell.rewrite.client.SecondTopLevelClass::log(Ljava/lang/String;)("2d foo");
+ }-*/;
+ };
+ d.foo();
+
+ /*
+ * jdt generates $1 (a), $2 (b), $3 (d), $4 (e). javac generates $1 (a),
+ * $2 (b), $3 (c), $4 (d), $5 (e), $6 (synthetic). Added e so that the
+ * test fails quickly. Otherwise, it had to wait for a time-out (in
+ * looking through jdt generated code for non-existent jsni methods of $4)
+ * to fail.
+ */
+ EmmaClassLoadingTest.TestInterface e = new EmmaClassLoadingTest.TestInterface() {
+ public native void foo() /*-{
+ @com.google.gwt.dev.shell.rewrite.client.SecondTopLevelClass::log(Ljava/lang/String;)("2e foo");
+ }-*/;
+ };
+ }
+ }
+
+ private static String messages[] = {
+ "2a foo", "2b foo", "2enum A", "2d foo", "2e foo"};
+
+ private static int logCount = 0;
+
+ private static void log(String msg) {
+ assertEquals(messages[logCount++], msg);
+ }
+}
+
+/**
+ * Check that the mapping algorithm is not confused by the presence of other
+ * inner classes.
+ */
+class ThirdTopLevelClass extends TestCase {
+
+ private static String messages[] = {"3a foo"};
+
+ private static int logCount = 0;
+
+ private static void log(String msg) {
+ assertEquals(messages[logCount++], msg);
+ }
+
+ void test() {
+ Timer t1 = new Timer() {
+ @Override
+ public void run() {
+ }
+ };
+
+ EmmaClassLoadingTest.TestInterface a = new EmmaClassLoadingTest.TestInterface() {
+ public native void foo() /*-{
+ @com.google.gwt.dev.shell.rewrite.client.ThirdTopLevelClass::log(Ljava/lang/String;)("3a foo");
+ }-*/;
+ };
+ a.foo();
+
+ Timer t2 = new Timer() {
+ @Override
+ public void run() {
+ }
+ };
+ }
}
diff --git a/user/test/com/google/gwt/event/shared/HandlerTestBase.java b/user/test/com/google/gwt/event/shared/HandlerTestBase.java
index 303ff12..80e551b 100644
--- a/user/test/com/google/gwt/event/shared/HandlerTestBase.java
+++ b/user/test/com/google/gwt/event/shared/HandlerTestBase.java
@@ -29,6 +29,7 @@
*/
public abstract class HandlerTestBase extends GWTTestCase {
+ @Override
public String getModuleName() {
return "com.google.gwt.event.Event";
}
diff --git a/user/test/com/google/gwt/json/client/JSONTest.java b/user/test/com/google/gwt/json/client/JSONTest.java
index de9f9f0..c10751f 100644
--- a/user/test/com/google/gwt/json/client/JSONTest.java
+++ b/user/test/com/google/gwt/json/client/JSONTest.java
@@ -55,14 +55,14 @@
private static void assertJSONObjectEquals(JSONObject expected,
JSONObject actual) {
Set<String> actKeys = actual.keySet();
- for (String key : expected.keySet()) {
- actKeys.remove(key);
+ Set<String> expKeys = expected.keySet();
+ assertEquals(expKeys.size(), actKeys.size());
+ for (String key : expKeys) {
assertTrue(actual.containsKey(key));
JSONValue expValue = expected.get(key);
JSONValue actValue = actual.get(key);
assertJSONValueEquals(expValue, actValue);
}
- assertEquals(0, actKeys.size());
}
private static void assertJSONValueEquals(JSONValue expected, JSONValue actual) {
diff --git a/user/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java
index c7483be..716c5ee 100644
--- a/user/test/com/google/gwt/user/UISuite.java
+++ b/user/test/com/google/gwt/user/UISuite.java
@@ -23,9 +23,11 @@
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.ButtonTest;
import com.google.gwt.user.client.ui.CaptionPanelTest;
import com.google.gwt.user.client.ui.CheckBoxTest;
import com.google.gwt.user.client.ui.CompositeTest;
+import com.google.gwt.user.client.ui.CreateEventTest;
import com.google.gwt.user.client.ui.CustomButtonTest;
import com.google.gwt.user.client.ui.DOMTest;
import com.google.gwt.user.client.ui.DateBoxTest;
@@ -95,6 +97,7 @@
suite.addTestSuite(AbsolutePanelTest.class);
suite.addTestSuite(AnchorTest.class);
suite.addTestSuite(AsyncProxyTest.class);
+ suite.addTestSuite(ButtonTest.class);
suite.addTestSuite(CaptionPanelTest.class);
suite.addTestSuite(CheckBoxTest.class);
suite.addTestSuite(ClippedImagePrototypeTest.class);
@@ -160,6 +163,7 @@
suite.addTestSuite(XMLTest.class);
suite.addTestSuite(ClassInitTest.class);
suite.addTestSuite(DateChangeEventTest.class);
+ suite.addTestSuite(CreateEventTest.class);
return suite;
}
}
diff --git a/user/test/com/google/gwt/user/client/ui/ButtonTest.java b/user/test/com/google/gwt/user/client/ui/ButtonTest.java
new file mode 100644
index 0000000..83777e7
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/ButtonTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.ui;
+
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests for {@link Button}.
+ */
+public class ButtonTest extends GWTTestCase {
+
+ public String getModuleName() {
+ return "com.google.gwt.user.User";
+ }
+
+ private class H implements ClickHandler {
+ boolean clicked;
+ Element target;
+
+ public void onClick(ClickEvent event) {
+ target = event.getNativeEvent().getTarget();
+ clicked = true;
+ }
+ }
+
+ public void testClick() {
+ Button b = new Button();
+ RootPanel.get().add(b);
+
+ H h = new H();
+ b.addClickHandler(h);
+
+ b.click();
+ assertTrue(h.clicked);
+
+ // Old Mozilla browsers don't set up the event target properly for
+ // synthesized clicks. This tests the workaround in DOMImplMozillaOld.
+ assertEquals(b.getElement(), h.target);
+ }
+}
+
diff --git a/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java b/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java
index 95fb16c..2a4ed97 100644
--- a/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java
+++ b/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java
@@ -96,6 +96,14 @@
assertEquals("valuable", cb.getFormValue());
}
+ public void testConstructorInputElement() {
+ InputElement elm = DOM.createInputCheck().cast();
+ CheckBox box = new CheckBox(elm.<Element> cast());
+ assertFalse(box.getValue());
+ elm.setDefaultChecked(true);
+ assertTrue(box.getValue());
+ }
+
public void testDebugId() {
CheckBox check = new CheckBox("myLabel");
@@ -111,42 +119,18 @@
UIObjectTest.assertDebugIdContents("myCheck-label", "myLabel");
}
- public void testConstructorInputElement() {
+ /**
+ * Tests that detaching and attaching a CheckBox widget retains the checked
+ * state of the element. This is known to be tricky on IE.
+ */
+ public void testDetachment() {
InputElement elm = DOM.createInputCheck().cast();
CheckBox box = new CheckBox(elm.<Element> cast());
- assertFalse(box.getValue());
- elm.setDefaultChecked(true);
- assertTrue(box.getValue());
- }
-
- public void testReplaceInputElement() {
- cb.setValue(true);
- cb.setTabIndex(1234);
- cb.setEnabled(false);
- cb.setAccessKey('k');
- cb.setFormValue("valuable");
-
- InputElement elm = Document.get().createCheckInputElement();
- assertFalse(elm.isChecked());
-
- Element asOldElement = elm.cast();
- cb.replaceInputElement(asOldElement);
-
- // The values should be preserved
- assertTrue(cb.getValue());
- assertEquals(1234, cb.getTabIndex());
- assertFalse(cb.isEnabled());
- assertEquals("k", elm.getAccessKey());
- assertEquals("valuable", cb.getFormValue());
-
- assertTrue(elm.isChecked());
- cb.setValue(false);
- assertFalse(elm.isChecked());
-
+ RootPanel.get().add(box);
elm.setChecked(true);
- assertTrue(cb.getValue());
-
- // TODO: When event creation is in, test that click on the new element works
+ RootPanel.get().remove(box);
+ RootPanel.get().add(box);
+ assertTrue(elm.isChecked());
}
public void testFormValue() {
@@ -182,6 +166,36 @@
assertEquals(ListenerTester.fired, 0);
}
+ public void testReplaceInputElement() {
+ cb.setValue(true);
+ cb.setTabIndex(1234);
+ cb.setEnabled(false);
+ cb.setAccessKey('k');
+ cb.setFormValue("valuable");
+
+ InputElement elm = Document.get().createCheckInputElement();
+ assertFalse(elm.isChecked());
+
+ Element asOldElement = elm.cast();
+ cb.replaceInputElement(asOldElement);
+
+ // The values should be preserved
+ assertTrue(cb.getValue());
+ assertEquals(1234, cb.getTabIndex());
+ assertFalse(cb.isEnabled());
+ assertEquals("k", elm.getAccessKey());
+ assertEquals("valuable", cb.getFormValue());
+
+ assertTrue(elm.isChecked());
+ cb.setValue(false);
+ assertFalse(elm.isChecked());
+
+ elm.setChecked(true);
+ assertTrue(cb.getValue());
+
+ // TODO: When event creation is in, test that click on the new element works
+ }
+
@SuppressWarnings("deprecation")
public void testValueChangeEvent() {
Handler h = new Handler();
diff --git a/user/test/com/google/gwt/user/client/ui/CreateEventTest.java b/user/test/com/google/gwt/user/client/ui/CreateEventTest.java
new file mode 100644
index 0000000..9029f94
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/CreateEventTest.java
@@ -0,0 +1,572 @@
+/*
+ * 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.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.dom.client.ImageElement;
+import com.google.gwt.dom.client.InputElement;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.EventListener;
+
+/**
+ * Tests for the native event triggering methods in {@link Event}.
+ */
+public class CreateEventTest extends GWTTestCase {
+
+ /**
+ * Listener for use with key[down up press].
+ */
+ private class KeyEventListener extends BubbleAssertingEventListener {
+ public KeyEventListener(String eventType) {
+ super(eventType);
+ }
+
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ assertAllShiftKeysOn(event);
+ assertEquals(KEY_CODE, event.getKeyCode());
+ }
+ }
+
+ /**
+ * Listener for use with mouse[down up move over out].
+ */
+ private class MouseEventListener extends BubbleAssertingEventListener {
+ public MouseEventListener(String eventType) {
+ super(eventType);
+ }
+
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ assertMouseCoordinates(event);
+ assertAllShiftKeysOn(event);
+ assertEquals(Event.BUTTON_LEFT, event.getButton());
+ }
+ }
+
+ /**
+ * An event listener that asserts that the event is passed to child, then
+ * parent.
+ */
+ private class BubbleAssertingEventListener implements EventListener {
+ public boolean parentReceived, childReceived;
+ private final String eventType;
+
+ public BubbleAssertingEventListener(String eventType) {
+ this.eventType = eventType;
+ }
+
+ public void onBrowserEvent(Event event) {
+ assertEquals(eventType, event.getType());
+
+ Element target = event.getCurrentTarget();
+ if (target == child) {
+ assertFalse("Expecting child to receive the event only once",
+ childReceived);
+ assertFalse("Expecting child to receive the event before parent",
+ parentReceived);
+
+ childReceived = true;
+ } else if (target == parent) {
+ assertFalse("Expecting parent to receive the event only once",
+ parentReceived);
+ assertTrue("Expecting parent to receive the event after the child",
+ childReceived);
+
+ parentReceived = true;
+ }
+ }
+ }
+
+ /**
+ * Used with {@link CreateEventTest#testGetCurrentEvent()}.
+ */
+ private static class CurrentEventListener implements EventListener {
+ public boolean gotClick, gotKeyPress, gotFocus;
+
+ public void onBrowserEvent(Event event) {
+ switch (Event.getCurrentEvent().getTypeInt()) {
+ case Event.ONCLICK:
+ gotClick = true;
+ break;
+ case Event.ONKEYPRESS:
+ gotKeyPress = true;
+ break;
+ case Event.ONFOCUS:
+ gotFocus = true;
+ break;
+ }
+ }
+ }
+
+ /**
+ * An event listener that asserts that the event is passed only to child.
+ */
+ private class NonBubbleAssertingEventListener implements EventListener {
+ private boolean childReceived;
+ private String eventType;
+
+ public NonBubbleAssertingEventListener(String eventType) {
+ this.eventType = eventType;
+ }
+
+ public void onBrowserEvent(Event event) {
+ assertEquals(eventType, event.getType());
+
+ if (event.getTarget() == child) {
+ assertFalse("Expecting child to receive the event only once",
+ childReceived);
+ childReceived = true;
+ } else if (event.getTarget() == parent) {
+ fail("Not expecting parent to receive the event");
+ }
+ }
+
+ protected String getEventType() {
+ return eventType;
+ }
+ }
+
+ /**
+ * An event listener that asserts that events are received properly for the
+ * img element.
+ */
+ private class ImgEventListener implements EventListener {
+ private boolean imgReceived;
+ private final String eventType;
+
+ public ImgEventListener(String eventType) {
+ this.eventType = eventType;
+ }
+
+ public void onBrowserEvent(Event event) {
+ if (event.getType().equals(eventType)) {
+ if (event.getTarget() == img) {
+ assertFalse("Expecting img to receive the event only once",
+ imgReceived);
+
+ imgReceived = true;
+ } else if (event.getTarget() == parent) {
+ fail("Not expecting parent to receive the event");
+ }
+ }
+ }
+ }
+
+ private static final int MOUSE_DETAIL = 1;
+ private static final int CLIENT_X = 2;
+ private static final int CLIENT_Y = 3;
+ private static final int SCREEN_X = 4;
+ private static final int SCREEN_Y = 5;
+ private static final int KEY_CODE = 'A';
+
+ private static final int ALL_EVENTS = Event.MOUSEEVENTS | Event.KEYEVENTS
+ | Event.FOCUSEVENTS | Event.ONCHANGE | Event.ONCLICK | Event.ONDBLCLICK
+ | Event.ONCONTEXTMENU | Event.ONLOAD | Event.ONERROR | Event.ONSCROLL;
+ private static DivElement parent;
+ private static InputElement child;
+ private static ImageElement img;
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.UserTest";
+ }
+
+ /**
+ * Tests that {@link Event#getCurrentEvent()} returns the right value for
+ * synthesized events.
+ */
+ public void testGetCurrentEvent() {
+ CurrentEventListener listener = new CurrentEventListener();
+ Event.setEventListener(child, listener);
+
+ // Test all three major event types.
+ child.dispatchEvent(Document.get().createClickEvent(0, 0, 0, 0, 0, false,
+ false, false, false));
+ child.dispatchEvent(Document.get().createKeyPressEvent(false, false, false,
+ false, 65, 65));
+ child.dispatchEvent(Document.get().createFocusEvent());
+
+ assertTrue("Expecting click as current event", listener.gotClick);
+ assertTrue("Expecting keypress as current event", listener.gotKeyPress);
+ assertTrue("Expecting focus as current event", listener.gotFocus);
+ }
+
+ /**
+ * Tests NativeEvent.stopPropagation()
+ */
+ public void testStopPropagation() {
+ NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
+ "click") {
+ @Override
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ if (event.getCurrentTarget() == child) {
+ event.stopPropagation();
+ }
+ }
+ };
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createClickEvent(MOUSE_DETAIL, SCREEN_X,
+ SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true));
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ }
+
+ /**
+ * Tests createBlurEvent().
+ */
+ public void testTriggerBlurEvent() {
+ NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
+ "blur") {
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ assertEquals("blur", event.getType());
+ }
+ };
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createBlurEvent());
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ }
+
+ /**
+ * Tests createChangeEvent().
+ */
+ public void testTriggerChangeEvent() {
+ BubbleAssertingEventListener listener = new BubbleAssertingEventListener(
+ "change");
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createChangeEvent());
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ }
+
+ /**
+ * Tests createClickEvent().
+ */
+ public void testTriggerClickEvent() {
+ BubbleAssertingEventListener listener = new BubbleAssertingEventListener(
+ "click") {
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ assertMouseCoordinates(event);
+ assertAllShiftKeysOn(event);
+ }
+ };
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createClickEvent(MOUSE_DETAIL, SCREEN_X,
+ SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true));
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ assertTrue("Expected parent to receive event", listener.parentReceived);
+ }
+
+ /**
+ * Tests createContextMenuEvent().
+ * TODO: Re-enable this test when we no longer support Firefox2 and earlier
+ * (which doesn't appear to dispatch contextmenu events properly).
+ */
+// public void testTriggerContextMenuEvent() {
+// BubbleAssertingEventListener listener = new BubbleAssertingEventListener(
+// "contextmenu");
+// Event.setEventListener(parent, listener);
+// Event.setEventListener(child, listener);
+//
+// child.dispatchEvent(Document.get().createContextMenuEvent());
+//
+// assertTrue("Expected child to receive event", listener.childReceived);
+// assertTrue("Expected parent to receive event", listener.parentReceived);
+// }
+
+ /**
+ * Tests createDblClickEvent().
+ */
+ public void testTriggerDblClickEvent() {
+ BubbleAssertingEventListener listener = new BubbleAssertingEventListener(
+ "dblclick") {
+ public void onBrowserEvent(Event event) {
+ if (event.getTypeInt() == Event.ONCLICK) {
+ // Some browsers (IE, I'm looking at you) synthesize an extra click
+ // event when a double-click is triggered. This synthesized click
+ // will *not* have the same properties as the dblclick, so we will
+ // not try to assert them here.
+ return;
+ }
+
+ super.onBrowserEvent(event);
+ assertMouseCoordinates(event);
+ assertAllShiftKeysOn(event);
+ }
+ };
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createDblClickEvent(MOUSE_DETAIL,
+ SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true));
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ assertTrue("Expected parent to receive event", listener.parentReceived);
+ }
+
+ /**
+ * Tests createErrorEvent().
+ */
+ public void testTriggerErrorEvent() {
+ ImgEventListener listener = new ImgEventListener("error");
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(img, listener);
+
+ img.dispatchEvent(Document.get().createErrorEvent());
+
+ assertTrue("Expected child to receive event", listener.imgReceived);
+ }
+
+ /**
+ * Tests createFocusEvent().
+ */
+ public void testTriggerFocusEvent() {
+ NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
+ "focus") {
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ assertEquals("focus", event.getType());
+ }
+ };
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createFocusEvent());
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ }
+
+ /**
+ * Tests createKeyDownEvent().
+ */
+ public void testTriggerKeyDownEvent() {
+ KeyEventListener listener = new KeyEventListener("keydown");
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createKeyDownEvent(true, true, true,
+ true, KEY_CODE, KEY_CODE));
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ assertTrue("Expected parent to receive event", listener.parentReceived);
+ }
+
+ /**
+ * Tests createKeyPressEvent().
+ */
+ public void testTriggerKeyPressEvent() {
+ KeyEventListener listener = new KeyEventListener("keypress");
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createKeyPressEvent(true, true, true,
+ true, KEY_CODE, KEY_CODE));
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ assertTrue("Expected parent to receive event", listener.parentReceived);
+ }
+
+ /**
+ * Tests createKeyUpEvent().
+ */
+ public void testTriggerKeyUpEvent() {
+ KeyEventListener listener = new KeyEventListener("keyup");
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createKeyUpEvent(true, true, true, true,
+ KEY_CODE, KEY_CODE));
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ assertTrue("Expected parent to receive event", listener.parentReceived);
+ }
+
+ /**
+ * Tests createLoadEvent().
+ */
+ public void testTriggerLoadEvent() {
+ ImgEventListener listener = new ImgEventListener("load");
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(img, listener);
+
+ img.dispatchEvent(Document.get().createLoadEvent());
+
+ assertTrue("Expected img to receive event", listener.imgReceived);
+ }
+
+ /**
+ * Tests createMouseDownEvent().
+ */
+ public void testTriggerMouseDownEvent() {
+ MouseEventListener listener = new MouseEventListener("mousedown");
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createMouseDownEvent(MOUSE_DETAIL,
+ SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true,
+ Event.BUTTON_LEFT));
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ assertTrue("Expected parent to receive event", listener.parentReceived);
+ }
+
+ /**
+ * Tests createMouseMoveEvent().
+ */
+ public void testTriggerMouseMoveEvent() {
+ MouseEventListener listener = new MouseEventListener("mousemove");
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createMouseMoveEvent(MOUSE_DETAIL,
+ SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true,
+ Event.BUTTON_LEFT));
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ assertTrue("Expected parent to receive event", listener.parentReceived);
+ }
+
+ /**
+ * Tests createMouseOutEvent().
+ */
+ public void testTriggerMouseOutEvent() {
+ MouseEventListener listener = new MouseEventListener("mouseout") {
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+
+// TODO: Re-enable this assertion when we no longer support Firefox2 and earlier.
+// Old Firefoxen throw away the relatedTarget parameter of initMouseEvent().
+// Element relatedTarget = event.getRelatedTarget();
+// assertEquals("Expected relatedElement to be img", img, relatedTarget);
+ }
+ };
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createMouseOutEvent(MOUSE_DETAIL,
+ SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true,
+ Event.BUTTON_LEFT, img));
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ assertTrue("Expected parent to receive event", listener.parentReceived);
+ }
+
+ /**
+ * Tests createMouseOverEvent().
+ */
+ public void testTriggerMouseOverEvent() {
+ MouseEventListener listener = new MouseEventListener("mouseover") {
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+
+// TODO: Re-enable this assertion when we no longer support Firefox2 and earlier.
+// Old Firefoxen throw away the relatedTarget parameter of initMouseEvent().
+// Element relatedTarget = event.getRelatedTarget();
+// assertEquals("Expected relatedElement to be img", img, relatedTarget);
+ }
+ };
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createMouseOverEvent(MOUSE_DETAIL, SCREEN_X, SCREEN_Y,
+ CLIENT_X, CLIENT_Y, true, true, true, true, Event.BUTTON_LEFT, img));
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ assertTrue("Expected parent to receive event", listener.parentReceived);
+ }
+
+ /**
+ * Tests createMouseUpEvent().
+ */
+ public void testTriggerMouseUpEvent() {
+ MouseEventListener listener = new MouseEventListener("mouseup");
+ Event.setEventListener(parent, listener);
+ Event.setEventListener(child, listener);
+
+ child.dispatchEvent(Document.get().createMouseUpEvent(MOUSE_DETAIL,
+ SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true,
+ Event.BUTTON_LEFT));
+
+ assertTrue("Expected child to receive event", listener.childReceived);
+ assertTrue("Expected parent to receive event", listener.parentReceived);
+ }
+
+ /**
+ * Tests createScrollEvent().
+ * TODO: Re-enable this test when we no longer support Firefox2 and earlier
+ * (which doesn't appear to dispatch contextmenu events properly).
+ */
+// public void testTriggerScrollEvent() {
+// NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
+// "scroll") {
+// public void onBrowserEvent(Event event) {
+// super.onBrowserEvent(event);
+// assertEquals("scroll", event.getType());
+// }
+// };
+// Event.setEventListener(parent, listener);
+// Event.setEventListener(child, listener);
+//
+// child.dispatchEvent(Document.get().createScrollEvent());
+//
+// assertTrue("Expected child to receive event", listener.childReceived);
+// }
+
+ @Override
+ protected void gwtSetUp() throws Exception {
+ parent = Document.get().createDivElement();
+ child = Document.get().createTextInputElement();
+ img = Document.get().createImageElement();
+
+ Document.get().getBody().appendChild(parent);
+ parent.appendChild(child);
+ parent.appendChild(img);
+
+ Event.sinkEvents(parent, ALL_EVENTS);
+ Event.sinkEvents(child, ALL_EVENTS);
+ Event.sinkEvents(img, ALL_EVENTS);
+ }
+
+ private void assertAllShiftKeysOn(Event event) {
+ assertEquals("Expecting ctrl on", true, event.getCtrlKey());
+ assertEquals("Expecting alt on", true, event.getAltKey());
+ assertEquals("Expecting shift on", true, event.getShiftKey());
+ assertEquals("Expecting meta on", true, event.getMetaKey());
+ }
+
+ private void assertMouseCoordinates(Event event) {
+ assertEquals("clientX", CLIENT_X, event.getClientX());
+ assertEquals("clientY", CLIENT_Y, event.getClientY());
+ assertEquals("screenX", SCREEN_X, event.getScreenX());
+ assertEquals("screenY", SCREEN_Y, event.getScreenY());
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java b/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java
index 5593cfa..ebe60ca 100644
--- a/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java
+++ b/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java
@@ -16,18 +16,23 @@
package com.google.gwt.user.client.ui;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.CustomButton.Face;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
/**
- * Test for <code>PushButton</code> as most of this widget's functionality is
- * UI based, the primary test will be in the new UI testing framework once it is
+ * Test for <code>PushButton</code> as most of this widget's functionality is UI
+ * based, the primary test will be in the new UI testing framework once it is
* released.
*
*/
@@ -154,4 +159,31 @@
assertFalse(b.isDown());
assertFalse(b.isEnabled());
}
+
+ public void testSyntheticClick() {
+ PushButton b = new PushButton();
+ final ArrayList<String> events = new ArrayList<String>();
+
+ b.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ events.add(event.getNativeEvent().getType());
+ }
+ });
+
+ RootPanel.get().add(b);
+
+ // Synthesize over/down/up events, which should kick off CustomButton's
+ // internal machinery to synthesize a click.
+ b.getElement().dispatchEvent(
+ Document.get().createMouseOverEvent(1, 0, 0, 0, 0, false, false, false,
+ false, Event.BUTTON_LEFT, null));
+ b.getElement().dispatchEvent(
+ Document.get().createMouseDownEvent(1, 0, 0, 0, 0, false, false, false,
+ false, Event.BUTTON_LEFT));
+ b.getElement().dispatchEvent(
+ Document.get().createMouseUpEvent(1, 0, 0, 0, 0, false, false, false,
+ false, Event.BUTTON_LEFT));
+ assertEquals("Expecting one click event", 1, events.size());
+ assertEquals("Expecting one click event", "click", events.get(0));
+ }
}
diff --git a/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java b/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
index 04a9127..ef908a6 100644
--- a/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
+++ b/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.user.client.ui;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
@@ -68,6 +70,20 @@
assertEquals("text", dialogBox.getText());
assertTrue(dialogBox.getHTML().equalsIgnoreCase("<b>text</b>"));
}
+
+ public void testSimpleCloseButtonOnModalDialog() {
+ final DialogBox dialogBox = new DialogBox(false, true);
+ Button button = new Button();
+ button.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ dialogBox.hide();
+ }
+ });
+ dialogBox.add(button);
+ dialogBox.show();
+ button.click();
+ assertFalse(dialogBox.isShowing());
+ }
public void testDebugId() {
DialogBox dBox = new DialogBox();
@@ -86,7 +102,6 @@
// Check the header IDs
DeferredCommand.addCommand(new Command() {
public void execute() {
- String prefix = UIObject.DEBUG_ID_PREFIX;
UIObjectTest.assertDebugIdContents("myDialogBox-caption",
"test caption");
finishTest();
diff --git a/user/test/com/google/gwt/user/client/ui/impl/ClippedImagePrototypeTest.java b/user/test/com/google/gwt/user/client/ui/impl/ClippedImagePrototypeTest.java
index e305a2e..7480a84 100644
--- a/user/test/com/google/gwt/user/client/ui/impl/ClippedImagePrototypeTest.java
+++ b/user/test/com/google/gwt/user/client/ui/impl/ClippedImagePrototypeTest.java
@@ -82,7 +82,6 @@
* is called.
*/
public void testApplyToClippedImage() {
-
final Image image = new Image("counting-backwards.png", 12, 13, 8, 8);
assertEquals(12, image.getOriginLeft());
@@ -91,27 +90,6 @@
assertEquals(8, image.getHeight());
assertEquals("clipped", ImageTest.getCurrentImageStateName(image));
- final TestLoadListener listener = new TestLoadListener(image) {
- @Override
- public void onLoad(Widget sender) {
- super.onLoad(sender);
-
- if (image.getOriginLeft() == 12 && image.getOriginTop() == 13) {
- ClippedImagePrototype clippedImagePrototype = new ClippedImagePrototype(
- "counting-forwards.png", 16, 16, 16, 16);
-
- clippedImagePrototype.applyTo(image);
-
- assertEquals(16, image.getOriginLeft());
- assertEquals(16, image.getOriginTop());
- assertEquals(16, image.getWidth());
- assertEquals(16, image.getHeight());
- assertEquals("clipped", ImageTest.getCurrentImageStateName(image));
- }
- }
- };
- image.addLoadListener(listener);
-
final TestLoadHandler handler = new TestLoadHandler() {
@Override
public void onLoad(LoadEvent event) {
@@ -137,14 +115,13 @@
fail("The image " + image.getUrl() + " failed to load.");
}
});
-
+
RootPanel.get().add(image);
delayTestFinish(2000);
Timer t = new Timer() {
@Override
public void run() {
- assertEquals(2, listener.getOnloadEventFireCount());
assertEquals(2, handler.getOnloadEventFireCount());
finishTest();
}