Merging releases/1.5@r2994:r3048 into trunk.
svn merge -r 2994:3048 https://google-web-toolkit.googlecode.com/svn/releases/1.5 .
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@3050 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/HostedModeTemplate.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/HostedModeTemplate.js
index 456e5da..8f2c3b9 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/HostedModeTemplate.js
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/HostedModeTemplate.js
@@ -21,7 +21,7 @@
var $wnd = window
,$doc = document
,external = $wnd.external
- ,$stats = $wnd.__gwt_stats || null
+ ,$stats = $wnd.__gwtStatsEvent ? function(a) {return $wnd.__gwtStatsEvent(a);} : null
// These variables gate calling gwtOnLoad; all must be true to start
,scriptsDone, loadDone, bodyDone
@@ -47,8 +47,17 @@
; // end of global vars
- // Record startup timing information
- $stats && $stats('__MODULE_NAME__', 'startup', 'hostedModeSelectionStart', {millis:(new Date()).getTime()});
+ // Only fire the event if really hosted mode; in web mode the compiled
+ // selection script will fire its own startup event.
+ if (isHostedMode()) {
+ $stats && $stats({
+ moduleName: '__MODULE_NAME__',
+ subSystem: 'startup',
+ evtGroup: 'bootstrap',
+ millis:(new Date()).getTime(),
+ type: 'begin'
+ });
+ }
// ------------------ TRUE GLOBALS ------------------
@@ -88,10 +97,16 @@
}
// remove this whole function from the global namespace to allow GC
__MODULE_FUNC__ = null;
+ // JavaToJavaScriptCompiler logs onModuleLoadStart for each EntryPoint.
frameWnd.gwtOnLoad(onLoadErrorFunc, '__MODULE_NAME__', base);
-
- // Record when the module was started
- $stats && $stats('__MODULE_NAME__', 'startup', 'hostedModeSelectionEnd', {millis:(new Date()).getTime()});
+ // Record when the module EntryPoints return.
+ $stats && $stats({
+ moduleName: '__MODULE_NAME__',
+ subSystem: 'startup',
+ evtGroup: 'moduleStartup',
+ millis:(new Date()).getTime(),
+ type: 'end'
+ });
}
}
@@ -255,22 +270,42 @@
throw null;
}
- // --------------- PROPERTY PROVIDERS ---------------
+ var frameInjected;
+ function maybeInjectFrame() {
+ if (!frameInjected) {
+ frameInjected = true;
+ var iframe = $doc.createElement('iframe');
+ // Prevents mixed mode security in IE6/7.
+ iframe.src = "javascript:''";
+ iframe.id = "__MODULE_NAME__";
+ iframe.style.cssText = "position:absolute;width:0;height:0;border:none";
+ iframe.tabIndex = -1;
+ // Due to an IE6/7 refresh quirk, this must be an appendChild.
+ $doc.body.appendChild(iframe);
+
+ /*
+ * The src has to be set after the iframe is attached to the DOM to avoid
+ * refresh quirks in Safari. We have to use the location.replace trick to
+ * avoid FF2 refresh quirks.
+ */
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'moduleStartup',
+ millis:(new Date()).getTime(),
+ type: 'moduleRequested'
+ });
+ iframe.contentWindow.location.replace(base + strongName);
+ }
+ }
+
+ // --------------- PROPERTY PROVIDERS ---------------
// __PROPERTIES_BEGIN__
// __PROPERTIES_END__
// --------------- EXPOSED FUNCTIONS ----------------
- // Called when the script injection is complete.
- //
- __MODULE_FUNC__.onInjectionDone = function() {
- // Mark this module's script injection done and (possibly) start the module.
- scriptsDone = true;
- $stats && $stats('__MODULE_NAME__', 'startup', 'module', {requested:(new Date()).getTime()});
- maybeStartModule();
- }
-
// Called when the compiled script identified by moduleName is done loading.
//
__MODULE_FUNC__.onScriptLoad = function() {
@@ -279,12 +314,26 @@
// called before the frame was injected ... it is completely bogus.
if (frameInjected) {
// Mark this module's script as done loading and (possibly) start the module.
- $stats && $stats('__MODULE_NAME__', 'startup', 'module', {evalEnd:(new Date()).getTime()});
loadDone = true;
maybeStartModule();
}
}
+ // Called when the script injection is complete.
+ //
+ __MODULE_FUNC__.onInjectionDone = function() {
+ // Mark this module's script injection done and (possibly) start the module.
+ scriptsDone = true;
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'loadExternalRefs',
+ millis:(new Date()).getTime(),
+ type: 'end'
+ });
+ maybeStartModule();
+ }
+
// --------------- STRAIGHT-LINE CODE ---------------
// do it early for compile/browse rebasing
@@ -324,9 +373,19 @@
// --------------- WINDOW ONLOAD HOOK ---------------
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'bootstrap',
+ millis:(new Date()).getTime(),
+ type: 'selectingPermutation'
+ });
+
var strongName;
if (isHostedMode()) {
strongName = "hosted.html?__MODULE_FUNC__";
+ // Hang an expando for hosted.html to be able to grab the module name early.
+ __MODULE_FUNC__.moduleName = '__MODULE_NAME__';
} else {
try {
// __PERMUTATIONS_BEGIN__
@@ -356,28 +415,6 @@
}
}
- var frameInjected;
- function maybeInjectFrame() {
- if (!frameInjected) {
- frameInjected = true;
- var iframe = $doc.createElement('iframe');
- // Prevents mixed mode security in IE6/7.
- iframe.src = "javascript:''";
- iframe.id = "__MODULE_NAME__";
- iframe.style.cssText = "position:absolute;width:0;height:0;border:none";
- iframe.tabIndex = -1;
- // Due to an IE6/7 refresh quirk, this must be an appendChild.
- $doc.body.appendChild(iframe);
-
- /*
- * The src has to be set after the iframe is attached to the DOM to avoid
- * refresh quirks in Safari. We have to use the location.replace trick to
- * avoid FF2 refresh quirks.
- */
- iframe.contentWindow.location.replace(base + strongName);
- }
- }
-
// For everyone that supports DOMContentLoaded.
if ($doc.addEventListener) {
$doc.addEventListener("DOMContentLoaded", function() {
@@ -394,10 +431,27 @@
}
}, 50);
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'bootstrap',
+ millis:(new Date()).getTime(),
+ type: 'end'
+ });
+
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'loadExternalRefs',
+ millis:(new Date()).getTime(),
+ type: 'begin'
+ });
+
// __MODULE_SCRIPTS_BEGIN__
// Script resources are injected here
// __MODULE_SCRIPTS_END__
- $doc.write('<script>__MODULE_FUNC__.onInjectionDone(\'__MODULE_NAME__\')</script>');
+
+ $doc.write('<script defer="defer">__MODULE_FUNC__.onInjectionDone(\'__MODULE_NAME__\')</script>');
}
// Called from compiled code to hook the window's resize & load events (the
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html b/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
index 9f638db..190408a 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
@@ -2,7 +2,14 @@
<head><script>
var $wnd = parent;
var $doc = $wnd.document;
-var $moduleName, $moduleBase, $stats;
+var $moduleName, $moduleBase
+,$stats = $wnd.__gwtStatsEvent ? function(a) {return $wnd.__gwtStatsEvent(a);} : null;
+if ($stats) {
+ var moduleFuncName = location.search.substr(1);
+ var moduleFunc = $wnd[moduleFuncName];
+ var moduleName = moduleFunc ? moduleFunc.moduleName : "unknown";
+ $stats({moduleName:moduleName,subSystem:'startup',evtGroup:'moduleStartup',millis:(new Date()).getTime(),type:'moduleEvalStart'});
+}
</script></head>
<body>
<font face='arial' size='-1'>This html file is for hosted mode support.</font>
@@ -17,6 +24,10 @@
}
}
+window.fireOnModuleLoadStart = function(className) {
+ $stats && $stats({moduleName:$moduleName, subSystem:'startup', evtGroup:'moduleStartup', millis:(new Date()).getTime(), type:'onModuleLoadStart', className:className});
+};
+
window.onunload = function() {
external.gwtOnLoad(window, null);
};
@@ -24,5 +35,6 @@
window.__gwt_module_id = 0;
var query = window.location.search.substr(1);
+$stats && $stats({moduleName:$moduleName,subSystem:'startup',evtGroup:'moduleStartup',millis:(new Date()).getTime(),type:'moduleEvalEnd'});
if (query && $wnd[query]) $wnd[query].onScriptLoad();
--></script></body></html>
diff --git a/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java b/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java
index 2bb2353..89517d8 100644
--- a/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/IFrameLinker.java
@@ -82,7 +82,11 @@
out.newlineOpt();
out.print("var $moduleName, $moduleBase;");
out.newlineOpt();
- out.print("var $stats = $wnd.__gwtstatsEvent ? function(a,b,c,d) {$wnd.__gwtstatsEvent(a,b,c,d)} : null;");
+ out.print("var $stats = $wnd.__gwtStatsEvent ? function(a) {return $wnd.__gwtStatsEvent(a);} : null;");
+ out.newlineOpt();
+ out.print("$stats && $stats({moduleName:'" + context.getModuleName()
+ + "',subSystem:'startup',evtGroup:'moduleStartup'"
+ + ",millis:(new Date()).getTime(),type:'moduleEvalStart'});");
out.newlineOpt();
out.print("</script></head>");
out.newlineOpt();
@@ -93,9 +97,6 @@
// browser won't mistake strings containing "<script>" for actual script.
out.print("<script><!--");
out.newline();
- out.print("$stats && $stats('" + context.getModuleName()
- + "', 'startup', 'moduleEvalStart', {millis:(new Date()).getTime()});");
- out.newline();
return out.toString();
}
@@ -103,8 +104,9 @@
protected String getModuleSuffix(TreeLogger logger, LinkerContext context) {
DefaultTextOutput out = new DefaultTextOutput(context.isOutputCompact());
- out.print("$stats && $stats('" + context.getModuleName()
- + "', 'startup', 'moduleEvalEnd', {millis:(new Date()).getTime()});");
+ out.print("$stats && $stats({moduleName:'" + context.getModuleName()
+ + "',subSystem:'startup',evtGroup:'moduleStartup'"
+ + ",millis:(new Date()).getTime(),type:'moduleEvalEnd'});");
// Generate the call to tell the bootstrap code that we're ready to go.
out.newlineOpt();
diff --git a/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js b/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js
index 64bba8f..29d93f1 100644
--- a/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js
+++ b/dev/core/src/com/google/gwt/core/linker/IFrameTemplate.js
@@ -21,7 +21,7 @@
var $wnd = window
,$doc = document
,external = $wnd.external
- ,$stats = $wnd.__gwtstatsEvent ? function(a,b,c,d) {$wnd.__gwtstatsEvent(a,b,c,d)} : null
+ ,$stats = $wnd.__gwtStatsEvent ? function(a) {return $wnd.__gwtStatsEvent(a);} : null
// These variables gate calling gwtOnLoad; all must be true to start
,scriptsDone, loadDone, bodyDone
@@ -47,8 +47,13 @@
; // end of global vars
- // Record startup timing information
- $stats && $stats('__MODULE_NAME__', 'startup', 'selectionStart', {millis:(new Date()).getTime()});
+ $stats && $stats({
+ moduleName: '__MODULE_NAME__',
+ subSystem: 'startup',
+ evtGroup: 'bootstrap',
+ millis:(new Date()).getTime(),
+ type: 'begin',
+ });
// ------------------ TRUE GLOBALS ------------------
@@ -88,10 +93,16 @@
}
// remove this whole function from the global namespace to allow GC
__MODULE_FUNC__ = null;
+ // JavaToJavaScriptCompiler logs onModuleLoadStart for each EntryPoint.
frameWnd.gwtOnLoad(onLoadErrorFunc, '__MODULE_NAME__', base);
-
- // Record when the module was started
- $stats && $stats('__MODULE_NAME__', 'startup', 'selectionDone', {millis:(new Date()).getTime()});
+ // Record when the module EntryPoints return.
+ $stats && $stats({
+ moduleName: '__MODULE_NAME__',
+ subSystem: 'startup',
+ evtGroup: 'moduleStartup',
+ millis:(new Date()).getTime(),
+ type: 'end',
+ });
}
}
@@ -255,22 +266,42 @@
throw null;
}
- // --------------- PROPERTY PROVIDERS ---------------
+ var frameInjected;
+ function maybeInjectFrame() {
+ if (!frameInjected) {
+ frameInjected = true;
+ var iframe = $doc.createElement('iframe');
+ // Prevents mixed mode security in IE6/7.
+ iframe.src = "javascript:''";
+ iframe.id = "__MODULE_NAME__";
+ iframe.style.cssText = "position:absolute;width:0;height:0;border:none";
+ iframe.tabIndex = -1;
+ // Due to an IE6/7 refresh quirk, this must be an appendChild.
+ $doc.body.appendChild(iframe);
+
+ /*
+ * The src has to be set after the iframe is attached to the DOM to avoid
+ * refresh quirks in Safari. We have to use the location.replace trick to
+ * avoid FF2 refresh quirks.
+ */
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'moduleStartup',
+ millis:(new Date()).getTime(),
+ type: 'moduleRequested'
+ });
+ iframe.contentWindow.location.replace(base + strongName);
+ }
+ }
+
+ // --------------- PROPERTY PROVIDERS ---------------
// __PROPERTIES_BEGIN__
// __PROPERTIES_END__
// --------------- EXPOSED FUNCTIONS ----------------
- // Called when the script injection is complete.
- //
- __MODULE_FUNC__.onInjectionDone = function() {
- // Mark this module's script injection done and (possibly) start the module.
- scriptsDone = true;
- $stats && $stats('__MODULE_NAME__', 'startup', 'moduleRequested', {millis:(new Date()).getTime()});
- maybeStartModule();
- }
-
// Called when the compiled script identified by moduleName is done loading.
//
__MODULE_FUNC__.onScriptLoad = function() {
@@ -284,6 +315,21 @@
}
}
+ // Called when the script injection is complete.
+ //
+ __MODULE_FUNC__.onInjectionDone = function() {
+ // Mark this module's script injection done and (possibly) start the module.
+ scriptsDone = true;
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'loadExternalRefs',
+ millis:(new Date()).getTime(),
+ type: 'end'
+ });
+ maybeStartModule();
+ }
+
// --------------- STRAIGHT-LINE CODE ---------------
// do it early for compile/browse rebasing
@@ -292,6 +338,14 @@
// --------------- WINDOW ONLOAD HOOK ---------------
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'bootstrap',
+ millis:(new Date()).getTime(),
+ type: 'selectingPermutation'
+ });
+
var strongName;
if (isHostedMode()) {
strongName = "hosted.html?__MODULE_FUNC__";
@@ -324,28 +378,6 @@
}
}
- var frameInjected;
- function maybeInjectFrame() {
- if (!frameInjected) {
- frameInjected = true;
- var iframe = $doc.createElement('iframe');
- // Prevents mixed mode security in IE6/7.
- iframe.src = "javascript:''";
- iframe.id = "__MODULE_NAME__";
- iframe.style.cssText = "position:absolute;width:0;height:0;border:none";
- iframe.tabIndex = -1;
- // Due to an IE6/7 refresh quirk, this must be an appendChild.
- $doc.body.appendChild(iframe);
-
- /*
- * The src has to be set after the iframe is attached to the DOM to avoid
- * refresh quirks in Safari. We have to use the location.replace trick to
- * avoid FF2 refresh quirks.
- */
- iframe.contentWindow.location.replace(base + strongName);
- }
- }
-
// For everyone that supports DOMContentLoaded.
if ($doc.addEventListener) {
$doc.addEventListener("DOMContentLoaded", function() {
@@ -362,10 +394,27 @@
}
}, 50);
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'bootstrap',
+ millis:(new Date()).getTime(),
+ type: 'end'
+ });
+
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'loadExternalRefs',
+ millis:(new Date()).getTime(),
+ type: 'begin'
+ });
+
// __MODULE_SCRIPTS_BEGIN__
// Script resources are injected here
// __MODULE_SCRIPTS_END__
- $doc.write('<script>__MODULE_FUNC__.onInjectionDone(\'__MODULE_NAME__\')</script>');
+
+ $doc.write('<script defer="defer">__MODULE_FUNC__.onInjectionDone(\'__MODULE_NAME__\')</script>');
}
// Called from compiled code to hook the window's resize & load events (the
diff --git a/dev/core/src/com/google/gwt/core/linker/SingleScriptLinker.java b/dev/core/src/com/google/gwt/core/linker/SingleScriptLinker.java
index 7e80bd1..50aa425 100644
--- a/dev/core/src/com/google/gwt/core/linker/SingleScriptLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/SingleScriptLinker.java
@@ -78,7 +78,7 @@
out.newlineOpt();
out.print("var $moduleName, $moduleBase;");
out.newlineOpt();
- out.print("var $stats = $wnd.__gwtstatsEvent ? function(a,b,c,d) {$wnd.__gwtstatsEvent(a,b,c,d)} : null;");
+ out.print("var $stats = $wnd.__gwtStatsEvent ? function(a) {$wnd.__gwtStatsEvent(a)} : null;");
out.newlineOpt();
// Find the single CompilationResult
diff --git a/dev/core/src/com/google/gwt/core/linker/XSLinker.java b/dev/core/src/com/google/gwt/core/linker/XSLinker.java
index 23f1c78..ed544c2 100644
--- a/dev/core/src/com/google/gwt/core/linker/XSLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/XSLinker.java
@@ -58,10 +58,11 @@
out.newlineOpt();
out.print("var $moduleName, $moduleBase;");
out.newlineOpt();
- out.print("var $stats = $wnd.__gwtstatsEvent ? function(a,b,c,d){$wnd.__gwtstatsEvent(a,b,c,d)} : null;");
+ out.print("var $stats = $wnd.__gwtStatsEvent ? function(a) {return $wnd.__gwtStatsEvent(a);} : null;");
out.newlineOpt();
- out.print("$stats && $stats('" + context.getModuleName()
- + "', 'startup', 'moduleEvalStart', {millis:(new Date()).getTime()});");
+ out.print("$stats && $stats({moduleName:'" + context.getModuleName()
+ + "',subSystem:'startup',evtGroup:'moduleStartup'"
+ + ",millis:(new Date()).getTime(),type:'moduleEvalStart'});");
out.newlineOpt();
return out.toString();
@@ -72,8 +73,9 @@
throws UnableToCompleteException {
DefaultTextOutput out = new DefaultTextOutput(context.isOutputCompact());
- out.print("$stats && $stats('" + context.getModuleName()
- + "', 'startup', 'moduleEvalEnd', {millis:(new Date()).getTime()});");
+ out.print("$stats && $stats({moduleName:'" + context.getModuleName()
+ + "',subSystem:'startup',evtGroup:'moduleStartup'"
+ + ",millis:(new Date()).getTime(),type:'moduleEvalEnd'});");
// Generate the call to tell the bootstrap code that we're ready to go.
out.newlineOpt();
@@ -97,4 +99,5 @@
LinkerContext context) throws UnableToCompleteException {
return "com/google/gwt/core/linker/XSTemplate.js";
}
+
}
diff --git a/dev/core/src/com/google/gwt/core/linker/XSTemplate.js b/dev/core/src/com/google/gwt/core/linker/XSTemplate.js
index cdc993c..0e4e4cc 100644
--- a/dev/core/src/com/google/gwt/core/linker/XSTemplate.js
+++ b/dev/core/src/com/google/gwt/core/linker/XSTemplate.js
@@ -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
@@ -16,41 +16,46 @@
function __MODULE_FUNC__() {
// ---------------- INTERNAL GLOBALS ----------------
-
+
// Cache symbols locally for good obfuscation
var $wnd = window
,$doc = document
,external = $wnd.external
- ,$stats = $wnd.__gwtstatsEvent ? function(a,b,c,d) {$wnd.__gwtstatsEvent(a,b,c,d)} : null
+ ,$stats = $wnd.__gwtStatsEvent ? function(a) {return $wnd.__gwtStatsEvent(a);} : null
// These variables gate calling gwtOnLoad; all must be true to start
,gwtOnLoad, bodyDone
// If non-empty, an alternate base url for this module
,base = ''
-
+
// A map of properties that were declared in meta tags
,metaProps = {}
-
+
// Maps property names onto sets of legal values for that property.
,values = []
-
+
// Maps property names onto a function to compute that property.
,providers = []
-
+
// A multi-tier lookup map that uses actual property values to quickly find
// the strong name of the cache.js file to load.
,answers = []
// Error functions. Default unset in compiled mode, may be set by meta props.
,onLoadErrorFunc, propertyErrorFunc
-
+
; // end of global vars
- // Record startup timing information
- $stats && $stats('__MODULE_NAME__', 'startup', 'selectionStart', {millis:(new Date()).getTime()});
-
- // ------------------ TRUE GLOBALS ------------------
+ $stats && $stats({
+ moduleName: '__MODULE_NAME__',
+ subSystem: 'startup',
+ evtGroup: 'bootstrap',
+ millis:(new Date()).getTime(),
+ type: 'begin',
+ });
+
+ // ------------------ TRUE GLOBALS ------------------
// Maps to synchronize the loading of styles and scripts; resources are loaded
// only once, even when multiple modules depend on them. This API must not
@@ -77,28 +82,36 @@
function maybeStartModule() {
// TODO: it may not be necessary to check gwtOnLoad here.
if (gwtOnLoad && bodyDone) {
- if (isHostedMode()) {
- external.gwtOnLoad($wnd, $wnd.$moduleName);
- } else {
- gwtOnLoad(onLoadErrorFunc, '__MODULE_NAME__', base);
- // Record when the module was started
- $stats && $stats('__MODULE_NAME__', 'startup', 'selectionDone', {millis:(new Date()).getTime()});
- }
+ gwtOnLoad(onLoadErrorFunc, '__MODULE_NAME__', base);
+ // Record when the module EntryPoints return.
+ $stats && $stats({
+ moduleName: '__MODULE_NAME__',
+ subSystem: 'startup',
+ evtGroup: 'moduleStartup',
+ millis:(new Date()).getTime(),
+ type: 'end',
+ });
}
}
// Determine our own script's URL via magic :)
+ // This function produces one side-effect, it sets base to the module's
+ // base url.
//
function computeScriptBase() {
- // see if gwt.js left a marker for us
- var thisScript, markerScript;
+ var thisScript
+ ,markerId = "__gwt_marker___MODULE_NAME__"
+ ,markerScript;
- // try writing a marker
- $doc.write('<script id="__gwt_marker___MODULE_NAME__"></script>');
- markerScript = $doc.getElementById("__gwt_marker___MODULE_NAME__");
- if (markerScript) {
- // this script should be the previous element
- thisScript = markerScript.previousSibling;
+ $doc.write('<script id="' + markerId + '"></script>');
+ markerScript = $doc.getElementById(markerId);
+
+ // Our script element is assumed to be the closest previous script element
+ // to the marker, so start at the marker and walk backwards until we find
+ // a script.
+ thisScript = markerScript && markerScript.previousSibling;
+ while (thisScript && thisScript.tagName != 'SCRIPT') {
+ thisScript = thisScript.previousSibling;
}
function getDirectoryOfFile(path) {
@@ -123,7 +136,7 @@
var loc = $doc.location;
var href = loc.href;
base = getDirectoryOfFile(href.substr(0, href.length
- - loc.hash.length));
+ - loc.hash.length));
}
} else if ((base.match(/^\w+:\/\//))) {
// If the URL is obviously absolute, do nothing.
@@ -142,7 +155,7 @@
markerScript.parentNode.removeChild(markerScript);
}
}
-
+
// Called to slurp up all <meta> tags:
// gwt:property, gwt:onPropertyErrorFn, gwt:onLoadErrorFn
//
@@ -150,7 +163,7 @@
var metas = document.getElementsByTagName('meta');
for (var i = 0, n = metas.length; i < n; ++i) {
var meta = metas[i], name = meta.getAttribute('name'), content;
-
+
if (name) {
if (name == 'gwt:property') {
content = meta.getAttribute('content');
@@ -192,7 +205,7 @@
/**
* Determines whether or not a particular property value is allowed. Called by
* property providers.
- *
+ *
* @param propName the name of the property being checked
* @param propValue the property value being tested
*/
@@ -222,7 +235,7 @@
// set the final one to the value
answer[propValArray[n]] = value;
}
-
+
// Computes the value of a given property. propName must be a valid property
// name. Used by the generated PERMUTATIONS code.
//
@@ -240,8 +253,8 @@
}
throw null;
}
-
- // --------------- PROPERTY PROVIDERS ---------------
+
+ // --------------- PROPERTY PROVIDERS ---------------
// __PROPERTIES_BEGIN__
// __PROPERTIES_END__
@@ -259,21 +272,36 @@
// --------------- STRAIGHT-LINE CODE ---------------
+ if (isHostedMode()) {
+ alert("Cross-site hosted mode not yet implemented. See issue " +
+ "http://code.google.com/p/google-web-toolkit/issues/detail?id=2079");
+ return;
+ }
+
// do it early for compile/browse rebasing
computeScriptBase();
processMetas();
-
- if (isHostedMode()) {
- // Set up the globals and execute the hosted mode hook function
- $wnd.$wnd = $wnd;
- $wnd.$doc = $doc;
- $wnd.$moduleName = '__MODULE_NAME__';
- $wnd.$moduleBase = base;
- $wnd.__gwt_getProperty = computePropValue;
- $wnd.__gwt_initHandlers = __MODULE_FUNC__.__gwt_initHandlers;
- }
+
// --------------- WINDOW ONLOAD HOOK ---------------
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'bootstrap',
+ millis:(new Date()).getTime(),
+ type: 'selectingPermutation'
+ });
+
+ var strongName;
+ try {
+// __PERMUTATIONS_BEGIN__
+ // Permutation logic
+// __PERMUTATIONS_END__
+ } catch (e) {
+ // intentionally silent on property failure
+ return;
+ }
+
var onBodyDoneTimerId;
function onBodyDone() {
if (!bodyDone) {
@@ -294,7 +322,9 @@
// For everyone that supports DOMContentLoaded.
if ($doc.addEventListener) {
- $doc.addEventListener("DOMContentLoaded", onBodyDone, false);
+ $doc.addEventListener("DOMContentLoaded", function() {
+ onBodyDone();
+ }, false);
}
// Fallback. If onBodyDone() gets fired twice, it's not a big deal.
@@ -304,31 +334,42 @@
}
}, 50);
- if (isHostedMode()) {
- alert("Cross-site hosted mode not yet implemented. See issue " +
- "http://code.google.com/p/google-web-toolkit/issues/detail?id=2079");
- return;
- }
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'bootstrap',
+ millis:(new Date()).getTime(),
+ type: 'end'
+ });
- var strongName;
- try {
-// __PERMUTATIONS_BEGIN__
- // Permutation logic
-// __PERMUTATIONS_END__
- } catch (e) {
- // intentionally silent on property failure
- return;
- }
+ $stats && $stats({
+ moduleName:'__MODULE_NAME__',
+ subSystem:'startup',
+ evtGroup: 'loadExternalRefs',
+ millis:(new Date()).getTime(),
+ type: 'begin'
+ });
+
// __MODULE_SCRIPTS_BEGIN__
// Script resources are injected here
// __MODULE_SCRIPTS_END__
- $doc.write('<script src="' + base + strongName + '"></script>');
- $stats && $stats('__MODULE_NAME__', 'startup', 'moduleRequested', {millis:(new Date()).getTime()});
+
+ $doc.write('<script defer="defer">'
+ + 'window.__gwtStatsEvent && window.__gwtStatsEvent({'
+ + 'moduleName:\'__MODULE_NAME__\', subSystem:\'startup\','
+ + 'evtGroup: \'loadExternalRefs\', millis:(new Date()).getTime(),'
+ + 'type: \'end\'});'
+ + 'window.__gwtStatsEvent && window.__gwtStatsEvent({'
+ + 'moduleName:\'__MODULE_NAME__\', subSystem:\'startup\','
+ + 'evtGroup: \'moduleStartup\', millis:(new Date()).getTime(),'
+ + 'type: \'moduleRequested\'});'
+ + '</script>'
+ + '<script defer="defer" src="' + base + strongName + '"></script>');
}
// Called from compiled code to hook the window's resize & load events (the
// code running in the script frame is not allowed to hook these directly).
-//
+//
// Notes:
// 1) We declare it here in the global scope so that it won't closure the
// internals of the module func.
@@ -345,13 +386,13 @@
;
$wnd.onresize = function(evt) {
- try {
- resize();
- } finally {
- oldOnResize && oldOnResize(evt);
- }
+ try {
+ resize();
+ } finally {
+ oldOnResize && oldOnResize(evt);
+ }
};
-
+
$wnd.onbeforeunload = function(evt) {
var ret, oldRet;
try {
@@ -362,14 +403,14 @@
// Avoid returning null as IE6 will coerce it into a string.
// Ensure that "" gets returned properly.
if (ret != null) {
- return ret;
- }
- if (oldRet != null) {
- return oldRet;
- }
- // returns undefined.
+ return ret;
+ }
+ if (oldRet != null) {
+ return oldRet;
+ }
+ // returns undefined.
};
-
+
$wnd.onunload = function(evt) {
try {
unload();
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 e4e723a..5a6748a 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
@@ -141,6 +141,10 @@
return state == State.COMPILED || state == State.CHECKED;
}
+ public boolean isError() {
+ return state == State.ERROR;
+ }
+
/**
* Returns <code>true</code> if this unit was generated by a
* {@link com.google.gwt.core.ext.Generator}.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index 2d6e700..6c620bf 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -212,40 +212,23 @@
*
* <pre>
* Stats.isStatsAvailable() &&
- * Stats.stats(GWT.getModuleName(), "startup",
- * "onModuleLoadStart:<className>", Stats.makeTimeStat());
+ * Stats.onModuleStart("mainClassName");
* </pre>
*/
private static JStatement makeStatsCalls(JProgram program,
String mainClassName) {
-
- // Trim to the unqualified name for brevity
- if (mainClassName.contains(".")) {
- mainClassName = mainClassName.substring(mainClassName.lastIndexOf('.') + 1);
- }
-
JMethod isStatsAvailableMethod = program.getIndexedMethod("Stats.isStatsAvailable");
- JMethod makeTimeStatMethod = program.getIndexedMethod("Stats.makeTimeStat");
- JMethod moduleNameMethod = program.getIndexedMethod("Stats.getModuleName");
- JMethod statsMethod = program.getIndexedMethod("Stats.stats");
+ JMethod onModuleStartMethod = program.getIndexedMethod("Stats.onModuleStart");
JMethodCall availableCall = new JMethodCall(program, null, null,
isStatsAvailableMethod);
- JMethodCall makeTimeStatCall = new JMethodCall(program, null, null,
- makeTimeStatMethod);
- JMethodCall moduleNameCall = new JMethodCall(program, null, null,
- moduleNameMethod);
- JMethodCall statsCall = new JMethodCall(program, null, null, statsMethod);
-
- statsCall.getArgs().add(moduleNameCall);
- statsCall.getArgs().add(program.getLiteralString("startup"));
- statsCall.getArgs().add(
- program.getLiteralString("onModuleLoadStart:" + mainClassName));
- statsCall.getArgs().add(makeTimeStatCall);
+ JMethodCall onModuleStartCall = new JMethodCall(program, null, null,
+ onModuleStartMethod);
+ onModuleStartCall.getArgs().add(program.getLiteralString(mainClassName));
JBinaryOperation amp = new JBinaryOperation(program, null,
program.getTypePrimitiveBoolean(), JBinaryOperator.AND, availableCall,
- statsCall);
+ onModuleStartCall);
return amp.makeStatement();
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
index c20e519..b179a14 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
@@ -774,7 +774,7 @@
case MUL:
case DIV:
case MOD: {
- if (isTypeDouble(lhs) || isTypeFloat(rhs) || isTypeDouble(lhs)
+ if (isTypeDouble(lhs) || isTypeFloat(lhs) || isTypeDouble(rhs)
|| isTypeFloat(rhs)) {
// do the op on doubles and cast back
double left = toDouble(lhs);
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 c0f1f9c..8f19fcd 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
@@ -129,6 +129,16 @@
} else if (f.isFile() && lowerCaseFileName.endsWith(".zip")) {
return new ZipFileClassPathEntry(new ZipFile(f));
} else {
+ // It's a file ending in neither jar nor zip, speculatively try to
+ // open as jar/zip anyway.
+ try {
+ return new ZipFileClassPathEntry(new JarFile(f));
+ } catch (Exception ignored) {
+ }
+ try {
+ return new ZipFileClassPathEntry(new ZipFile(f));
+ } catch (Exception ignored) {
+ }
logger.log(TreeLogger.TRACE, "Unexpected entry in classpath; " + f
+ " is neither a directory nor an archive (.jar or .zip)");
return null;
diff --git a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
index 7af4f31..b663f76 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
@@ -300,6 +300,10 @@
onModuleLoad = module.getClass().getMethod("onModuleLoad");
}
onModuleLoad.setAccessible(true);
+ String reboundSourceName = module.getClass().getName().replace('$',
+ '.');
+ invokeNativeVoid("fireOnModuleLoadStart", null,
+ new Class[] {String.class}, new Object[] {reboundSourceName});
onModuleLoad.invoke(module);
}
} else {
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Stats.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Stats.java
index 25d6d4f..79fbd86 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Stats.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Stats.java
@@ -15,9 +15,6 @@
*/
package com.google.gwt.lang;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.core.client.JavaScriptObject;
-
/**
* Provides access to the statistics collector function as an intrinsic for use
* by the compiler. The typical use case is:
@@ -27,25 +24,18 @@
* </pre>
*/
final class Stats {
-
- static native String getModuleName() /*-{
- return $moduleName;
- }-*/;
-
- static boolean isStatsAvailable() {
- return GWT.isScript() && isStatsAvailable0();
- }
-
- static native JavaScriptObject makeTimeStat() /*-{
- return {millis : (new Date()).getTime()};
- }-*/;
-
- static native boolean stats(String moduleName, String system, String event,
- JavaScriptObject data) /*-{
- return $stats(moduleName, system, event, data);
- }-*/;
-
- private static native boolean isStatsAvailable0() /*-{
+ static native boolean isStatsAvailable() /*-{
return !!$stats;
}-*/;
+
+ static native boolean onModuleStart(String mainClassName) /*-{
+ return $stats({
+ moduleName: $moduleName,
+ subSystem: "startup",
+ evtGroup: "moduleStartup",
+ millis : (new Date()).getTime(),
+ type: "onModuleLoadStart",
+ className: mainClassName,
+ });
+ }-*/;
}
diff --git a/dev/mac/src/com/google/gwt/dev/BootStrapPlatform.java b/dev/mac/src/com/google/gwt/dev/BootStrapPlatform.java
index 559e59a..f4043a5 100644
--- a/dev/mac/src/com/google/gwt/dev/BootStrapPlatform.java
+++ b/dev/mac/src/com/google/gwt/dev/BootStrapPlatform.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -31,6 +31,15 @@
}
public static void init() {
+ /*
+ * The following check must be made before attempting to initialize Safari,
+ * or we'll fail with an less-than-helpful UnsatisfiedLinkError.
+ */
+ if (!isJava5()) {
+ System.err.println("You must use a Java 1.5 runtime to use GWT Hosted Mode on Mac OS X.");
+ System.exit(-1);
+ }
+
LowLevelSaf.init();
// Ensure we were started with -XstartOnFirstThread
if (!hasStartOnFirstThreadFlag(LowLevelSaf.getProcessArgs())) {
@@ -102,6 +111,14 @@
}
/**
+ * Determine if we're using the Java 1.5 runtime, since the 1.6 runtime is
+ * 64-bit.
+ */
+ private static boolean isJava5() {
+ return System.getProperty("java.version").startsWith("1.5");
+ }
+
+ /**
* Sets platform specific system properties. Currently, this disables
* CocoaComponent CompatibilityMode.
*
diff --git a/dev/mac/src/com/google/gwt/dev/shell/mac/LowLevelSaf.java b/dev/mac/src/com/google/gwt/dev/shell/mac/LowLevelSaf.java
index 426b2d9..3787e90 100644
--- a/dev/mac/src/com/google/gwt/dev/shell/mac/LowLevelSaf.java
+++ b/dev/mac/src/com/google/gwt/dev/shell/mac/LowLevelSaf.java
@@ -17,6 +17,7 @@
import com.google.gwt.dev.shell.LowLevel;
+import java.io.File;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Stack;
@@ -56,6 +57,9 @@
* Stores a map from DispatchObject/DispatchMethod to the live underlying
* jsval. This is used to both preserve identity for the same Java Object and
* also prevent GC.
+ *
+ * Access must be synchronized because WebKit can finalize on a foreign
+ * thread.
*/
static Map<Object, Integer> sObjectToJsval = new IdentityHashMap<Object, Integer>();
@@ -127,7 +131,17 @@
return;
}
- LowLevel.init();
+ try {
+ LowLevel.init();
+ } catch (UnsatisfiedLinkError e) {
+ // Try to provide some additional context
+ System.err.println("On Mac OS X, ensure that you have Safari 3 installed.");
+ if (!(new File("/System/Library/Frameworks/JavaScriptCore.framework")).isDirectory()) {
+ System.err.println("Could not find JavaScriptCore in the expected location.");
+ }
+ throw e;
+ }
+
if (!initImpl(DispatchObject.class, DispatchMethod.class, LowLevelSaf.class)) {
throw new RuntimeException("Unable to initialize LowLevelSaf");
}
@@ -280,38 +294,43 @@
public static int wrapDispatchMethod(int jsContext, String name,
DispatchMethod dispatch) {
- Integer cached = LowLevelSaf.sObjectToJsval.get(dispatch);
- if (cached != null) {
- /*
- * Add another lock to the cached jsval, since it will not have any.
- */
- LowLevelSaf.gcProtect(LowLevelSaf.getCurrentJsContext(), cached);
- return cached;
- } else {
- final int[] rval = new int[1];
- if (!wrapDispatchMethodImpl(jsContext, name, dispatch, rval)) {
- throw new RuntimeException("Failed to wrap DispatchMethod.");
+ synchronized (sObjectToJsval) {
+ Integer cached = LowLevelSaf.sObjectToJsval.get(dispatch);
+ if (cached != null) {
+ /*
+ * Add another lock to the cached jsval, since it will not have any.
+ */
+ LowLevelSaf.gcProtect(LowLevelSaf.getCurrentJsContext(), cached);
+ return cached;
+ } else {
+ final int[] rval = new int[1];
+ if (!wrapDispatchMethodImpl(jsContext, name, dispatch, rval)) {
+ throw new RuntimeException("Failed to wrap DispatchMethod.");
+ }
+ LowLevelSaf.sObjectToJsval.put(dispatch, rval[0]);
+ return rval[0];
}
- LowLevelSaf.sObjectToJsval.put(dispatch, rval[0]);
- return rval[0];
}
}
public static int wrapDispatchObject(int jsContext, DispatchObject dispatcher) {
- Integer cached = LowLevelSaf.sObjectToJsval.get(dispatcher);
- if (cached != null) {
- /*
- * Add another lock to the cached jsval, since it will not have any.
- */
- LowLevelSaf.gcProtect(LowLevelSaf.getCurrentJsContext(), cached);
- return cached;
- } else {
- final int[] rval = new int[1];
- if (!wrapDispatchObjectImpl(jsContext, dispatcher, rval)) {
- throw new RuntimeException("Failed to wrap DispatchObject.");
+ synchronized (sObjectToJsval) {
+
+ Integer cached = LowLevelSaf.sObjectToJsval.get(dispatcher);
+ if (cached != null) {
+ /*
+ * Add another lock to the cached jsval, since it will not have any.
+ */
+ LowLevelSaf.gcProtect(LowLevelSaf.getCurrentJsContext(), cached);
+ return cached;
+ } else {
+ final int[] rval = new int[1];
+ if (!wrapDispatchObjectImpl(jsContext, dispatcher, rval)) {
+ throw new RuntimeException("Failed to wrap DispatchObject.");
+ }
+ LowLevelSaf.sObjectToJsval.put(dispatcher, rval[0]);
+ return rval[0];
}
- LowLevelSaf.sObjectToJsval.put(dispatcher, rval[0]);
- return rval[0];
}
}
@@ -332,7 +351,9 @@
* Native code accessor to remove the mapping upon GC.
*/
static void releaseObject(Object o) {
- sObjectToJsval.remove(o);
+ synchronized (sObjectToJsval) {
+ sObjectToJsval.remove(o);
+ }
}
private static native boolean executeScriptWithInfoImpl(int jsContext,
diff --git a/doc/build.xml b/doc/build.xml
index b67b0cd..9a42ed7 100644
--- a/doc/build.xml
+++ b/doc/build.xml
@@ -13,6 +13,12 @@
value="com.google.gwt.core.client;com.google.gwt.core.ext;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" />
<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
+ include an entire package.
+ -->
+ <property name="USER_CLASSES"
+ value="${gwt.root}/user/src/com/google/gwt/junit/tools/GWTTestSuite.java" />
+
<!--
*** Note that if the USER_SOURCE_PATH paths are updated,
the fileset dependencies in the outofdate tags in the
@@ -86,7 +92,7 @@
<arg value="-examplepackages" />
<arg value="com.google.gwt.examples;com.google.gwt.examples.i18n;com.google.gwt.examples.http.client;com.google.gwt.examples.rpc.server;com.google.gwt.examples.benchmarks" />
<arg value="-packages" />
- <arg value="${USER_PKGS}" />
+ <arg value="${USER_PKGS};${USER_CLASSES}" />
</java>
</sequential>
</outofdate>
diff --git a/jni/linux/ExternalWrapper.cpp b/jni/linux/ExternalWrapper.cpp
index d13d8b1..12e7324 100644
--- a/jni/linux/ExternalWrapper.cpp
+++ b/jni/linux/ExternalWrapper.cpp
@@ -26,6 +26,13 @@
#include "Tracer.h"
#include "JsStringWrap.h"
+#ifdef ENABLE_TRACING
+extern void PrintJSValue(JSContext* cx, jsval val, char* prefix="");
+#else
+// Include a null version just to keep from cluttering up call sites.
+static inline void PrintJSValue(JSContext* cx, jsval val, char* prefix="") { }
+#endif
+
// note that this does not use the NS_DEFINE_CID macro because it defines
// the variable as const, which by default has internal linkage. I could
// work around it by putting extern in front of the macro, but that seems
@@ -83,25 +90,25 @@
}
tracer.log("module name=%s", JS_GetStringBytes(moduleName));
} else {
- tracer.log("null module name");
+ tracer.log("null module name");
}
-
+
jobject externalObject = NS_REINTERPRET_CAST(jobject, JS_GetPrivate(cx, obj));
jclass objClass = savedJNIEnv->GetObjectClass(externalObject);
if (!objClass || savedJNIEnv->ExceptionCheck()) {
tracer.setFail("can't get LowLevelMoz.ExternalObject class");
return JS_FALSE;
}
-
+
jmethodID methodID = savedJNIEnv->GetMethodID(objClass, "gwtOnLoad",
"(ILjava/lang/String;)Z");
if (!methodID || savedJNIEnv->ExceptionCheck()) {
tracer.setFail("can't get gwtOnLoad method");
return JS_FALSE;
}
-
+
tracer.log("scriptGlobal=%08x", unsigned(scriptGlobal.get()));
-
+
jboolean result = savedJNIEnv->CallBooleanMethod(externalObject, methodID,
NS_REINTERPRET_CAST(jint, scriptGlobal.get()), jModuleName);
if (savedJNIEnv->ExceptionCheck()) {
@@ -122,8 +129,14 @@
{
Tracer tracer("gwt_external_getProperty");
JsRootedValue::ContextManager context(cx);
- if (*vp != JSVAL_VOID)
+ if (*vp != JSVAL_VOID) {
+ // we setup the gwtOnLoad function as a property in GetScriptObject and
+ // do not maintain a copy of it anywhere. So, if there is a cached
+ // value for a property we must return it. As we never redefine any
+ // property values, this is safe. If we were going to keep this code
+ // around and add Toby's profiling code we would need to revisit this.
return JS_TRUE;
+ }
if (!JSVAL_IS_STRING(id)) {
tracer.setFail("not a string");
@@ -134,7 +147,7 @@
// All this is for calling resolveReference which only returns void. So,
// just replace this code to return void for now. TODO(jat): revisit when
-// merging in Toby's code.
+// merging in Toby's code.
#if 0
jstring jident = savedJNIEnv->NewString(jsStr.chars(), jsStr.length());
if (!jident || savedJNIEnv->ExceptionCheck()) {
@@ -303,7 +316,7 @@
tracer.setFail("can't create a new ExternalWrapper");
return NS_ERROR_OUT_OF_MEMORY;
}
-
+
nsresult result = object->QueryInterface(aIID, aResult);
if (!*aResult || NS_FAILED(result)) {
tracer.setFail("ExternalWrapper::QueryInterface failed");
diff --git a/jni/linux/LowLevelMoz.cpp b/jni/linux/LowLevelMoz.cpp
index b0ee1ed..9c3aba2 100644
--- a/jni/linux/LowLevelMoz.cpp
+++ b/jni/linux/LowLevelMoz.cpp
@@ -19,18 +19,6 @@
// Define to log debug-level output rather than just warnings.
#define DEBUG
-/*
- * Debug definitions -- define FILETRACE to have debug output written to
- * a file named gwt-ll.log, or JAVATRACE to have debug output passed to the
- * Java LowLevelMoz.trace method.
- */
-//#define FILETRACE
-//#define JAVATRACE
-
-#if defined(FILETRACE) || defined(JAVATRACE)
-#define ANYTRACE
-#endif
-
#include <cstdio>
#include <cstdarg>
#include <cwchar>
@@ -45,6 +33,16 @@
#include "Tracer.h"
#include "JsStringWrap.h"
+/*
+ * Debug definitions -- define FILETRACE to have debug output written to
+ * a file named gwt-ll.log, or JAVATRACE to have debug output passed to the
+ * Java LowLevelMoz.trace method.
+ */
+#ifdef ENABLE_TRACING
+#define FILETRACE
+//#define JAVATRACE
+#endif
+
// include javah-generated header to make sure we match
#include "LowLevelMoz.h"
@@ -52,7 +50,7 @@
jclass lowLevelMozClass;
// Only include debugging code if we are tracing somewhere.
-#ifdef ANYTRACE
+#ifdef ENABLE_TRACING
/*
* Template so vsnprintf/vswprintf can be used interchangeably in the
@@ -127,7 +125,7 @@
* be rewritten for out-of-process hosted mode, it seems unlikely to be worth
* the effort until that is completed.
*/
-static void PrintJSValue(JSContext* cx, jsval val, char* prefix="") {
+void PrintJSValue(JSContext* cx, jsval val, char* prefix="") {
JSType type = JS_TypeOfValue(cx, val);
const char* typeString=JS_GetTypeName(cx, type);
static const int BUF_SIZE = 256;
diff --git a/jni/linux/NativeWrapper.cpp b/jni/linux/NativeWrapper.cpp
index c017fd7..38958d0 100644
--- a/jni/linux/NativeWrapper.cpp
+++ b/jni/linux/NativeWrapper.cpp
@@ -132,10 +132,7 @@
JSObject *obj, jsval id, jsval *vp)
{
Tracer tracer("gwt_nativewrapper_getProperty");
- tracer.log("context=%08x", unsigned(cx));
- if (*vp != JSVAL_VOID) {
- return JS_TRUE;
- }
+ tracer.log("context=%08x, obj=%08x", unsigned(cx), unsigned(obj));
JsRootedValue::ContextManager context(cx);
jclass dispClass;
diff --git a/jni/linux/prebuilt/libgwt-ll.so b/jni/linux/prebuilt/libgwt-ll.so
index 33af9c7..88d2b41 100755
--- a/jni/linux/prebuilt/libgwt-ll.so
+++ b/jni/linux/prebuilt/libgwt-ll.so
Binary files differ
diff --git a/jni/mac/java-dispatch.cpp b/jni/mac/java-dispatch.cpp
index 9cdef44..fafab11 100644
--- a/jni/mac/java-dispatch.cpp
+++ b/jni/mac/java-dispatch.cpp
@@ -88,7 +88,17 @@
/*
* Java class and method references needed to do delegation.
*/
+
+ /*
+ * The main JVM, used by foreign threads to attach.
+ */
+ static JavaVM* _javaVM;
+
+ /*
+ * Only valid for the main thread! WebKit can finalized on a foreign thread.
+ */
static JNIEnv* _javaEnv;
+
static jclass _javaDispatchObjectClass;
static jclass _javaDispatchMethodClass;
static jclass _lowLevelSafClass;
@@ -460,6 +470,9 @@
return false;
}
+ _javaVM = 0;
+ javaEnv->GetJavaVM(&_javaVM);
+
_javaEnv = javaEnv;
_javaDispatchObjectClass = static_cast<jclass>(
javaEnv->NewGlobalRef(javaDispatchObjectClass));
@@ -478,7 +491,8 @@
_lowLevelSafReleaseObject = javaEnv->GetStaticMethodID(
lowLevelSafClass, "releaseObject", "(Ljava/lang/Object;)V");
- if (!_javaDispatchObjectSetFieldMethod || !_javaDispatchObjectGetFieldMethod
+ if (!_javaVM
+ || !_javaDispatchObjectSetFieldMethod || !_javaDispatchObjectGetFieldMethod
|| !_javaDispatchMethodInvokeMethod || !_javaDispatchObjectToStringMethod
|| !_lowLevelSafReleaseObject || javaEnv->ExceptionCheck()) {
return false;
@@ -489,14 +503,22 @@
}
void ReleaseJavaObject(jobject jObject) {
- // Tell the Java code we're done with this object.
- _javaEnv->CallStaticVoidMethod(_lowLevelSafClass, _lowLevelSafReleaseObject,
- jObject);
- if (_javaEnv->ExceptionCheck()) {
+ // Tricky: this call may be on a foreign thread.
+ JNIEnv* javaEnv = 0;
+ if ((_javaVM->AttachCurrentThreadAsDaemon(reinterpret_cast<void**>(&javaEnv),
+ NULL) < 0) || !javaEnv) {
TR_FAIL();
return;
}
- _javaEnv->DeleteGlobalRef(jObject);
+
+ // Tell the Java code we're done with this object.
+ javaEnv->CallStaticVoidMethod(_lowLevelSafClass, _lowLevelSafReleaseObject,
+ jObject);
+ if (javaEnv->ExceptionCheck()) {
+ TR_FAIL();
+ return;
+ }
+ javaEnv->DeleteGlobalRef(jObject);
}
} // namespace gwt
diff --git a/jni/mac/prebuilt/libgwt-ll.jnilib b/jni/mac/prebuilt/libgwt-ll.jnilib
index c9db8c5..5a4030f 100755
--- a/jni/mac/prebuilt/libgwt-ll.jnilib
+++ b/jni/mac/prebuilt/libgwt-ll.jnilib
Binary files differ
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
index 888987c..9101ef9 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
@@ -35,6 +35,7 @@
addIssue(new Issue2338());
addIssue(new Issue2339());
addIssue(new Issue2392());
+ addIssue(new Issue2443());
addIssue(new TestFireEvents());
}
}
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue2443.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue2443.java
new file mode 100644
index 0000000..f7fd88a
--- /dev/null
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue2443.java
@@ -0,0 +1,79 @@
+/*
+ * 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.museum.client.defaultmuseum;
+
+import com.google.gwt.museum.client.common.AbstractIssue;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Dragging a {@link DialogBox} to the right edge of the screen creates a
+ * horizontal scroll bar. The {@link DialogBox} should wrap the the text in
+ * order to avoid creating the scroll bar.
+ */
+public class Issue2443 extends AbstractIssue {
+ /**
+ * The DialogBox to test.
+ */
+ private DialogBox dialogBox = null;
+
+ @Override
+ public Widget createIssue() {
+ // Create the DialogBox
+ dialogBox = new DialogBox(false, false);
+ dialogBox.setText("Dialog Box");
+
+ String message = "This text should wrap when the "
+ + "DialogBox is dragged to the right edge of the screen. ";
+ VerticalPanel vPanel = new VerticalPanel();
+ vPanel.add(new Label(message));
+ vPanel.add(new Button("Close", new ClickListener() {
+ public void onClick(Widget sender) {
+ dialogBox.hide();
+ }
+ }));
+ dialogBox.setWidget(vPanel);
+
+ // Create a button to display the dialog box
+ Button showButton = new Button("Show DialogBox", new ClickListener() {
+ public void onClick(Widget sender) {
+ dialogBox.center();
+ }
+ });
+ return showButton;
+ }
+
+ @Override
+ public String getInstructions() {
+ return "Move the DialogBox to the right edge of the screen. The DialogBox "
+ + "should wrap its text as best it can to avoid creating a horizontal "
+ + "scroll bar.";
+ }
+
+ @Override
+ public String getSummary() {
+ return "DialogBox does not resize naturally";
+ }
+
+ @Override
+ public boolean hasCSS() {
+ return true;
+ }
+}
diff --git a/reference/code-museum/src/com/google/gwt/museum/public/issues/Issue2443.css b/reference/code-museum/src/com/google/gwt/museum/public/issues/Issue2443.css
new file mode 100644
index 0000000..53c6554
--- /dev/null
+++ b/reference/code-museum/src/com/google/gwt/museum/public/issues/Issue2443.css
@@ -0,0 +1,5 @@
+@import url("Default.css");
+
+iframe {
+ border: 2px solid black;
+}
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 443bd40..dbc326d 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
@@ -298,7 +298,7 @@
int contentWidth = width - menuWidth - 30;
int contentWidthInner = contentWidth - 10;
bottomPanel.setCellWidth(mainMenu, menuWidth + "px");
- bottomPanel.setCellWidth(contentLayout, contentWidth + "px");
+ bottomPanel.setCellWidth(contentDecorator, contentWidth + "px");
contentLayout.getCellFormatter().setWidth(0, 0, contentWidthInner + "px");
contentLayout.getCellFormatter().setWidth(1, 0, contentWidthInner + "px");
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/Showcase.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/Showcase.java
index 280fb2d..0819baf 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/Showcase.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/Showcase.java
@@ -17,10 +17,8 @@
import com.google.gwt.core.client.EntryPoint;
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.HeadElement;
-import com.google.gwt.dom.client.LinkElement;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.i18n.client.LocaleInfo;
@@ -60,9 +58,9 @@
import com.google.gwt.sample.showcase.client.content.widgets.CwFileUpload;
import com.google.gwt.sample.showcase.client.content.widgets.CwHyperlink;
import com.google.gwt.sample.showcase.client.content.widgets.CwRadioButton;
+import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.HistoryListener;
-import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.ChangeListener;
@@ -71,7 +69,6 @@
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TabBar;
@@ -150,20 +147,12 @@
public static String CUR_THEME = ShowcaseConstants.STYLE_THEMES[0];
/**
- * Convenience method for getting the document's head element.
- *
- * @return the document's head element
- */
- private static native HeadElement getHeadElement() /*-{
- return $doc.getElementsByTagName("head")[0];
- }-*/;
-
- /**
* Get the URL of the page, without an hash of query string.
*
* @return the location of the page
*/
- private static native String getHostPageLocation() /*-{
+ private static native String getHostPageLocation()
+ /*-{
var s = $doc.location.href;
// Pull off any hash.
@@ -186,6 +175,16 @@
private Application app;
/**
+ * When the user selects a {@link TreeItem} from the main menu, we
+ * synchronously change the current example and add a history token for
+ * history support. However, adding the history token causes the history
+ * changed event to fire, which normally selects the associated menu item and
+ * displays the example. We don't want to repeat this twice, so we use a
+ * boolean to indicate that we want to ignore the history changed event.
+ */
+ private boolean ignoreNextHistoryEvent = false;
+
+ /**
* A mapping of history tokens to their associated menu items.
*/
private Map<String, TreeItem> itemTokens = new HashMap<String, TreeItem>();
@@ -196,50 +195,12 @@
private Map<TreeItem, ContentWidget> itemWidgets = new HashMap<TreeItem, ContentWidget>();
/**
- * A small widget used to determine when a new style sheet has finished
- * loading. The widget has a natural width of 0px, but when any GWT.css style
- * sheet is loaded, the width changes to 5px. We use a Timer to check the
- * width until the style sheet loads.
- */
- private Label styleTester;
-
- /**
- * The timer that uses the styleTester to determine when the new GWT style
- * sheet has loaded.
- */
- private Timer styleTesterTimer = new Timer() {
- @Override
- public void run() {
- styleTester.setVisible(false);
- styleTester.setVisible(true);
- if (styleTester.getOffsetWidth() > 0) {
- RootPanel.getBodyElement().getStyle().setProperty("display", "none");
- RootPanel.getBodyElement().getStyle().setProperty("display", "");
- app.onWindowResizedImpl(Window.getClientWidth());
- } else {
- schedule(25);
- }
- }
- };
-
- /**
* This is the entry point method.
*/
public void onModuleLoad() {
// Generate the source code and css for the examples
GWT.create(GeneratorInfo.class);
- // Create a widget to test when style sheets are loaded
- styleTester = new HTML("<div class=\"topLeftInner\"></div>");
- styleTester.setStyleName("gwt-DecoratorPanel");
- styleTester.getElement().getStyle().setProperty("position", "absolute");
- styleTester.getElement().getStyle().setProperty("visibility", "hidden");
- styleTester.getElement().getStyle().setProperty("display", "inline");
- styleTester.getElement().getStyle().setPropertyPx("padding", 0);
- styleTester.getElement().getStyle().setPropertyPx("top", 0);
- styleTester.getElement().getStyle().setPropertyPx("left", 0);
- RootPanel.get().add(styleTester);
-
// Create the constants
ShowcaseConstants constants = (ShowcaseConstants) GWT.create(ShowcaseConstants.class);
@@ -249,7 +210,6 @@
setupMainLinks(constants);
setupOptionsPanel();
setupMainMenu(constants);
- RootPanel.get().add(app);
// Swap out the style sheets for the RTL versions if needed. We need to do
// this after the app is loaded because the app will setup the layout based
@@ -261,44 +221,63 @@
// menu.
updateStyleSheets();
- // Add an listener that sets the content widget when a menu item is selected
- app.setListener(new ApplicationListener() {
- public void onMenuItemSelected(TreeItem item) {
- ContentWidget content = itemWidgets.get(item);
- if (content != null) {
- History.newItem(getContentWidgetToken(content));
- }
- }
- });
-
// Setup a history listener to reselect the associate menu item
- HistoryListener historyListener = new HistoryListener() {
+ final HistoryListener historyListener = new HistoryListener() {
public void onHistoryChanged(String historyToken) {
+ // Ignore the event if the user selected the content from the main menu
+ if (ignoreNextHistoryEvent) {
+ ignoreNextHistoryEvent = false;
+ return;
+ }
+
TreeItem item = itemTokens.get(historyToken);
if (item != null) {
- // Select the item in the tree
- if (!item.equals(app.getMainMenu().getSelectedItem())) {
- app.getMainMenu().setSelectedItem(item, false);
- app.getMainMenu().ensureSelectedItemVisible();
- }
+ // Select the associated TreeItem
+ app.getMainMenu().setSelectedItem(item, false);
+ app.getMainMenu().ensureSelectedItemVisible();
- // Show the associated widget
+ // Show the associated ContentWidget
displayContentWidget(itemWidgets.get(item));
}
}
};
History.addHistoryListener(historyListener);
- // Show the initial example
- String initToken = History.getToken();
- if (initToken.length() > 0) {
- historyListener.onHistoryChanged(initToken);
- } else {
- // Use the first token available
- TreeItem firstItem = app.getMainMenu().getItem(0).getChild(0);
- ContentWidget firstContent = itemWidgets.get(firstItem);
- historyListener.onHistoryChanged(getContentWidgetToken(firstContent));
- }
+ // Add an listener that sets the content widget when a menu item is selected
+ app.setListener(new ApplicationListener() {
+ public void onMenuItemSelected(TreeItem item) {
+ ContentWidget content = itemWidgets.get(item);
+ if (content != null && !content.equals(app.getContent())) {
+ // Show the new example
+ displayContentWidget(content);
+
+ // Update the history token, but ignore the next history event
+ ignoreNextHistoryEvent = true;
+ History.newItem(getContentWidgetToken(content));
+ }
+ }
+ });
+
+ // When the style sheet has loaded, attach the app
+ StyleSheetLoader.waitForStyleSheet(getCurrentReferenceStyleName(),
+ new Command() {
+ public void execute() {
+ if (!app.isAttached()) {
+ RootPanel.get().add(app);
+ }
+
+ // Show the initial example
+ String initToken = History.getToken();
+ if (initToken.length() > 0) {
+ historyListener.onHistoryChanged(initToken);
+ } else {
+ // Use the first token available
+ TreeItem firstItem = app.getMainMenu().getItem(0).getChild(0);
+ app.getMainMenu().setSelectedItem(firstItem, true);
+ app.getMainMenu().ensureSelectedItemVisible();
+ }
+ }
+ });
}
/**
@@ -325,17 +304,17 @@
}
/**
- * Create a new {@link LinkElement} that links to a style sheet and append it
- * to the head element.
+ * Get the style name of the reference element defined in the current GWT
+ * theme style sheet.
*
- * @param href the path to the style sheet
+ * @return the style name
*/
- private void loadStyleSheet(String href) {
- LinkElement linkElem = Document.get().createLinkElement();
- linkElem.setRel("stylesheet");
- linkElem.setType("text/css");
- linkElem.setHref(href);
- getHeadElement().appendChild(linkElem);
+ private String getCurrentReferenceStyleName() {
+ String gwtRef = "gwt-Reference-" + CUR_THEME;
+ if (LocaleInfo.getCurrentLocale().isRTL()) {
+ gwtRef += "-rtl";
+ }
+ return gwtRef;
}
/**
@@ -556,8 +535,9 @@
showcaseStyleSheet = showcaseStyleSheet.replace(".css", "_rtl.css");
}
- // Remove existing style sheets
- HeadElement headElem = getHeadElement();
+ // Find existing style sheets that need to be removed
+ final HeadElement headElem = StyleSheetLoader.getHeadElement();
+ final List<Element> toRemove = new ArrayList<Element>();
NodeList<Node> children = headElem.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.getItem(i);
@@ -566,35 +546,48 @@
if (elem.getTagName().equalsIgnoreCase("link")
&& elem.getPropertyString("rel").equalsIgnoreCase("stylesheet")) {
String href = elem.getPropertyString("href");
- // If the style sheet is already loaded, we keep it and set
- // gwtStyleSheet to null so that we do not load it below. The same
- // applies to showcaseStyleSheet.
- if (gwtStyleSheet != null && href.contains(gwtStyleSheet)) {
- gwtStyleSheet = null;
- } else if (showcaseStyleSheet != null
- && href.contains(showcaseStyleSheet)) {
- showcaseStyleSheet = null;
- } else {
- headElem.removeChild(elem);
- i--;
+ // If the correct style sheets are already loaded, then we should have
+ // nothing to remove.
+ if (!href.contains(gwtStyleSheet)
+ && !href.contains(showcaseStyleSheet)) {
+ toRemove.add(elem);
}
}
}
}
- // Kick off the timer that checks to see when the stylesheet has been applied, so that
- // we can force a re-layout of the application. We even do this in the case where
- // no stylesheets are swapped out, because this could be on the first load of the application,
- // and the stylesheet may not have been applied to the DOM elements as yet.
- styleTesterTimer.schedule(25);
-
- // Add the new style sheets
+ // Return if we already have the correct style sheets
+ if (toRemove.size() == 0) {
+ return;
+ }
+
+ // Detach the app while we manipulate the styles to avoid rendering issues
+ RootPanel.get().remove(app);
+
+ // Remove the old style sheets
+ for (Element elem : toRemove) {
+ headElem.removeChild(elem);
+ }
+
+ // Load the GWT theme style sheet
String modulePath = GWT.getModuleBaseURL();
- if (gwtStyleSheet != null) {
- loadStyleSheet(modulePath + gwtStyleSheet);
- }
- if (showcaseStyleSheet != null) {
- loadStyleSheet(modulePath + showcaseStyleSheet);
- }
+ Command callback = new Command() {
+ public void execute() {
+ // Different themes use different background colors for the body
+ // element, but IE only changes the background of the visible content
+ // on the page instead of changing the background color of the entire
+ // page. By changing the display style on the body element, we force
+ // IE to redraw the background correctly.
+ RootPanel.getBodyElement().getStyle().setProperty("display", "none");
+ RootPanel.getBodyElement().getStyle().setProperty("display", "");
+ RootPanel.get().add(app);
+ }
+ };
+ StyleSheetLoader.loadStyleSheet(modulePath + gwtStyleSheet,
+ getCurrentReferenceStyleName(), callback);
+
+ // Load the showcase specific style sheet after the GWT theme style sheet so
+ // that custom styles supercede the theme styles.
+ StyleSheetLoader.loadStyleSheet(modulePath + showcaseStyleSheet);
}
}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants.properties b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants.properties
index 88cb3e5..6238f61 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants.properties
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants.properties
@@ -49,10 +49,8 @@
cwBasicTextSelected = Selected
cwCheckBoxName = Checkbox
cwCheckBoxDescription = Basic Checkbox Widgets
-cwCheckBoxCheckAll = <b>Check all that apply:</b>
-cwCheckBoxFemale = Female
-cwCheckBoxMale = Male
-cwCheckBoxUnknown = Unknown (disabled)
+cwCheckBoxCheckAll = <b>Check all days that you are available:</b>
+cwCheckBoxDays = Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
cwConstantsExampleDescription = Interface Constants makes it possible to localize strings, numbers, and maps of strings onto strings. This example isn't terribly exciting, but it does demonstrate how to localize constants. The labels and color choices below are provided by the localized implementation of the sample interface ExampleConstants.
cwConstantsExampleName = Constants
cwConstantsExampleLinkText = This example interacts with the sample interface:
@@ -148,11 +146,12 @@
cwHyperlinkChoose = <b>Choose a section:</b>
cwListBoxName = List Box
cwListBoxDescription = Built-in selection box and drop down lists
+cwListBoxCars = compact, sedan, coupe, convertible, SUV, truck
cwListBoxCategories = Cars, Sports, Vacation Spots
cwListBoxSelectAll = <b>Select all that apply:</b>
cwListBoxSelectCategory = <b>Select a category:</b>
cwListBoxSports = Baseball, Basketball, Football, Hockey, Lacrosse, Polo, Soccor, Softball, Water Polo
-cwListBoxVacations = Carribean, Disney World, Grand Canyon, Paris, Italy
+cwListBoxVacations = Carribean, Grand Canyon, Paris, Italy, New York, Las Vegas
cwMenuBarName = Menu Bar
cwMenuBarDescription = The Menu Bar can be used to navigate through many options. It also supports nested sub menus.
cwMenuBarEditCategory = Edit
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_ar.properties b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_ar.properties
index d1f2a69..d629b09 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_ar.properties
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_ar.properties
@@ -44,10 +44,8 @@
cwBasicTextSelected = مختارة
cwCheckBoxName = خانة تأشير
cwCheckBoxDescription = ودجات خانة تاشير اساسية
-cwCheckBoxCheckAll = <b>تحقق من كل ما ينطبق:</b>
-cwCheckBoxFemale = انثى
-cwCheckBoxMale = ذكر
-cwCheckBoxUnknown = مجهول (معطل)
+cwCheckBoxCheckAll = <b>تأكد من ان كل الأيام أنت المتاحة:</b>
+cwCheckBoxDays = الاثنين , الثلاثاء , الاربعاء , الخميس , الجمعة , السبت , الأحد
cwConstantsExampleDescription = ان ثوابت الواجهة تمكن من التخصيص المحلي للمنصوصات او الارقام وجداول تعيين المنصوصات على منصوصات. مع ان هذا ليس مثالا ممتازا الا انه يوضح كيف يمكن تخصيص الثوابت محليا. ان اللواصق وخيارات الالوان ادناه مزودة من التطبيق الذي تم تخصيصه محليا لعينة الواجهة ExampleConstants
cwConstantsExampleName = الثوابت
cwConstantsExampleLinkText = هذا المثال يتفاعل مع عينة الواجهة:
@@ -141,11 +139,12 @@
cwHyperlinkChoose = <b>اختيار احد الاقسام:</b>
cwListBoxName = مربع اللائحة
cwListBoxDescription = مربع اختيار ولوائح منسدلة مضمنين
+cwListBoxCars = الميثاق , سيدان , العربة , للتحويل , جيب , وشاحنة
cwListBoxCategories = سيارات, رياضة, مواقع للعطلة
cwListBoxSelectAll = <b>اختر كل ما ينطبق:</b>
cwListBoxSelectCategory = <b>اختر الفئة:</b>
cwListBoxSports = البيسبول , كرة السلة , كرة القدم الامريكية , الهوكي , لاكروس , بولو , كرة القدم , الكرة الناعمة , وكرة الماء
-cwListBoxVacations = منطقة البحر الكاريبي , ديزني وورلد , جراند كانيون , باريس , ايطاليا
+cwListBoxVacations = منطقة البحر الكاريبي , جراند كانيون , باريس , ايطاليا , نيويورك , لاس فيجا
cwMenuBarName = شريط القوائم
cwMenuBarDescription = شريط القوائم يمكنك من التنقل بين العديد من الخيارات, وكذلك يعدم القوائم المتفرعة
cwMenuBarEditCategory = تحرير
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_fr.properties b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_fr.properties
index a56cbc2..47569c1 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_fr.properties
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_fr.properties
@@ -49,10 +49,8 @@
cwBasicTextSelected = Sélectionné
cwCheckBoxName = Case à cocher
cwCheckBoxDescription = Widgets de case à cocher basique
-cwCheckBoxCheckAll = <b>Sélectionnez toutes les réponses appropriées:</b>
-cwCheckBoxFemale = F
-cwCheckBoxMale = M
-cwCheckBoxUnknown = Inconnu (désactivé)
+cwCheckBoxCheckAll = <b>Arrivée tous les jours que vous êtes disponible:</b>
+cwCheckBoxDays = lundi, mardi, mercredi, jeudi, vendredi, samedi, dimanche
cwConstantsExampleDescription = Les Constantes d'Interfaces permet de localiser des chaînes de caractères, des numéros et des mappes qui mappent une chaine de caractères à une autre. Cet exemple n'est pas très passionnant, mais il nous montre comment localiser des constantes. Les étiquettes et le choix des couleurs ci-dessous sont fournies par l'application localisée de l'échantillon d'interface ExampleConstants.
cwConstantsExampleName = Constantes
cwConstantsExampleLinkText = Cet exemple interagit avec l'échatillon de l'interface:
@@ -148,11 +146,12 @@
cwHyperlinkChoose = <b>Choisir une section:</b>
cwListBoxName = Zone de liste
cwListBoxDescription = Zone de sélection et listes déroulantes intégrées
+cwListBoxCars = compact, berline, coupé, cabriolet, VUS, camions
cwListBoxCategories = Voitures, Sports, Lieux de vacances
cwListBoxSelectAll = <b>Sélectionnez toutes les options appropriées:</b>
cwListBoxSelectCategory = <b>Sélectionnez une catégorie:</b>
cwListBoxSports = Base-ball, Basket-ball, Football, Hockey, Crosse, Polo, Soccer, Softball, Water-polo
-cwListBoxVacations = Caraïbes, Disneyland, Grand Canyon, Paris, Italie
+cwListBoxVacations = Caraïbes, Grand Canyon, Paris, Italie, New York, Las Vegas
cwMenuBarName = Barre de menus
cwMenuBarDescription = La barre de menus permet de naviguer parmi de nombreuses options. Elle prend également en charge des sous-menus.
cwMenuBarEditCategory = Édition
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_zh.properties b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_zh.properties
index 524c626..e0f7857 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_zh.properties
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_zh.properties
@@ -44,10 +44,8 @@
cwBasicTextSelected = 已选择
cwCheckBoxName = 复选框
cwCheckBoxDescription = 简单复选框部件
-cwCheckBoxCheckAll = <b>选中所有适用内容:</b>
-cwCheckBoxFemale = 女
-cwCheckBoxMale = 男
-cwCheckBoxUnknown = 未知(已禁用)
+cwCheckBoxCheckAll = <b>检查所有天知道您有空:</b>
+cwCheckBoxDays =周一,周二,周三,周四,周五,周六,周日
cwConstantsExampleDescription =常量接口(Constants)可以用来本地化字串,数字,字串到字串的映射表。这个例子也许并不特别有趣,但它演示了如何本地化常量。抽象界面ExampleConstants的本地化实现提供了标签文本和颜色选择 。
cwConstantsExampleName =常量
cwConstantsExampleLinkText = 这个例子使用了示例接口:
@@ -141,11 +139,12 @@
cwHyperlinkChoose = <b>选择一个栏目:</b>
cwListBoxName = 列表框
cwListBoxDescription = 预制的选择框和下拉列表
+cwListBoxCars = 紧凑,轿车,跑车,兑换,越野车,卡车
cwListBoxCategories = 汽车, 体育, 度假景点
cwListBoxSelectAll = <b>选择所有适用内容:</b>
cwListBoxSelectCategory = <b>选择类别:</b>
cwListBoxSports = 棒球, 篮球, 足球, 冰球, 曲棍球, 马球, 足球, 垒球, 水球
-cwListBoxVacations = 加勒比海, 迪斯尼乐园, 大峡谷, 巴黎, 意大利
+cwListBoxVacations = 加勒比地区,大峡谷,巴黎,意大利,纽约,拉斯维加斯
cwMenuBarName = 菜单栏
cwMenuBarDescription = 菜单栏可用于遍历众多选项,还可支持嵌套子菜单。
cwMenuBarEditCategory = 编辑
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/StyleSheetLoader.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/StyleSheetLoader.java
new file mode 100644
index 0000000..0252d9d
--- /dev/null
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/StyleSheetLoader.java
@@ -0,0 +1,135 @@
+/*
+ * 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.sample.showcase.client;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.HeadElement;
+import com.google.gwt.dom.client.LinkElement;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.RootPanel;
+
+/**
+ * A utility class that loads style sheets.
+ */
+public class StyleSheetLoader {
+ /**
+ * A {@link Timer} that creates a small reference widget used to determine
+ * when a new style sheet has finished loading. The widget has a natural width
+ * of 0px, but when the style sheet is loaded, the width changes to 5px. The
+ * style sheet should contain a style definition that is passed into the
+ * constructor that defines a height and width greater than 0px.
+ */
+ private static class StyleTesterTimer extends Timer {
+ private Command callback;
+ private Label refWidget;
+
+ /**
+ * Create a new {@link StyleTesterTimer}.
+ *
+ * @param refStyleName the reference style name
+ * @param callback the callback to execute when the style sheet loads
+ */
+ public StyleTesterTimer(String refStyleName, Command callback) {
+ this.callback = callback;
+
+ // Create the reference Widget
+ refWidget = new Label();
+ refWidget.setStyleName(refStyleName);
+ refWidget.getElement().getStyle().setProperty("position", "absolute");
+ refWidget.getElement().getStyle().setProperty("visibility", "hidden");
+ refWidget.getElement().getStyle().setProperty("display", "inline");
+ refWidget.getElement().getStyle().setPropertyPx("padding", 0);
+ refWidget.getElement().getStyle().setPropertyPx("margin", 0);
+ refWidget.getElement().getStyle().setPropertyPx("border", 0);
+ refWidget.getElement().getStyle().setPropertyPx("top", 0);
+ refWidget.getElement().getStyle().setPropertyPx("left", 0);
+ RootPanel.get().add(refWidget);
+ }
+
+ @Override
+ public void run() {
+ // Redisplay the reference widget so it redraws itself
+ refWidget.setVisible(false);
+ refWidget.setVisible(true);
+
+ // Check the dimensions of the reference widget
+ if (refWidget.getOffsetWidth() > 0) {
+ RootPanel.get().remove(refWidget);
+
+ // Fire the callback in a DeferredCommand to ensure the browser has
+ // enough time to parse the styles. Otherwise, we'll get weird styling
+ // issues.
+ DeferredCommand.addCommand(callback);
+ } else {
+ schedule(10);
+ }
+ }
+ }
+
+ /**
+ * Convenience method for getting the document's head element.
+ *
+ * @return the document's head element
+ */
+ public static native HeadElement getHeadElement()
+ /*-{
+ return $doc.getElementsByTagName("head")[0];
+ }-*/;
+
+ /**
+ * Load a style sheet onto the page.
+ *
+ * @param href the url of the style sheet
+ */
+ public static void loadStyleSheet(String href) {
+ LinkElement linkElem = Document.get().createLinkElement();
+ linkElem.setRel("stylesheet");
+ linkElem.setType("text/css");
+ linkElem.setHref(href);
+ getHeadElement().appendChild(linkElem);
+ }
+
+ /**
+ * Load a style sheet onto the page and fire a callback when it has loaded.
+ * The style sheet should contain a style definition called refStyleName that
+ * defines a height and width greater than 0px.
+ *
+ * @param href the url of the style sheet
+ * @param refStyleName the style name of the reference element
+ * @param callback the callback executed when the style sheet has loaded
+ */
+ public static void loadStyleSheet(String href, String refStyleName,
+ Command callback) {
+ loadStyleSheet(href);
+ waitForStyleSheet(refStyleName, callback);
+ }
+
+ /**
+ * Detect when a style sheet has loaded by placing an element on the page that
+ * is affected by a rule in the style sheet, as described in
+ * {@link #loadStyleSheet(String, String, Command)}. When the style sheet has
+ * loaded, the callback will be executed.
+ *
+ * @param refStyleName the style name of the reference element
+ * @param callback the callback executed when the style sheet has loaded
+ */
+ public static void waitForStyleSheet(String refStyleName, Command callback) {
+ new StyleTesterTimer(refStyleName, callback).run();
+ }
+}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwListBox.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwListBox.java
index 6e11a38..e9715a5 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwListBox.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/lists/CwListBox.java
@@ -38,6 +38,8 @@
@ShowcaseSource
public static interface CwConstants extends Constants,
ContentWidget.CwConstants {
+ String[] cwListBoxCars();
+
String[] cwListBoxCategories();
String cwListBoxDescription();
@@ -54,15 +56,6 @@
}
/**
- * The data for each type of list.
- */
- @ShowcaseData
- private static final String[] carTypes = {
- "Acura", "Audi", "BMW", "Buick", "Chevrolet", "Dodge", "Ford", "Honda",
- "KIA", "Lexus", "Lincoln", "Mercedes", "Porsche", "Saturn", "Toyota",
- "Volkswagen", "Volvo"};
-
- /**
* An instance of the constants.
*/
@ShowcaseData
@@ -150,7 +143,7 @@
String[] listData = null;
switch (category) {
case 0:
- listData = carTypes;
+ listData = constants.cwListBoxCars();
break;
case 1:
listData = constants.cwListBoxSports();
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCheckBox.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCheckBox.java
index a08369d..ac3813f 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCheckBox.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCheckBox.java
@@ -38,15 +38,11 @@
ContentWidget.CwConstants {
String cwCheckBoxCheckAll();
+ String[] cwCheckBoxDays();
+
String cwCheckBoxDescription();
- String cwCheckBoxFemale();
-
- String cwCheckBoxMale();
-
String cwCheckBoxName();
-
- String cwCheckBoxUnknown();
}
/**
@@ -87,21 +83,20 @@
label.ensureDebugId("cwCheckBox-label");
vPanel.add(label);
- // Add a male checkbox
- CheckBox maleCheckBox = new CheckBox(constants.cwCheckBoxMale());
- maleCheckBox.ensureDebugId("cwCheckBox-male");
- vPanel.add(maleCheckBox);
-
- // Add a female checkbox
- CheckBox femaleCheckBox = new CheckBox(constants.cwCheckBoxFemale());
- femaleCheckBox.ensureDebugId("cwCheckBox-female");
- vPanel.add(femaleCheckBox);
+ // Add a checkbox for each day of the week
+ String[] daysOfWeek = constants.cwCheckBoxDays();
+ for (int i = 0; i < daysOfWeek.length; i++) {
+ String day = daysOfWeek[i];
+ CheckBox checkBox = new CheckBox(day);
+ checkBox.ensureDebugId("cwCheckBox-" + day);
- // Add one disabled checkbox
- CheckBox disabledCheckBox = new CheckBox(constants.cwCheckBoxUnknown());
- disabledCheckBox.ensureDebugId("cwCheckBox-disabled");
- disabledCheckBox.setEnabled(false);
- vPanel.add(disabledCheckBox);
+ // Disable the weekends
+ if (i >= 5) {
+ checkBox.setEnabled(false);
+ }
+
+ vPanel.add(checkBox);
+ }
// Return the panel of checkboxes
return vPanel;
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCustomButton.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCustomButton.java
index a28673a..60035ec 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCustomButton.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwCustomButton.java
@@ -23,7 +23,6 @@
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.KeyboardListenerAdapter;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.ToggleButton;
import com.google.gwt.user.client.ui.VerticalPanel;
@@ -98,7 +97,6 @@
PushButton normalPushButton = new PushButton(
Showcase.images.gwtLogo().createImage());
normalPushButton.ensureDebugId("cwCustomButton-push-normal");
- normalPushButton.addKeyboardListener(new KeyboardListenerAdapter());
pushPanel.add(normalPushButton);
// Add a disabled PushButton
@@ -112,7 +110,6 @@
ToggleButton normalToggleButton = new ToggleButton(
Showcase.images.gwtLogo().createImage());
normalToggleButton.ensureDebugId("cwCustomButton-toggle-normal");
- normalToggleButton.addKeyboardListener(new KeyboardListenerAdapter());
togglePanel.add(normalToggleButton);
// Add a disabled ToggleButton
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/locale.png b/samples/showcase/src/com/google/gwt/sample/showcase/client/locale.png
index cc16676..fb9423b 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/locale.png
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/locale.png
Binary files differ
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/propertieschanges.txt b/samples/showcase/src/com/google/gwt/sample/showcase/client/propertieschanges.txt
deleted file mode 100644
index 49bb17c..0000000
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/propertieschanges.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-cwDecoratorPanelName
-cwDecoratorPanelDescription
-
-cwAnimationName = Animations
-cwAnimationDescription = Animate your application with timed effects.
-cwAnimationStart = Start
-cwAnimationCancel = Cancel
-cwAnimationOptions = Animation Options
-
-cwDecoratorPanelFormName => cwDisclosurePanelFormName
-cwDecoratorPanelFormDescription => cwDisclosurePanelFormDescription
-cwDecoratorPanelFormTitle => cwDisclosurePanelFormTitle
diff --git a/user/src/com/google/gwt/animation/client/Animation.java b/user/src/com/google/gwt/animation/client/Animation.java
index b90fa72..11e53ed 100644
--- a/user/src/com/google/gwt/animation/client/Animation.java
+++ b/user/src/com/google/gwt/animation/client/Animation.java
@@ -45,13 +45,18 @@
* Update all {@link Animation Animations}.
*/
private static void updateAnimations() {
+ // Duplicate the animations list in case it changes as we iterate over it
+ Animation[] curAnimations = new Animation[animations.size()];
+ curAnimations = animations.toArray(curAnimations);
+
// Iterator through the animations
double curTime = Duration.currentTimeMillis();
- for (int i = 0; i < animations.size(); i++) {
- Animation animation = animations.get(i);
- if (animation.update(curTime)) {
- animations.remove(i);
- i--;
+ for (Animation animation : curAnimations) {
+ if (animation.running && animation.update(curTime)) {
+ // We can't just remove the animation at the index, because calling
+ // animation.update may have the side effect of canceling this
+ // animation, running new animations, or canceling other animations.
+ animations.remove(animation);
}
}
@@ -67,7 +72,13 @@
private int duration = -1;
/**
- * Has the {@link Animation} been started.
+ * Is the {@link Animation} running, even if {@link #onStart()} has not yet
+ * been called.
+ */
+ private boolean running = false;
+
+ /**
+ * Has the {@link Animation} actually started.
*/
private boolean started = false;
@@ -81,16 +92,15 @@
* scheduled to run, {@link #onCancel()} will be called.
*/
public void cancel() {
- // Ignore if no animations are running
- if (animations == null) {
+ // Ignore if the animation is not currently running
+ if (!running) {
return;
}
- // Remove this animation from the list
- if (animations.remove(this)) {
- onCancel();
- }
+ animations.remove(this);
+ onCancel();
started = false;
+ running = false;
}
/**
@@ -116,6 +126,7 @@
cancel();
// Save the duration and startTime
+ this.running = true;
this.duration = duration;
this.startTime = startTime;
@@ -162,7 +173,6 @@
*/
protected void onCancel() {
if (started) {
- started = false;
onComplete();
}
}
@@ -213,8 +223,9 @@
}
if (finished) {
// Animation is complete.
- started = false;
onComplete();
+ started = false;
+ running = false;
return true;
}
return false;
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index f31a6fb..09d2bbe 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -18,12 +18,15 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.TreeLogger.Type;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.BootStrapPlatform;
import com.google.gwt.dev.GWTShell;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.ModuleDefLoader;
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.BrowserWidgetHost;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import com.google.gwt.junit.client.TimeoutException;
@@ -155,6 +158,42 @@
}
/**
+ * Sanity check; if the type we're trying to run did not actually wind up in
+ * the type oracle, there's no way this test can possibly run. Bail early
+ * instead of failing on the client.
+ */
+ private static JUnitFatalLaunchException checkTestClassInCurrentModule(
+ TreeLogger logger, ModuleDef currentModule, String moduleName,
+ TestCase testCase) throws UnableToCompleteException {
+ TypeOracle typeOracle = currentModule.getTypeOracle(logger);
+ String typeName = testCase.getClass().getName();
+ typeName = typeName.replace('$', '.');
+ JClassType foundType = typeOracle.findType(typeName);
+ if (foundType != null) {
+ return null;
+ }
+ Map<String, CompilationUnit> unitMap = currentModule.getCompilationState().getCompilationUnitMap();
+ CompilationUnit unit = unitMap.get(typeName);
+ String errMsg;
+ if (unit == null) {
+ errMsg = "The test class '" + typeName + "' was not found in module '"
+ + moduleName + "'; no compilation unit for that type was seen";
+ } else if (unit.isError()) {
+ errMsg = "The test class '" + typeName
+ + "' had compile errors; check log for details";
+ } else if (!unit.isCompiled()) {
+ errMsg = "The test class '"
+ + typeName
+ + "' depends on a unit that had compile errors; check log for details";
+ } else {
+ errMsg = "Unexpected error: the test class '"
+ + typeName
+ + "' appears to be valid, but no corresponding type was found in TypeOracle; please contact GWT support";
+ }
+ return new JUnitFatalLaunchException(errMsg);
+ }
+
+ /**
* Retrieves the JUnitShell. This should only be invoked during TestRunner
* execution of JUnit tests.
*/
@@ -586,6 +625,13 @@
runStyle.maybeCompileModule(syntheticModuleName);
}
+ JUnitFatalLaunchException launchException = checkTestClassInCurrentModule(
+ getTopLogger(), currentModule, moduleName, testCase);
+ if (launchException != null) {
+ testResult.addError(testCase, launchException);
+ return;
+ }
+
messageQueue.setNextTest(new TestInfo(currentModule.getName(),
testCase.getClass().getName(), testCase.getName()));
diff --git a/user/src/com/google/gwt/junit/client/GWTTestCase.java b/user/src/com/google/gwt/junit/client/GWTTestCase.java
index 99d22df..2158542 100644
--- a/user/src/com/google/gwt/junit/client/GWTTestCase.java
+++ b/user/src/com/google/gwt/junit/client/GWTTestCase.java
@@ -243,7 +243,7 @@
* {@link #gwtTearDown()} instead.
*/
@Override
- protected void tearDown() throws Exception {
+ protected final void tearDown() throws Exception {
// implemented in the translatable version of this class
}
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 9f3ae92..20c7f68 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImpl.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImpl.java
@@ -34,19 +34,15 @@
protected static boolean isMyListener(Object object) {
/*
* The first test ensures the Object belongs to this module in hosted mode,
- * because this hosted mode class loader will have a different copy of
- * the EventListener class than some other module would have.
+ * because this hosted mode class loader will have a different copy of the
+ * EventListener class than some other module would have.
*
* However, in web mode we could still get a collision where another module
* happens to use the same typeId. The second test ensures the Object is not
* "foreign". See Cast.isJavaScriptObject().
*/
- boolean b = object instanceof com.google.gwt.user.client.EventListener
+ return object instanceof com.google.gwt.user.client.EventListener
&& !(object instanceof JavaScriptObject);
- if (!b) {
- System.out.println(object.toString());
- }
- return b;
}
public native void eventCancelBubble(Event evt, boolean cancel) /*-{
diff --git a/user/src/com/google/gwt/user/client/impl/HistoryImplIE6.java b/user/src/com/google/gwt/user/client/impl/HistoryImplIE6.java
index 72b54e9..eacc70d 100644
--- a/user/src/com/google/gwt/user/client/impl/HistoryImplIE6.java
+++ b/user/src/com/google/gwt/user/client/impl/HistoryImplIE6.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -31,12 +31,24 @@
* @param maybeHtml untrusted string that may contain html
* @return sanitized string
*/
+ @SuppressWarnings("unused")
private static String escapeHtml(String maybeHtml) {
final Element div = DOM.createDiv();
DOM.setInnerText(div, maybeHtml);
return DOM.getInnerHTML(div);
}
+ /**
+ * For IE6, reading from $wnd.location.hash drops part of the fragment if the
+ * fragment contains a '?'. To avoid this bug, we use location.href instead.
+ */
+ @SuppressWarnings("unused")
+ private static native String getLocationHash() /*-{
+ var href = $wnd.location.href;
+ var hashLoc = href.indexOf("#");
+ return (hashLoc > 0) ? href.substring(hashLoc) : "";
+ }-*/;
+
@Override
public boolean init() {
if (!super.init()) {
@@ -54,7 +66,7 @@
@Override
protected native void initHistoryToken() /*-{
// Get the initial token from the url's hash component.
- var hash = $wnd.location.hash;
+ var hash = @com.google.gwt.user.client.impl.HistoryImplIE6::getLocationHash()();
if (hash.length > 0) {
try {
$wnd.__gwt_historyToken = this.@com.google.gwt.user.client.impl.HistoryImpl::decodeFragment(Ljava/lang/String;)(hash.substring(1));
@@ -100,7 +112,7 @@
doc.close();
}
}-*/;
-
+
private native void initUrlCheckTimer() /*-{
// This is the URL check timer. It detects when an unexpected change
// occurs in the document's URL (e.g. when the user enters one manually
@@ -110,7 +122,7 @@
// bar in the UI to stop working under these circumstances.
var historyImplRef = this;
var urlChecker = function() {
- var hash = $wnd.location.hash;
+ var hash = @com.google.gwt.user.client.impl.HistoryImplIE6::getLocationHash()();
if (hash.length > 0) {
var token = '';
try {
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/RemoteServiceProxy.java b/user/src/com/google/gwt/user/client/rpc/impl/RemoteServiceProxy.java
index 5e32c56..cdcbc7b 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/RemoteServiceProxy.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/RemoteServiceProxy.java
@@ -15,7 +15,6 @@
*/
package com.google.gwt.user.client.rpc.impl;
-import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
@@ -41,8 +40,8 @@
private static int requestId;
public static native JavaScriptObject bytesStat(String method, int count,
- int bytes) /*-{
- var stat = @com.google.gwt.user.client.rpc.impl.RemoteServiceProxy::timeStat(Ljava/lang/String;I)(method, count);
+ int bytes, String eventType) /*-{
+ var stat = @com.google.gwt.user.client.rpc.impl.RemoteServiceProxy::timeStat(Ljava/lang/String;ILjava/lang/String;)(method, count, eventType);
stat.bytes = bytes;
return stat;
}-*/;
@@ -50,24 +49,29 @@
/**
* Indicates if RPC statistics should be gathered.
*/
- public static boolean isStatsAvailable() {
- return GWT.isScript() && isStatsAvailable0();
- }
+ /**
+ * Indicates if RPC statistics should be gathered.
+ */
+ public static native boolean isStatsAvailable() /*-{
+ return !!$stats;
+ }-*/;
/**
* Always use this as {@link #isStatsAvailable()} &&
- * {@link #stats(String, String, int)}.
+ * {@link #stats(JavaScriptObject)}.
*/
- public static native boolean stats(String invocation, JavaScriptObject data) /*-{
- return $stats(@com.google.gwt.core.client.GWT::getModuleName()(), 'rpc',
- invocation, data);
+ public static native boolean stats(JavaScriptObject data) /*-{
+ return $stats(data);
}-*/;
- public static native JavaScriptObject timeStat(String method, int count) /*-{
+ public static native JavaScriptObject timeStat(String method, int count, String eventType) /*-{
return {
- id: count,
+ moduleName: @com.google.gwt.core.client.GWT::getModuleName()(),
+ subSystem: 'rpc',
+ evtGroup: count,
method: method,
- millis: (new Date()).getTime()
+ millis: (new Date()).getTime(),
+ type: eventType
};
}-*/;
@@ -119,13 +123,6 @@
}
/**
- * Indicates if RPC statistics should be gathered.
- */
- private static native boolean isStatsAvailable0() /*-{
- return @com.google.gwt.core.client.GWT::isScript()() && !!$stats;
- }-*/;
-
- /**
* The module base URL as specified during construction.
*/
private final String moduleBaseURL;
@@ -244,9 +241,8 @@
callback.onFailure(iex);
} finally {
if (RemoteServiceProxy.isStatsAvailable()
- && RemoteServiceProxy.stats(methodName + ":" + invocationCount
- + ":requestSent", RemoteServiceProxy.bytesStat(methodName,
- invocationCount, requestData.length()))) {
+ && RemoteServiceProxy.stats(RemoteServiceProxy.bytesStat(methodName,
+ invocationCount, requestData.length(), "requestSent"))) {
}
}
return null;
@@ -273,13 +269,6 @@
RequestBuilder rb = doPrepareRequestBuilderImpl(responseReader, methodName,
invocationCount, requestData, callback);
- // We'll record when the request was configured...
- if (RemoteServiceProxy.isStatsAvailable()
- && RemoteServiceProxy.stats(methodName + ":" + invocationCount
- + ":requestPrepared", RemoteServiceProxy.bytesStat(methodName,
- invocationCount, requestData.length()))) {
- }
-
return rb;
}
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/RequestCallbackAdapter.java b/user/src/com/google/gwt/user/client/rpc/impl/RequestCallbackAdapter.java
index cd80ac3..e963da9 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/RequestCallbackAdapter.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/RequestCallbackAdapter.java
@@ -185,9 +185,8 @@
String encodedResponse = response.getText();
int statusCode = response.getStatusCode();
boolean toss = RemoteServiceProxy.isStatsAvailable()
- && RemoteServiceProxy.stats(methodName + ":" + requestId
- + ":responseReceived", RemoteServiceProxy.bytesStat(methodName,
- requestId, encodedResponse.length()));
+ && RemoteServiceProxy.stats(RemoteServiceProxy.bytesStat(methodName,
+ requestId, encodedResponse.length(), "responseReceived"));
if (statusCode != Response.SC_OK) {
caught = new StatusCodeException(statusCode, encodedResponse);
@@ -207,9 +206,8 @@
caught = e;
} finally {
boolean toss = RemoteServiceProxy.isStatsAvailable()
- && RemoteServiceProxy.stats(methodName + ":" + requestId
- + ":responseDeserialized", RemoteServiceProxy.timeStat(
- methodName, requestId));
+ && RemoteServiceProxy.stats(RemoteServiceProxy.timeStat(
+ methodName, requestId, "responseDeserialized"));
}
try {
@@ -220,9 +218,8 @@
}
} finally {
boolean toss = RemoteServiceProxy.isStatsAvailable()
- && RemoteServiceProxy.stats(methodName + ":" + requestId
- + ":responseCallbackDone", RemoteServiceProxy.timeStat(
- methodName, requestId));
+ && RemoteServiceProxy.stats(RemoteServiceProxy.timeStat(
+ methodName, requestId, "end"));
}
}
}
diff --git a/user/src/com/google/gwt/user/client/ui/DecoratedPopupPanel.java b/user/src/com/google/gwt/user/client/ui/DecoratedPopupPanel.java
index 4b0ea1a..fe59e0f 100644
--- a/user/src/com/google/gwt/user/client/ui/DecoratedPopupPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/DecoratedPopupPanel.java
@@ -144,6 +144,24 @@
maybeUpdateSize();
}
+ @Override
+ protected void doAttachChildren() {
+ // See comment in doDetachChildren for an explanation of this call
+ decPanel.onAttach();
+ }
+
+ @Override
+ protected void doDetachChildren() {
+ // We need to detach the decPanel because it is not part of the iterator of
+ // Widgets that this class returns (see the iterator() method override).
+ // Detaching the decPanel detaches both itself and its children. We do not
+ // call super.onDetachChildren() because that would detach the decPanel's
+ // children (redundantly) without detaching the decPanel itself.
+ // This is similar to a {@link ComplexPanel}, but we do not want to expose
+ // the decPanel widget, as its just an internal implementation.
+ decPanel.onDetach();
+ }
+
/**
* Get a specific Element from the panel.
*
diff --git a/user/src/com/google/gwt/user/client/ui/Frame.java b/user/src/com/google/gwt/user/client/ui/Frame.java
index fcfa53e..e58bbe7 100644
--- a/user/src/com/google/gwt/user/client/ui/Frame.java
+++ b/user/src/com/google/gwt/user/client/ui/Frame.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Google Inc.
+ * 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
@@ -35,13 +35,14 @@
* </p>
*/
public class Frame extends Widget {
-
+ static final String DEFAULT_STYLENAME = "gwt-Frame";
+
/**
* Creates an empty frame.
*/
public Frame() {
setElement(DOM.createIFrame());
- setStyleName("gwt-Frame");
+ setStyleName(DEFAULT_STYLENAME);
}
/**
diff --git a/user/src/com/google/gwt/user/client/ui/NamedFrame.java b/user/src/com/google/gwt/user/client/ui/NamedFrame.java
index 66e0cc9..2fa73e0 100644
--- a/user/src/com/google/gwt/user/client/ui/NamedFrame.java
+++ b/user/src/com/google/gwt/user/client/ui/NamedFrame.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -23,11 +23,17 @@
* A {@link com.google.gwt.user.client.ui.Frame} that has a 'name' associated
* with it. This allows the frame to be the target of a
* {@link com.google.gwt.user.client.ui.FormPanel}
+ *
+ * <h3>CSS Style Rules</h3>
+ * <ul class='css'>
+ * <li>.gwt-Frame { }</li>
+ * </ul>
*/
public class NamedFrame extends Frame {
// Used inside JSNI, so please don't delete this field just because
// your compiler or IDE says it's unused.
+ @SuppressWarnings("unused")
private static JavaScriptObject PATTERN_NAME;
static {
@@ -70,6 +76,7 @@
Element iframe = DOM.getFirstChild(div);
replaceElement(iframe);
+ setStyleName(DEFAULT_STYLENAME);
}
/**
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 589d6a7..cc64a7a 100644
--- a/user/src/com/google/gwt/user/client/ui/PopupPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
@@ -88,28 +88,36 @@
private boolean showing = false;
/**
+ * Create a new {@link ResizeAnimation}.
+ *
+ * @param panel the panel to affect
+ */
+ public ResizeAnimation(PopupPanel panel) {
+ this.curPanel = panel;
+ }
+
+ /**
* Open or close the content. This method always called immediately after
* the PopupPanel showing state has changed, so we base the animation on the
* current state.
*
- * @param panel the panel to open or close
+ * @param showing true if the popup is showing, false if not
*/
- public void setOpen(final PopupPanel panel) {
+ public void setState(boolean showing) {
// Immediately complete previous open/close animation
cancel();
// Determine if we need to animate
- boolean animate = panel.isAnimationEnabled;
- if (panel.animType == AnimationType.ONE_WAY_CORNER && !panel.showing) {
+ boolean animate = curPanel.isAnimationEnabled;
+ if (curPanel.animType == AnimationType.ONE_WAY_CORNER && !showing) {
animate = false;
}
// Open the new item
- showing = panel.showing;
- curPanel = panel;
+ this.showing = showing;
if (animate) {
// impl.onShow takes some time to complete, so we do it before starting
- // the animation. If we move this to onStart, the animation will look
+ // the animation. If we move this to onStart, the animation will look
// choppy or not run at all.
if (showing) {
// Set the position attribute, and then attach to the DOM. Otherwise,
@@ -124,7 +132,7 @@
RootPanel.get().add(curPanel);
impl.onShow(curPanel.getElement());
}
-
+
// Wait for the popup panel to be attached before running the animation
DeferredCommand.addCommand(new Command() {
public void execute() {
@@ -144,7 +152,6 @@
}
impl.setClip(curPanel.getElement(), "rect(auto, auto, auto, auto)");
DOM.setStyleAttribute(curPanel.getElement(), "overflow", "visible");
- curPanel = null;
}
@Override
@@ -208,7 +215,6 @@
impl.onHide(curPanel.getElement());
}
DOM.setStyleAttribute(curPanel.getElement(), "overflow", "visible");
- curPanel = null;
}
}
@@ -239,11 +245,6 @@
private static final PopupImpl impl = GWT.create(PopupImpl.class);
/**
- * The {@link ResizeAnimation} used to open and close the {@link PopupPanel}s.
- */
- private static ResizeAnimation resizeAnimation;
-
- /**
* If true, animate the opening of this popup from the center. If false,
* animate it open from top to bottom, and do not animate closing. Use false
* to animate menus.
@@ -259,6 +260,11 @@
private boolean isAnimationEnabled = false;
+ /**
+ * The {@link ResizeAnimation} used to open and close the {@link PopupPanel}s.
+ */
+ private ResizeAnimation resizeAnimation = new ResizeAnimation(this);
+
// the left style attribute in pixels
private int leftPosition = -1;
@@ -645,11 +651,7 @@
}
showing = true;
DOM.addEventPreview(this);
-
- if (resizeAnimation == null) {
- resizeAnimation = new ResizeAnimation();
- }
- resizeAnimation.setOpen(this);
+ resizeAnimation.setState(true);
}
@Override
@@ -708,7 +710,8 @@
*
* @param elt The Element on which <code>blur()</code> will be invoked
*/
- private native void blur(Element elt) /*-{
+ private native void blur(Element elt)
+ /*-{
if (elt.blur) {
elt.blur();
}
@@ -721,10 +724,7 @@
showing = false;
// Hide the popup
- if (resizeAnimation == null) {
- resizeAnimation = new ResizeAnimation();
- }
- resizeAnimation.setOpen(this);
+ resizeAnimation.setState(false);
// Fire the event listeners
if (popupListeners != null) {
diff --git a/user/src/com/google/gwt/user/client/ui/impl/PopupImplIE6.java b/user/src/com/google/gwt/user/client/ui/impl/PopupImplIE6.java
index 52e43f2..1dffb8d 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/PopupImplIE6.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/PopupImplIE6.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -56,6 +56,11 @@
// Visibility of frame should match visiblity of popup element.
style.visibility = popup.style.visibility;
+ // Issue 2443: remove styles that affect the size of the iframe
+ style.border = 0;
+ style.padding = 0;
+ style.margin = 0;
+
// takes effect immediately
style.left = popup.offsetLeft;
style.top = popup.offsetTop;
diff --git a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
index b307e9e..762c9dd 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/ProxyCreator.java
@@ -344,15 +344,12 @@
w.indent();
String requestIdName = nameFactory.createName("requestId");
- w.println("long " + requestIdName + " = getNextRequestId();");
+ w.println("int " + requestIdName + " = getNextRequestId();");
- String statsMethodExpr = getProxySimpleName() + "." + syncMethod.getName()
- + ":\" + getRequestId() + \"";
+ String statsMethodExpr = getProxySimpleName() + "." + syncMethod.getName();
String tossName = nameFactory.createName("toss");
- w.println("boolean " + tossName + " = isStatsAvailable() && stats(\""
- + statsMethodExpr + ":requestStart\", timeStat(\""
- + getProxySimpleName() + "." + syncMethod.getName()
- + "\", getRequestId()));");
+ w.println("boolean " + tossName + " = isStatsAvailable() && stats("
+ + "timeStat(\"" + statsMethodExpr + "\", getRequestId(), \"begin\"));");
w.print(ClientSerializationStreamWriter.class.getSimpleName());
w.print(" ");
@@ -414,9 +411,8 @@
w.println("String " + payloadName + " = " + streamWriterName
+ ".toString();");
- w.println(tossName + " = isStatsAvailable() && stats(\"" + statsMethodExpr
- + ":requestSerialized\", timeStat(\"" + getProxySimpleName() + "."
- + syncMethod.getName() + "\", getRequestId()));");
+ w.println(tossName + " = isStatsAvailable() && stats("
+ + "timeStat(\"" + statsMethodExpr + "\", getRequestId(), \"requestSerialized\"));");
/*
* Depending on the return type for the async method, return a
diff --git a/user/src/com/google/gwt/user/rebind/rpc/TypeHierarchyUtils.java b/user/src/com/google/gwt/user/rebind/rpc/TypeHierarchyUtils.java
index d1c048d..cf93f8f 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/TypeHierarchyUtils.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/TypeHierarchyUtils.java
@@ -35,7 +35,8 @@
/**
* Returns <code>true</code> if the type directly implements the specified
- * interface.
+ * interface. The test is done on erased types; any paramaterizations
+ * supplied in the arguments are ignored.
*
* @param type type to check
* @param intf interface to look for
@@ -44,6 +45,8 @@
*/
public static boolean directlyImplementsInterface(JClassType type,
JClassType intf) {
+ type = type.getErasedType();
+ intf = intf.getErasedType();
return directlyImplementsInterfaceRecursive(new HashSet<JClassType>(),
type, intf);
}
@@ -119,6 +122,8 @@
private static boolean directlyImplementsInterfaceRecursive(
Set<JClassType> seen, JClassType clazz, JClassType intf) {
+ assert (clazz.getErasedType() == clazz);
+ assert (intf.getErasedType() == intf);
if (clazz == intf) {
return true;
@@ -127,6 +132,7 @@
JClassType[] intfImpls = clazz.getImplementedInterfaces();
for (JClassType intfImpl : intfImpls) {
+ intfImpl = intfImpl.getErasedType();
if (!seen.contains(intfImpl)) {
seen.add(intfImpl);
diff --git a/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome.css b/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome.css
index a4b0af5..f35c453 100644
--- a/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome.css
+++ b/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome.css
@@ -29,11 +29,17 @@
a, a:visited, a:hover {
color: #0000AA;
}
-iframe {
- border-top: 2px solid #666;
- border-left: 2px solid #666;
- border-right: 2px solid #bbb;
- border-bottom: 2px solid #bbb;
+
+/**
+ * The reference theme can be used to determine when this style sheet has
+ * loaded. Create a hidden div element with absolute position, assign the style
+ * name below, and attach it to the DOM. Use a timer to detect when the
+ * element's height and width are set to 5px.
+ */
+.gwt-Reference-chrome {
+ height: 5px;
+ width: 5px;
+ zoom: 1;
}
.gwt-Button {
@@ -233,6 +239,13 @@
.gwt-FileUpload {
}
+.gwt-Frame {
+ border-top: 2px solid #666;
+ border-left: 2px solid #666;
+ border-right: 2px solid #bbb;
+ border-bottom: 2px solid #bbb;
+}
+
.gwt-HorizontalSplitPanel {
}
.gwt-HorizontalSplitPanel .hsplitter {
@@ -513,10 +526,14 @@
.gwt-PushButton-down-hovering,
.gwt-PushButton-down-disabled {
margin: 0;
- padding: 3px 5px;
text-decoration: none;
background: url("images/hborder.png") repeat-x 0px -27px;
}
+.gwt-PushButton-up,
+.gwt-PushButton-up-hovering,
+.gwt-PushButton-up-disabled {
+ padding: 3px 5px 3px 5px;
+}
.gwt-PushButton-up {
border: 1px outset #ccc;
cursor: pointer;
@@ -535,6 +552,11 @@
filter: alpha(opacity=40);
zoom: 1;
}
+.gwt-PushButton-down,
+.gwt-PushButton-down-hovering,
+.gwt-PushButton-down-disabled {
+ padding: 4px 4px 2px 6px;
+}
.gwt-PushButton-down {
border: 1px inset #666;
cursor: pointer;
@@ -985,10 +1007,14 @@
.gwt-ToggleButton-down-hovering,
.gwt-ToggleButton-down-disabled {
margin: 0;
- padding: 3px 5px;
text-decoration: none;
background: url("images/hborder.png") repeat-x 0px -27px;
}
+.gwt-ToggleButton-up,
+.gwt-ToggleButton-up-hovering,
+.gwt-ToggleButton-up-disabled {
+ padding: 3px 5px 3px 5px;
+}
.gwt-ToggleButton-up {
border: 1px outset #ccc;
cursor: pointer;
@@ -1007,6 +1033,11 @@
zoom: 1;
filter: alpha(opacity=40);
}
+.gwt-ToggleButton-down,
+.gwt-ToggleButton-down-hovering,
+.gwt-ToggleButton-down-disabled {
+ padding: 4px 4px 2px 6px;
+}
.gwt-ToggleButton-down {
background-position: 0 -513px;
border: 1px inset #ccc;
diff --git a/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome_rtl.css b/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome_rtl.css
index b848170..e5b1a0b 100644
--- a/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome_rtl.css
+++ b/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome_rtl.css
@@ -29,11 +29,17 @@
a, a:visited, a:hover {
color: #0000AA;
}
-iframe {
- border-top: 2px solid #666;
- border-left: 2px solid #666;
- border-right: 2px solid #bbb;
- border-bottom: 2px solid #bbb;
+
+/**
+ * The reference theme can be used to determine when this style sheet has
+ * loaded. Create a hidden div element with absolute position, assign the style
+ * name below, and attach it to the DOM. Use a timer to detect when the
+ * element's height and width are set to 5px.
+ */
+.gwt-Reference-chrome-rtl {
+ height: 5px;
+ width: 5px;
+ zoom: 1;
}
.gwt-Button {
@@ -233,6 +239,13 @@
.gwt-FileUpload {
}
+.gwt-Frame {
+ border-top: 2px solid #666;
+ border-left: 2px solid #666;
+ border-right: 2px solid #bbb;
+ border-bottom: 2px solid #bbb;
+}
+
.gwt-HorizontalSplitPanel {
}
.gwt-HorizontalSplitPanel .hsplitter {
@@ -513,10 +526,14 @@
.gwt-PushButton-down-hovering,
.gwt-PushButton-down-disabled {
margin: 0;
- padding: 3px 5px;
text-decoration: none;
background: url("images/hborder.png") repeat-x 0px -27px;
}
+.gwt-PushButton-up,
+.gwt-PushButton-up-hovering,
+.gwt-PushButton-up-disabled {
+ padding: 3px 5px 3px 5px;
+}
.gwt-PushButton-up {
border: 1px outset #ccc;
cursor: pointer;
@@ -535,6 +552,11 @@
filter: alpha(opacity=40);
zoom: 1;
}
+.gwt-PushButton-down,
+.gwt-PushButton-down-hovering,
+.gwt-PushButton-down-disabled {
+ padding: 4px 4px 2px 6px;
+}
.gwt-PushButton-down {
border: 1px inset #666;
cursor: pointer;
@@ -985,10 +1007,14 @@
.gwt-ToggleButton-down-hovering,
.gwt-ToggleButton-down-disabled {
margin: 0;
- padding: 3px 5px;
text-decoration: none;
background: url("images/hborder.png") repeat-x 0px -27px;
}
+.gwt-ToggleButton-up,
+.gwt-ToggleButton-up-hovering,
+.gwt-ToggleButton-up-disabled {
+ padding: 3px 5px 3px 5px;
+}
.gwt-ToggleButton-up {
border: 1px outset #ccc;
cursor: pointer;
@@ -1007,6 +1033,11 @@
zoom: 1;
filter: alpha(opacity=40);
}
+.gwt-ToggleButton-down,
+.gwt-ToggleButton-down-hovering,
+.gwt-ToggleButton-down-disabled {
+ padding: 4px 4px 2px 6px;
+}
.gwt-ToggleButton-down {
background-position: 0 -513px;
border: 1px inset #ccc;
diff --git a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css
index b1dc513..0b166cb 100644
--- a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css
+++ b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css
@@ -29,11 +29,17 @@
a, a:visited, a:hover {
color: #ccf;
}
-iframe {
- border-top: 2px solid #666;
- border-left: 2px solid #666;
- border-right: 2px solid #bbb;
- border-bottom: 2px solid #bbb;
+
+/**
+ * The reference theme can be used to determine when this style sheet has
+ * loaded. Create a hidden div element with absolute position, assign the style
+ * name below, and attach it to the DOM. Use a timer to detect when the
+ * element's height and width are set to 5px.
+ */
+.gwt-Reference-dark {
+ height: 5px;
+ width: 5px;
+ zoom: 1;
}
.gwt-Button {
@@ -196,6 +202,13 @@
.gwt-FileUpload {
}
+.gwt-Frame {
+ border-top: 2px solid #666;
+ border-left: 2px solid #666;
+ border-right: 2px solid #bbb;
+ border-bottom: 2px solid #bbb;
+}
+
.gwt-HorizontalSplitPanel {
}
.gwt-HorizontalSplitPanel .hsplitter {
@@ -477,10 +490,14 @@
.gwt-PushButton-down-hovering,
.gwt-PushButton-down-disabled {
margin: 0;
- padding: 3px 5px;
text-decoration: none;
background: url("images/hborder.png") repeat-x 0px -27px;
}
+.gwt-PushButton-up,
+.gwt-PushButton-up-hovering,
+.gwt-PushButton-up-disabled {
+ padding: 3px 5px 3px 5px;
+}
.gwt-PushButton-up {
border: 1px outset #000;
cursor: pointer;
@@ -499,6 +516,11 @@
filter: alpha(opacity=40);
zoom: 1;
}
+.gwt-PushButton-down,
+.gwt-PushButton-down-hovering,
+.gwt-PushButton-down-disabled {
+ padding: 4px 4px 2px 6px;
+}
.gwt-PushButton-down {
border: 1px inset #000;
cursor: pointer;
@@ -811,10 +833,14 @@
.gwt-ToggleButton-down-hovering,
.gwt-ToggleButton-down-disabled {
margin: 0;
- padding: 3px 5px;
text-decoration: none;
background: url("images/hborder.png") repeat-x 0px -27px;
}
+.gwt-ToggleButton-up,
+.gwt-ToggleButton-up-hovering,
+.gwt-ToggleButton-up-disabled {
+ padding: 3px 5px 3px 5px;
+}
.gwt-ToggleButton-up {
border: 1px outset #ccc;
cursor: pointer;
@@ -833,6 +859,11 @@
zoom: 1;
filter: alpha(opacity=40);
}
+.gwt-ToggleButton-down,
+.gwt-ToggleButton-down-hovering,
+.gwt-ToggleButton-down-disabled {
+ padding: 4px 4px 2px 6px;
+}
.gwt-ToggleButton-down {
background-position: 0 -513px;
border: 1px inset #ccc;
diff --git a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css
index d7bf2f7..e5804f9 100644
--- a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css
+++ b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css
@@ -29,11 +29,17 @@
a, a:visited, a:hover {
color: #ccf;
}
-iframe {
- border-top: 2px solid #666;
- border-left: 2px solid #666;
- border-right: 2px solid #bbb;
- border-bottom: 2px solid #bbb;
+
+/**
+ * The reference theme can be used to determine when this style sheet has
+ * loaded. Create a hidden div element with absolute position, assign the style
+ * name below, and attach it to the DOM. Use a timer to detect when the
+ * element's height and width are set to 5px.
+ */
+.gwt-Reference-dark-rtl {
+ height: 5px;
+ width: 5px;
+ zoom: 1;
}
.gwt-Button {
@@ -196,6 +202,13 @@
.gwt-FileUpload {
}
+.gwt-Frame {
+ border-top: 2px solid #666;
+ border-left: 2px solid #666;
+ border-right: 2px solid #bbb;
+ border-bottom: 2px solid #bbb;
+}
+
.gwt-HorizontalSplitPanel {
}
.gwt-HorizontalSplitPanel .hsplitter {
@@ -477,10 +490,14 @@
.gwt-PushButton-down-hovering,
.gwt-PushButton-down-disabled {
margin: 0;
- padding: 3px 5px;
text-decoration: none;
background: url("images/hborder.png") repeat-x 0px -27px;
}
+.gwt-PushButton-up,
+.gwt-PushButton-up-hovering,
+.gwt-PushButton-up-disabled {
+ padding: 3px 5px 3px 5px;
+}
.gwt-PushButton-up {
border: 1px outset #000;
cursor: pointer;
@@ -499,6 +516,11 @@
filter: alpha(opacity=40);
zoom: 1;
}
+.gwt-PushButton-down,
+.gwt-PushButton-down-hovering,
+.gwt-PushButton-down-disabled {
+ padding: 4px 4px 2px 6px;
+}
.gwt-PushButton-down {
border: 1px inset #000;
cursor: pointer;
@@ -811,10 +833,14 @@
.gwt-ToggleButton-down-hovering,
.gwt-ToggleButton-down-disabled {
margin: 0;
- padding: 3px 5px;
text-decoration: none;
background: url("images/hborder.png") repeat-x 0px -27px;
}
+.gwt-ToggleButton-up,
+.gwt-ToggleButton-up-hovering,
+.gwt-ToggleButton-up-disabled {
+ padding: 3px 5px 3px 5px;
+}
.gwt-ToggleButton-up {
border: 1px outset #ccc;
cursor: pointer;
@@ -833,6 +859,11 @@
zoom: 1;
filter: alpha(opacity=40);
}
+.gwt-ToggleButton-down,
+.gwt-ToggleButton-down-hovering,
+.gwt-ToggleButton-down-disabled {
+ padding: 4px 4px 2px 6px;
+}
.gwt-ToggleButton-down {
background-position: 0 -513px;
border: 1px inset #ccc;
diff --git a/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard.css b/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard.css
index e22b678..4f2aa6b 100644
--- a/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard.css
+++ b/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard.css
@@ -29,11 +29,17 @@
a, a:visited, a:hover {
color: #0000AA;
}
-iframe {
- border-top: 2px solid #666;
- border-left: 2px solid #666;
- border-right: 2px solid #bbb;
- border-bottom: 2px solid #bbb;
+
+/**
+ * The reference theme can be used to determine when this style sheet has
+ * loaded. Create a hidden div element with absolute position, assign the style
+ * name below, and attach it to the DOM. Use a timer to detect when the
+ * element's height and width are set to 5px.
+ */
+.gwt-Reference-standard {
+ height: 5px;
+ width: 5px;
+ zoom: 1;
}
.gwt-Button {
@@ -233,6 +239,13 @@
.gwt-FileUpload {
}
+.gwt-Frame {
+ border-top: 2px solid #666;
+ border-left: 2px solid #666;
+ border-right: 2px solid #bbb;
+ border-bottom: 2px solid #bbb;
+}
+
.gwt-HorizontalSplitPanel {
}
.gwt-HorizontalSplitPanel .hsplitter {
@@ -513,10 +526,14 @@
.gwt-PushButton-down-hovering,
.gwt-PushButton-down-disabled {
margin: 0;
- padding: 3px 5px;
text-decoration: none;
background: url("images/hborder.png") repeat-x 0px -27px;
}
+.gwt-PushButton-up,
+.gwt-PushButton-up-hovering,
+.gwt-PushButton-up-disabled {
+ padding: 3px 5px 3px 5px;
+}
.gwt-PushButton-up {
border: 1px outset #ccc;
cursor: pointer;
@@ -535,6 +552,11 @@
filter: alpha(opacity=40);
zoom: 1;
}
+.gwt-PushButton-down,
+.gwt-PushButton-down-hovering,
+.gwt-PushButton-down-disabled {
+ padding: 4px 4px 2px 6px;
+}
.gwt-PushButton-down {
border: 1px inset #666;
cursor: pointer;
@@ -984,10 +1006,14 @@
.gwt-ToggleButton-down-hovering,
.gwt-ToggleButton-down-disabled {
margin: 0;
- padding: 3px 5px;
text-decoration: none;
background: url("images/hborder.png") repeat-x 0px -27px;
}
+.gwt-ToggleButton-up,
+.gwt-ToggleButton-up-hovering,
+.gwt-ToggleButton-up-disabled {
+ padding: 3px 5px 3px 5px;
+}
.gwt-ToggleButton-up {
border: 1px outset #ccc;
cursor: pointer;
@@ -1006,6 +1032,11 @@
zoom: 1;
filter: alpha(opacity=40);
}
+.gwt-ToggleButton-down,
+.gwt-ToggleButton-down-hovering,
+.gwt-ToggleButton-down-disabled {
+ padding: 4px 4px 2px 6px;
+}
.gwt-ToggleButton-down {
background-position: 0 -513px;
border: 1px inset #ccc;
diff --git a/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard_rtl.css b/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard_rtl.css
index 1aeae9e..e86c67d 100644
--- a/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard_rtl.css
+++ b/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard_rtl.css
@@ -29,11 +29,17 @@
a, a:visited, a:hover {
color: #0000AA;
}
-iframe {
- border-top: 2px solid #666;
- border-left: 2px solid #666;
- border-right: 2px solid #bbb;
- border-bottom: 2px solid #bbb;
+
+/**
+ * The reference theme can be used to determine when this style sheet has
+ * loaded. Create a hidden div element with absolute position, assign the style
+ * name below, and attach it to the DOM. Use a timer to detect when the
+ * element's height and width are set to 5px.
+ */
+.gwt-Reference-standard-rtl {
+ height: 5px;
+ width: 5px;
+ zoom: 1;
}
.gwt-Button {
@@ -233,6 +239,13 @@
.gwt-FileUpload {
}
+.gwt-Frame {
+ border-top: 2px solid #666;
+ border-left: 2px solid #666;
+ border-right: 2px solid #bbb;
+ border-bottom: 2px solid #bbb;
+}
+
.gwt-HorizontalSplitPanel {
}
.gwt-HorizontalSplitPanel .hsplitter {
@@ -513,10 +526,14 @@
.gwt-PushButton-down-hovering,
.gwt-PushButton-down-disabled {
margin: 0;
- padding: 3px 5px;
text-decoration: none;
background: url("images/hborder.png") repeat-x 0px -27px;
}
+.gwt-PushButton-up,
+.gwt-PushButton-up-hovering,
+.gwt-PushButton-up-disabled {
+ padding: 3px 5px 3px 5px;
+}
.gwt-PushButton-up {
border: 1px outset #ccc;
cursor: pointer;
@@ -535,6 +552,11 @@
filter: alpha(opacity=40);
zoom: 1;
}
+.gwt-PushButton-down,
+.gwt-PushButton-down-hovering,
+.gwt-PushButton-down-disabled {
+ padding: 4px 4px 2px 6px;
+}
.gwt-PushButton-down {
border: 1px inset #666;
cursor: pointer;
@@ -984,10 +1006,14 @@
.gwt-ToggleButton-down-hovering,
.gwt-ToggleButton-down-disabled {
margin: 0;
- padding: 3px 5px;
text-decoration: none;
background: url("images/hborder.png") repeat-x 0px -27px;
}
+.gwt-ToggleButton-up,
+.gwt-ToggleButton-up-hovering,
+.gwt-ToggleButton-up-disabled {
+ padding: 3px 5px 3px 5px;
+}
.gwt-ToggleButton-up {
border: 1px outset #ccc;
cursor: pointer;
@@ -1006,6 +1032,11 @@
zoom: 1;
filter: alpha(opacity=40);
}
+.gwt-ToggleButton-down,
+.gwt-ToggleButton-down-hovering,
+.gwt-ToggleButton-down-disabled {
+ padding: 4px 4px 2px 6px;
+}
.gwt-ToggleButton-down {
background-position: 0 -513px;
border: 1px inset #ccc;
diff --git a/user/super/com/google/gwt/emul/java/util/Collections.java b/user/super/com/google/gwt/emul/java/util/Collections.java
index 252236b..d890482 100644
--- a/user/super/com/google/gwt/emul/java/util/Collections.java
+++ b/user/super/com/google/gwt/emul/java/util/Collections.java
@@ -75,9 +75,14 @@
}
}
- public static final List<?> EMPTY_LIST = unmodifiableList(new ArrayList<Object>());
- public static final Map<?, ?> EMPTY_MAP = unmodifiableMap(new HashMap<Object, Object>());
- public static final Set<?> EMPTY_SET = unmodifiableSet(new HashSet<Object>());
+ @SuppressWarnings("unchecked")
+ public static final List EMPTY_LIST = unmodifiableList(new ArrayList());
+
+ @SuppressWarnings("unchecked")
+ public static final Map EMPTY_MAP = unmodifiableMap(new HashMap());
+
+ @SuppressWarnings("unchecked")
+ public static final Set EMPTY_SET = unmodifiableSet(new HashSet());
private static Comparator<Comparable<Object>> reverseComparator = new Comparator<Comparable<Object>>() {
public int compare(Comparable<Object> o1, Comparable<Object> o2) {
diff --git a/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/GWTTestCase.java b/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/GWTTestCase.java
index 10f2906..ed205b2 100644
--- a/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/GWTTestCase.java
+++ b/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/GWTTestCase.java
@@ -238,7 +238,7 @@
}
@Override
- protected void tearDown() throws Exception {
+ protected final void tearDown() throws Exception {
gwtTearDown();
}
diff --git a/user/test/com/google/gwt/dev/jjs/test/JStaticEvalTest.java b/user/test/com/google/gwt/dev/jjs/test/JStaticEvalTest.java
index 6e1d360..e445b15 100644
--- a/user/test/com/google/gwt/dev/jjs/test/JStaticEvalTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/JStaticEvalTest.java
@@ -166,6 +166,7 @@
assertEquals(65536, ((char) returnIntNegOne()) + 1);
assertEquals(10.0, ((double) returnIntFive()) + ((double) returnIntFive()));
+ assertEquals(1.5, returnFloatOneHalf() + 1);
}
/**
@@ -334,6 +335,10 @@
return 1.0F;
}
+ private float returnFloatOneHalf() {
+ return 0.5F;
+ }
+
private int returnIntFive() {
return 5;
}
diff --git a/user/test/com/google/gwt/user/RPCSuite.java b/user/test/com/google/gwt/user/RPCSuite.java
index 9e63432..79e1b93 100644
--- a/user/test/com/google/gwt/user/RPCSuite.java
+++ b/user/test/com/google/gwt/user/RPCSuite.java
@@ -25,6 +25,7 @@
import com.google.gwt.user.client.rpc.UnicodeEscapingTest;
import com.google.gwt.user.client.rpc.ValueTypesTest;
import com.google.gwt.user.rebind.rpc.SerializableTypeOracleBuilderTest;
+import com.google.gwt.user.rebind.rpc.TypeHierarchyUtilsTest;
import com.google.gwt.user.server.rpc.RPCTest;
import com.google.gwt.user.server.rpc.SerializationPolicyLoaderTest;
import com.google.gwt.user.server.rpc.impl.LegacySerializationPolicyTest;
@@ -51,6 +52,7 @@
"Test for com.google.gwt.user.client.rpc");
suite.addTestSuite(SerializableTypeOracleBuilderTest.class);
+ suite.addTestSuite(TypeHierarchyUtilsTest.class);
suite.addTestSuite(RPCTest.class);
suite.addTestSuite(ValueTypesTest.class);
suite.addTestSuite(EnumsTest.class);
diff --git a/user/test/com/google/gwt/user/client/ui/DecoratedPopupTest.java b/user/test/com/google/gwt/user/client/ui/DecoratedPopupTest.java
index bc20531..3528888 100644
--- a/user/test/com/google/gwt/user/client/ui/DecoratedPopupTest.java
+++ b/user/test/com/google/gwt/user/client/ui/DecoratedPopupTest.java
@@ -20,6 +20,32 @@
*/
public class DecoratedPopupTest extends PopupTest {
@Override
+ public void testDependantPopupPanel() {
+ // Create the dependent popup
+ final PopupPanel dependantPopup = createPopupPanel();
+ dependantPopup.setAnimationEnabled(true);
+
+ // Create the primary popup
+ final DecoratedPopupPanel primaryPopup = new DecoratedPopupPanel(false,
+ false) {
+ @Override
+ protected void onAttach() {
+ dependantPopup.show();
+ super.onAttach();
+ }
+
+ @Override
+ protected void onDetach() {
+ dependantPopup.hide();
+ super.onDetach();
+ }
+ };
+ primaryPopup.setAnimationEnabled(true);
+
+ testDependantPopupPanel(primaryPopup);
+ }
+
+ @Override
protected PopupPanel createPopupPanel() {
return new DecoratedPopupPanel();
}
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 1a3f4e0..04a9127 100644
--- a/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
+++ b/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
@@ -32,7 +32,10 @@
/**
* Test the accessors.
*/
+ @Override
public void testAccessors() {
+ super.testAccessors();
+
// Set the widget
DialogBox box1 = new DialogBox();
assertNull(box1.getWidget());
@@ -91,4 +94,34 @@
});
delayTestFinish(250);
}
+
+ @Override
+ public void testDependantPopupPanel() {
+ // Create the dependent popup
+ final PopupPanel dependantPopup = createPopupPanel();
+ dependantPopup.setAnimationEnabled(true);
+
+ // Create the primary popup
+ final DialogBox primaryPopup = new DialogBox(false, false) {
+ @Override
+ protected void onAttach() {
+ dependantPopup.show();
+ super.onAttach();
+ }
+
+ @Override
+ protected void onDetach() {
+ dependantPopup.hide();
+ super.onDetach();
+ }
+ };
+ primaryPopup.setAnimationEnabled(true);
+
+ testDependantPopupPanel(primaryPopup);
+ }
+
+ @Override
+ protected PopupPanel createPopupPanel() {
+ return new DialogBox();
+ }
}
diff --git a/user/test/com/google/gwt/user/client/ui/HistoryTest.java b/user/test/com/google/gwt/user/client/ui/HistoryTest.java
index 2c5c17b..b06914a 100644
--- a/user/test/com/google/gwt/user/client/ui/HistoryTest.java
+++ b/user/test/com/google/gwt/user/client/ui/HistoryTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * 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
@@ -26,6 +26,7 @@
*/
public class HistoryTest extends GWTTestCase {
+ @Override
public String getModuleName() {
return "com.google.gwt.user.User";
}
@@ -164,4 +165,29 @@
// event to fire.
History.newItem("foobar");
}
+
+ /*
+ * Test against issue #2500. IE6 has a bug that causes it to not report any
+ * part of the current fragment after a '?' when read from location.hash;
+ * make sure that on affected browsers, we're not relying on this.
+ */
+ public void testTokenWithQuestionmark() {
+ delayTestFinish(5000);
+ final String token = "foo?bar";
+
+ History.addHistoryListener(new HistoryListener() {
+ public void onHistoryChanged(String historyToken) {
+
+ if (historyToken == null) {
+ fail("historyToken should not be null");
+ }
+
+ assertEquals(token, historyToken);
+ History.removeHistoryListener(this);
+ finishTest();
+ }
+ });
+
+ History.newItem(token);
+ }
}
diff --git a/user/test/com/google/gwt/user/client/ui/PopupTest.java b/user/test/com/google/gwt/user/client/ui/PopupTest.java
index d0e862f..f7462ba 100644
--- a/user/test/com/google/gwt/user/client/ui/PopupTest.java
+++ b/user/test/com/google/gwt/user/client/ui/PopupTest.java
@@ -17,6 +17,7 @@
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
/**
@@ -51,6 +52,37 @@
assertTrue(popup.isAnimationEnabled());
}
+ /**
+ * Issue 2463: If a {@link PopupPanel} contains a dependent {@link PopupPanel}
+ * that is hidden or shown in the onDetach or onAttach method, we could run
+ * into conflicts with the animations. The {@link MenuBar} exhibits this
+ * behavior because, when we detach a {@link MenuBar} from the page, it closes
+ * all of its sub menus, each located in a different {@link PopupPanel}.
+ */
+ public void testDependantPopupPanel() {
+ // Create the dependent popup
+ final PopupPanel dependantPopup = createPopupPanel();
+ dependantPopup.setAnimationEnabled(true);
+
+ // Create the primary popup
+ final PopupPanel primaryPopup = new PopupPanel(false, false) {
+ @Override
+ protected void onAttach() {
+ dependantPopup.show();
+ super.onAttach();
+ }
+
+ @Override
+ protected void onDetach() {
+ dependantPopup.hide();
+ super.onDetach();
+ }
+ };
+ primaryPopup.setAnimationEnabled(true);
+
+ testDependantPopupPanel(primaryPopup);
+ }
+
public void testPopup() {
// Get rid of window margins so we can test absolute position.
Window.setMargin("0px");
@@ -112,9 +144,47 @@
}
/**
+ * Issue 2481: Try to set the contents of the popup while the popup is
+ * attached. When we hide the popup, this should not leave the popup in an
+ * invalid attach state.
+ */
+ public void testSetWidgetWhileAttached() {
+ PopupPanel popup = createPopupPanel();
+ popup.show();
+ popup.setWidget(new Label("test"));
+ popup.hide();
+ }
+
+ /**
* Create a new PopupPanel.
*/
protected PopupPanel createPopupPanel() {
return new PopupPanel();
}
+
+ /**
+ * @see #testDependantPopupPanel()
+ */
+ protected void testDependantPopupPanel(final PopupPanel primaryPopup) {
+ // Show the popup
+ primaryPopup.show();
+
+ // Hide the popup
+ new Timer() {
+ @Override
+ public void run() {
+ primaryPopup.hide();
+ }
+ }.schedule(1000);
+
+ // Give time for any errors to occur
+ new Timer() {
+ @Override
+ public void run() {
+ finishTest();
+ }
+ }.schedule(2000);
+
+ delayTestFinish(5000);
+ }
}
diff --git a/user/test/com/google/gwt/user/rebind/rpc/TypeHierarchyUtilsTest.java b/user/test/com/google/gwt/user/rebind/rpc/TypeHierarchyUtilsTest.java
new file mode 100644
index 0000000..2ef52d0
--- /dev/null
+++ b/user/test/com/google/gwt/user/rebind/rpc/TypeHierarchyUtilsTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.rebind.rpc;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.NotFoundException;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.javac.MockCompilationUnit;
+import com.google.gwt.dev.javac.TypeOracleTestingUtils;
+import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
+
+import junit.framework.TestCase;
+
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tests for {@link TypeHierarchyUtils}.
+ */
+public class TypeHierarchyUtilsTest extends TestCase {
+ private static TreeLogger createLogger() {
+ PrintWriterTreeLogger logger = new PrintWriterTreeLogger(new PrintWriter(
+ System.err));
+ logger.setMaxDetail(TreeLogger.ERROR);
+ return logger;
+ }
+
+ public void testParameterizedInterface() throws UnableToCompleteException,
+ NotFoundException {
+ Set<CompilationUnit> units = new HashSet<CompilationUnit>();
+ {
+ StringBuilder code = new StringBuilder();
+ code.append("interface A<T> { }\n");
+ units.add(createMockCompilationUnit("A", code));
+ }
+ {
+ StringBuilder code = new StringBuilder();
+ code.append("interface B extends A<String> { }\n");
+ units.add(createMockCompilationUnit("A", code));
+ }
+ TreeLogger logger = createLogger();
+ TypeOracle to = TypeOracleTestingUtils.buildStandardTypeOracleWith(logger,
+ units);
+ JClassType a = to.getType("A");
+ JClassType b = to.getType("B");
+
+ List<JClassType> subtypesOfA = TypeHierarchyUtils.getImmediateSubtypes(a);
+ assertEquals(1, subtypesOfA.size());
+ assertTrue(subtypesOfA.contains(b));
+ }
+
+ private MockCompilationUnit createMockCompilationUnit(final String qname,
+ StringBuilder code) {
+ return new MockCompilationUnit(qname, code.toString());
+ }
+}