253220 - better software update - in place software update, etc etc. glory!

This commit is contained in:
ben%bengoodger.com 2004-08-05 02:45:27 +00:00
parent 0d6c204cda
commit 582c9d22c5
24 changed files with 1508 additions and 470 deletions

View File

@ -59,7 +59,7 @@ pref("app.build_id",
);
pref("app.extensions.version", "0.9");
pref("update.app.enabled", true);
pref("update.app.enabled", true); // Whether or not app updates are enabled
pref("update.app.url", "chrome://mozapps/locale/update/update.properties");
pref("update.app.updatesAvailable", false);
pref("update.app.updateVersion", "");
@ -87,6 +87,8 @@ pref("update.interval", 3600000); // Check each of the above inter
// every 60 mins
pref("update.showSlidingNotification", true); // Windows-only slide-up taskbar
// notification.
pref("update.app.performed", false); // Whether or not an update has been
// performed this session.
// These prefs relate to the number and severity of updates available. This is a
// cache that the browser notification mechanism uses to determine if it should show

View File

@ -5,7 +5,7 @@ function upgradeCleanup()
var srDest = $SpaceRequired$;
var err = initInstall("$ProductName$", "Browser", "$Version$");
var err = initInstall("$ProductName$", "Firefox", "$Version$");
logComment("initInstall: " + err);
var communicatorFolder = getFolder("Program");

View File

@ -1,4 +1,4 @@
var err = initInstall("$ProductName$ Help", "help", "$Version$");
var err = initInstall("$ProductName$ Help", "Help", "$Version$");
logComment("initInstall: " + err);
addFile("$ProductName$ Help",

View File

@ -18,7 +18,7 @@ var chromeName = chromeNode + ".jar";
var platformName = langcode + "-" + platformNode + ".jar";
var localeName = "locale/" + chromeNode + "/";
err = initInstall(prettyName, regName, "$Version$");
err = initInstall(prettyName, "en-US", "$Version$");
logComment("initInstall: " + err);
fProgram = getFolder("Program");

View File

@ -188,7 +188,7 @@ bin/components/nsSidebar.js
; bin/components/nsUpdateNotifier.js not needed for firefox
bin/components/nsXmlRpcClient.js
bin/components/nsExtensionManager.js
bin/components/nsBackgroundUpdateService.js
bin/components/nsUpdateService.js
bin/components/extensions.xpt
bin/components/update.xpt

View File

@ -321,6 +321,7 @@ function upgradeCleanup()
deleteThisFile("Chrome", "en-win.jar");
deleteThisFile("Components", "compreg.dat");
deleteThisFile("Components", "xpti.dat");
deleteThisFile("Components", "nsBackgroundUpdateService.js");
deleteThisFile("Program", "defaults/pref/all.js");
deleteThisFile("Program", "defaults/pref/security-prefs.js");
deleteThisFile("Program", "defaults/pref/winpref.js");
@ -351,7 +352,7 @@ if(args == "-greLocal")
gGreLocal = true;
srDest = $SpaceRequired$:bin;
err = initInstall("$ProductName$", "Browser", "$Version$");
err = initInstall("$ProductName$", "Firefox", "$Version$");
logComment("initInstall: " + err);
fProgram = getFolder("Program");

View File

@ -1,4 +1,4 @@
var err = initInstall("$ProductName$ Help", "help", "$Version$");
var err = initInstall("$ProductName$ Help", "Help", "$Version$");
logComment("initInstall: " + err);
addFile("$ProductName$ Help",

View File

@ -20,7 +20,7 @@ var platformName = langcode + "-" + platformNode + ".jar";
var localeName = "locale/" + chromeNode + "/";
srDest = $SpaceRequired$:bin;
err = initInstall(prettyName, regName, "$Version$");
err = initInstall(prettyName, "en-US", "$Version$");
logComment("initInstall: " + err);
fProgram = getFolder("Program");

View File

@ -185,7 +185,7 @@ bin\components\nsProxyAutoConfig.js
bin\components\nsSidebar.js
bin\components\nsXmlRpcClient.js
bin\components\nsExtensionManager.js
bin\components\nsBackgroundUpdateService.js
bin\components\nsUpdateService.js
bin\components\extensions.xpt
bin\components\update.xpt

View File

@ -1927,7 +1927,7 @@ nsChromeRegistry::SetProviderForPackage(const nsACString& aProvider,
if (aUseProfile && !mProfileInitialized) {
rv = LoadProfileDataSource();
NS_ENSURE_TRUE(rv, rv);
if (NS_FAILED(rv)) return rv;
}
// Figure out which file we're needing to modify, e.g., is it the install
@ -1952,42 +1952,42 @@ nsChromeRegistry::SetProviderForPackage(const nsACString& aProvider,
NS_IMETHODIMP nsChromeRegistry::SelectSkinForPackage(const nsACString& aSkin,
const PRUnichar *aPackageName,
PRBool aUseProfile)
PRBool aUseProfile)
{
return SelectProviderForPackage(NS_LITERAL_CSTRING("skin"), aSkin, aPackageName, mSelectedSkin, aUseProfile, PR_TRUE);
}
NS_IMETHODIMP nsChromeRegistry::SelectLocaleForPackage(const nsACString& aLocale,
const PRUnichar *aPackageName,
PRBool aUseProfile)
PRBool aUseProfile)
{
return SelectProviderForPackage(NS_LITERAL_CSTRING("locale"), aLocale, aPackageName, mSelectedLocale, aUseProfile, PR_TRUE);
}
NS_IMETHODIMP nsChromeRegistry::DeselectSkinForPackage(const nsACString& aSkin,
const PRUnichar *aPackageName,
PRBool aUseProfile)
const PRUnichar *aPackageName,
PRBool aUseProfile)
{
return SelectProviderForPackage(NS_LITERAL_CSTRING("skin"), aSkin, aPackageName, mSelectedSkin, aUseProfile, PR_FALSE);
}
NS_IMETHODIMP nsChromeRegistry::DeselectLocaleForPackage(const nsACString& aLocale,
const PRUnichar *aPackageName,
PRBool aUseProfile)
const PRUnichar *aPackageName,
PRBool aUseProfile)
{
return SelectProviderForPackage(NS_LITERAL_CSTRING("locale"), aLocale, aPackageName, mSelectedLocale, aUseProfile, PR_FALSE);
}
NS_IMETHODIMP nsChromeRegistry::IsSkinSelectedForPackage(const nsACString& aSkin,
const PRUnichar *aPackageName,
PRBool aUseProfile, PRBool* aResult)
const PRUnichar *aPackageName,
PRBool aUseProfile, PRBool* aResult)
{
return IsProviderSelectedForPackage(NS_LITERAL_CSTRING("skin"), aSkin, aPackageName, mSelectedSkin, aUseProfile, aResult);
}
NS_IMETHODIMP nsChromeRegistry::IsLocaleSelectedForPackage(const nsACString& aLocale,
const PRUnichar *aPackageName,
PRBool aUseProfile, PRBool* aResult)
const PRUnichar *aPackageName,
PRBool aUseProfile, PRBool* aResult)
{
return IsProviderSelectedForPackage(NS_LITERAL_CSTRING("locale"), aLocale, aPackageName, mSelectedLocale, aUseProfile, aResult);
}
@ -2221,7 +2221,7 @@ nsChromeRegistry::InstallProvider(const nsACString& aProviderType,
PRBool aRemove)
{
// XXX don't allow local chrome overrides of install chrome!
#ifdef DEBUG
#ifdef DEBUG2
printf("*** Chrome Registration of %-7s: Checking for contents.rdf at %s\n", PromiseFlatCString(aProviderType).get(), PromiseFlatCString(aBaseURL).get());
#endif
@ -2665,7 +2665,7 @@ NS_IMETHODIMP nsChromeRegistry::UninstallSkin(const nsACString& aSkinName, PRBoo
DeselectSkin(aSkinName, aUseProfile);
// Now uninstall it.
return UninstallProvider(NS_LITERAL_CSTRING("skin"), aSkinName, aUseProfile);
return UninstallProvider(NS_LITERAL_CSTRING("skin"), aSkinName, aUseProfile);
}
NS_IMETHODIMP nsChromeRegistry::UninstallLocale(const nsACString& aLocaleName, PRBool aUseProfile)
@ -2676,41 +2676,49 @@ NS_IMETHODIMP nsChromeRegistry::UninstallLocale(const nsACString& aLocaleName, P
return UninstallProvider(NS_LITERAL_CSTRING("locale"), aLocaleName, aUseProfile);
}
static void GetURIForPackage(nsIIOService* aIOService, const nsACString& aPackageName, nsIURI** aResult)
static void GetURIForProvider(nsIIOService* aIOService, const nsACString& aProviderName,
const nsACString& aProviderType, nsIURI** aResult)
{
nsCAutoString chromeURL("chrome://");
chromeURL += aPackageName;
chromeURL += "/content/";
chromeURL += aProviderName;
chromeURL += "/";
chromeURL += aProviderType;
chromeURL += "/";
nsCOMPtr<nsIURI> uri;
aIOService->NewURI(chromeURL, nsnull, nsnull, aResult);
}
NS_IMETHODIMP nsChromeRegistry::UninstallPackage(const nsACString& aPackageName, PRBool aUseProfile)
nsresult nsChromeRegistry::UninstallFromDynamicDataSource(const nsACString& aPackageName,
PRBool aIsOverlay, PRBool aUseProfile)
{
// Remove the package from the package list
nsresult rv = UninstallProvider(NS_LITERAL_CSTRING("package"), aPackageName, aUseProfile);
if (NS_FAILED(rv)) return rv;
nsresult rv;
// Now disconnect any overlay entries that this package may have supplied.
// This is a little tricky - the chrome registry identifies that packages may have
// dynamic overlays specified like so:
// - each package entry in the chrome registry datasource has a "chrome:hasOverlays"
// property set to "true"
// Disconnect any overlay/stylesheet entries that this package may have
// supplied. This is a little tricky - the chrome registry identifies
// that packages may have dynamic overlays/stylesheets specified like so:
// - each package entry in the chrome registry datasource has a
// "chrome:hasOverlays"/"chrome:hasStylesheets" property set to "true"
// - if this property is set, the chrome registry knows to load a dynamic overlay
// datasource over in <profile>/chrome/overlayinfo/<package_name>/overlays.rdf
// datasource over in
// <profile>/chrome/overlayinfo/<package_name>/content/overlays.rdf
// or
// <profile>/chrome/overlayinfo/<package_name>/skin/stylesheets.rdf
// To remove this dynamic overlay info when we disable a package:
// - first get an enumeration of all the packages that have the "hasOverlays"
// property set.
// - walk this list, loading the Dynamic Datasource (overlays.rdf) for each
// package
// - first get an enumeration of all the packages that have the
// "hasOverlays" and "hasStylesheets" properties set.
// - walk this list, loading the Dynamic Datasource (overlays.rdf/
// stylesheets.rdf) for each package
// - enumerate the Seqs in each Dynamic Datasource
// - for each seq, remove entries that refer to chrome URLs that are supplied
// by the package we're removing.
nsCOMPtr<nsIIOService> ioServ(do_GetService(NS_IOSERVICE_CONTRACTID));
nsCOMPtr<nsIURI> uninstallURI;
GetURIForPackage(ioServ, aPackageName, getter_AddRefs(uninstallURI));
const nsACString& providerType = aIsOverlay ? NS_LITERAL_CSTRING("content")
: NS_LITERAL_CSTRING("skin");
GetURIForProvider(ioServ, aPackageName, providerType,
getter_AddRefs(uninstallURI));
if (!uninstallURI) return NS_ERROR_OUT_OF_MEMORY;
nsCAutoString uninstallHost;
uninstallURI->GetHost(uninstallHost);
@ -2719,7 +2727,8 @@ NS_IMETHODIMP nsChromeRegistry::UninstallPackage(const nsACString& aPackageName,
mRDFService->GetLiteral(NS_LITERAL_STRING("true").get(), getter_AddRefs(trueLiteral));
nsCOMPtr<nsISimpleEnumerator> e;
mChromeDataSource->GetSources(mHasOverlays, trueLiteral, PR_TRUE, getter_AddRefs(e));
mChromeDataSource->GetSources(aIsOverlay ? mHasOverlays : mHasStylesheets,
trueLiteral, PR_TRUE, getter_AddRefs(e));
do {
PRBool hasMore;
e->HasMoreElements(&hasMore);
@ -2735,13 +2744,13 @@ NS_IMETHODIMP nsChromeRegistry::UninstallPackage(const nsACString& aPackageName,
val.Cut(0, NS_LITERAL_CSTRING("urn:mozilla:package:").Length());
nsCOMPtr<nsIURI> sourcePackageURI;
GetURIForPackage(ioServ, val, getter_AddRefs(sourcePackageURI));
GetURIForProvider(ioServ, val, providerType, getter_AddRefs(sourcePackageURI));
if (!sourcePackageURI) return NS_ERROR_OUT_OF_MEMORY;
PRBool states[] = { PR_FALSE, PR_TRUE };
for (PRInt32 i = 0; i < 2; ++i) {
nsCOMPtr<nsIRDFDataSource> overlayDS;
rv = GetDynamicDataSource(sourcePackageURI, PR_TRUE, states[i], PR_FALSE,
rv = GetDynamicDataSource(sourcePackageURI, aIsOverlay, states[i], PR_FALSE,
getter_AddRefs(overlayDS));
if (NS_FAILED(rv) || !overlayDS) continue;
@ -2816,6 +2825,125 @@ NS_IMETHODIMP nsChromeRegistry::UninstallPackage(const nsACString& aPackageName,
return rv;
}
static nsresult CleanResource(nsIRDFDataSource* aDS, nsIRDFResource* aResource)
{
nsresult rv;
nsCOMPtr<nsISimpleEnumerator> arcs;
for (PRInt32 i = 0; i < 2; ++i) {
rv = i == 0 ? aDS->ArcLabelsOut(aResource, getter_AddRefs(arcs))
: aDS->ArcLabelsIn(aResource, getter_AddRefs(arcs)) ;
if (NS_FAILED(rv)) return rv;
do {
PRBool hasMore;
arcs->HasMoreElements(&hasMore);
if (!hasMore)
break;
nsCOMPtr<nsISupports> supp;
arcs->GetNext(getter_AddRefs(supp));
nsCOMPtr<nsIRDFResource> prop(do_QueryInterface(supp));
nsCOMPtr<nsIRDFNode> target;
rv = aDS->GetTarget(aResource, prop, PR_TRUE, getter_AddRefs(target));
if (NS_FAILED(rv)) continue;
aDS->Unassert(aResource, prop, target);
}
while (1);
}
return NS_OK;
}
NS_IMETHODIMP nsChromeRegistry::UninstallPackage(const nsACString& aPackageName, PRBool aUseProfile)
{
nsresult rv;
// Uninstalling a package is a three step process:
//
// 1) Unhook all secondary resources
// 2) Remove the package from the package list
// 3) Remove references in the Dynamic Datasources (overlayinfo).
//
// Details:
// 1) The Chrome Registry holds information about a package like this:
//
// urn:mozilla:package:root
// --> urn:mozilla:package:newext1
// --> c:baseURL = <BASEURL>
// --> c:locType = "install"
// --> c:name = "newext1"
//
// urn:mozilla:skin:classic/1.0:packages
// --> urn:mozilla:skin:classic/1.0:newext1
// --> c:baseURL = <BASEURL>
// --> c:package = urn:mozilla:package:newext1
//
// urn:mozilla:locale:en-US:packages
// --> urn:mozilla:locale:en-US:newext1
// --> c:baseURL = <BASEURL>
// --> c:package = urn:mozilla:package:newext1
//
// We need to follow chrome:package arcs from the package resource to
// secondary resources and then clean them. This is so that a subsequent
// installation of the same package into the opposite datasource (profile
// vs. install) does not result in the chrome registry telling the necko
// to load from the wrong location by "hitting" on redundant entries in
// the opposing datasource first.
//
// 2) Then we have to clean the resource and remove it from the package list.
// 3) Then update the dynamic datasources.
//
nsCAutoString packageResourceURI("urn:mozilla:package:");
packageResourceURI += aPackageName;
nsCOMPtr<nsIRDFResource> packageResource;
GetResource(packageResourceURI, getter_AddRefs(packageResource));
// Instantiate the data source we wish to modify.
nsCOMPtr<nsIRDFDataSource> installSource;
rv = LoadDataSource(kChromeFileName, getter_AddRefs(installSource), aUseProfile, nsnull);
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(installSource, "failed to get installSource");
nsCOMPtr<nsISimpleEnumerator> sources;
rv = installSource->GetSources(mPackage, packageResource, PR_TRUE,
getter_AddRefs(sources));
if (NS_FAILED(rv)) return rv;
do {
PRBool hasMore;
sources->HasMoreElements(&hasMore);
if (!hasMore)
break;
nsCOMPtr<nsISupports> supp;
sources->GetNext(getter_AddRefs(supp));
nsCOMPtr<nsIRDFResource> res(do_QueryInterface(supp));
rv = CleanResource(installSource, res);
if (NS_FAILED(rv)) continue;
}
while (1);
// Clean the package resource
rv = CleanResource(installSource, packageResource);
if (NS_FAILED(rv)) return rv;
// Remove the package from the package list
rv = UninstallProvider(NS_LITERAL_CSTRING("package"), aPackageName, aUseProfile);
if (NS_FAILED(rv)) return rv;
rv = UninstallFromDynamicDataSource(aPackageName, PR_TRUE, aUseProfile);
if (NS_FAILED(rv)) return rv;
return UninstallFromDynamicDataSource(aPackageName, PR_FALSE, aUseProfile);
}
nsresult
nsChromeRegistry::UninstallProvider(const nsACString& aProviderType,
const nsACString& aProviderName,
@ -3341,7 +3469,7 @@ nsChromeRegistry::ProcessNewChromeBuffer(char *aBuffer, PRInt32 aLength)
if (isSelection) {
rv = SelectSkin(nsDependentCString(chromeLocation), isProfile);
#ifdef DEBUG
#ifdef DEBUG2
printf("***** Chrome Registration: Selecting skin %s as default\n", (const char*)chromeLocation);
#endif
}
@ -3354,7 +3482,7 @@ nsChromeRegistry::ProcessNewChromeBuffer(char *aBuffer, PRInt32 aLength)
if (isSelection) {
rv = SelectLocale(nsDependentCString(chromeLocation), isProfile);
#ifdef DEBUG
#ifdef DEBUG2
printf("***** Chrome Registration: Selecting locale %s as default\n", (const char*)chromeLocation);
#endif
}

View File

@ -217,6 +217,8 @@ private:
const nsACString& aBaseURL,
PRBool aUseProfile, PRBool aAllowScripts, PRBool aRemove);
nsresult UninstallProvider(const nsACString& aProviderType, const nsACString& aProviderName, PRBool aUseProfile);
nsresult UninstallFromDynamicDataSource(const nsACString& aPackageName,
PRBool aIsOverlay, PRBool aUseProfile);
nsresult ProcessNewChromeBuffer(char *aBuffer, PRInt32 aLength);

View File

@ -85,6 +85,17 @@
<radiogroup id="mode" class="small-indent">
<hbox>
<radio id="open" label="&openWith.label;" accesskey="&openWith.accesskey;"/>
<deck id="modeDeck" flex="1">
<hbox id="openHandlerBox" flex="1"/>
<hbox flex="1">
<button id="chooseButton" oncommand="dialog.chooseApp();"
#ifdef XP_MACOSX
label="&chooseHandlerMac.label;" accesskey="&chooseHandlerMac.accesskey;"/>
#else
label="&chooseHandler.label;" accesskey="&chooseHandler.accesskey;"/>
#endif
</hbox>
</deck>
</hbox>
<radio id="save" label="&save.label;" accesskey="&save.label;"/>

View File

@ -55,3 +55,9 @@
<!ENTITY whichIsA.label "which is a:">
<!ENTITY chooseHandlerMac.label "Choose...">
<!ENTITY chooseHandlerMac.accesskey "C">
<!ENTITY chooseHandler.label "Browse...">
<!ENTITY chooseHandler.accesskey "B">

View File

@ -1623,7 +1623,7 @@ nsExtensionManager.prototype = {
.getService(Components.interfaces.nsIXULChromeRegistry);
if (!pref.prefHasUserValue(PREF_EM_LAST_SELECTED_SKIN)) {
pref.setCharPref(PREF_EM_LAST_SELECTED_SKIN,
cr.getSelectedSkin("global"));
cr.getSelectedSkin("global"));
cr.selectSkin(KEY_DEFAULT_THEME, true);
}

View File

@ -1,5 +1,41 @@
updateitem {
-moz-binding: url("chrome://mozapps/content/update/updates.xml#updateItem");
display: -moz-box;
radiogroup[type="update-types"] {
overflow: auto;
-moz-binding: url("chrome://mozapps/content/update/updates.xml#updateCategorySet");
}
radio[type="update-type"] {
-moz-binding: url("chrome://mozapps/content/update/updates.xml#updateCategory");
-moz-box-orient: vertical;
-moz-box-align: stretch;
}
radio[type="update-type"] .updateCategoryContent {
visibility: collapse;
}
radiogroup[_uninitialized] radio[type="update-type"] .updateCategoryContent {
visibility: visible !important;
}
.updateCategoryContent {
overflow: hidden;
}
radio[type="update-type"][selected="true"] .updateCategoryContent {
visibility: visible;
}
.wizard-header-description {
display: none;
}
checkbox[type="update"] {
-moz-binding: url("chrome://mozapps/content/update/updates.xml#updateItem");
}
link {
-moz-binding: url("chrome://mozapps/content/update/updates.xml#link");
-moz-user-focus: normal;
}

View File

@ -49,8 +49,11 @@ const PREF_UPDATE_APP_UPDATESAVAILABLE = "update.app.updatesAvailable";
const PREF_UPDATE_APP_UPDATEVERSION = "update.app.updateVersion";
const PREF_UPDATE_APP_UPDATEDESCRIPTION = "update.app.updateDescription";
const PREF_UPDATE_APP_UPDATEURL = "update.app.updateURL";
const PREF_UPDATE_APP_PERFORMED = "update.app.performed";
const PREF_UPDATE_EXTENSIONS_COUNT = "update.extensions.count";
const PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD = "update.extensions.severity.threshold";
const PREF_UPDATE_SEVERITY = "update.severity";
var gSourceEvent = null;
var gUpdateTypes = null;
@ -70,7 +73,20 @@ var gUpdateWizard = {
updatingApp: false,
remainingExtensionUpdateCount: 0,
appComps: {
upgraded: {
core : [],
optional : [],
languages : [],
},
optional: {
optional : [],
languages : [],
}
},
selectedLocaleAvailable: false,
init: function ()
{
gUpdateTypes = window.arguments[0];
@ -108,33 +124,6 @@ var gUpdateWizard = {
}
if (this.updatingApp) {
var updates = Components.classes["@mozilla.org/updates/update-service;1"]
.getService(Components.interfaces.nsIUpdateService);
# If we're not a browser, use the external protocol service to load the URI.
#ifndef MOZ_PHOENIX
var uri = Components.classes["@mozilla.org/network/standard-url;1"]
.createInstance(Components.interfaces.nsIURI);
uri.spec = updates.appUpdateURL;
var protocolSvc = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
.getService(Components.interfaces.nsIExternalProtocolService);
if (protocolSvc.isExposedProtocol(uri.scheme))
protocolSvc.loadUrl(uri);
# If we're a browser, open a new browser window instead.
#else
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
var ary = Components.classes["@mozilla.org/supports-array;1"]
.createInstance(Components.interfaces.nsISupportsArray);
var url = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
url.data = updates.appUpdateURL;
ary.AppendElement(url);
ww.openWindow(null, "chrome://browser/content/browser.xul",
"_blank", "chrome,all,dialog=no", ary);
#endif
// Clear the "app update available" pref as an interim amnesty assuming
// the user actually does install the new version. If they don't, a subsequent
// update check will poke them again.
@ -163,6 +152,8 @@ var gUpdateWizard = {
var updates = Components.classes["@mozilla.org/updates/update-service;1"]
.getService(Components.interfaces.nsIUpdateService);
updates.appUpdatesAvailable = false;
pref.setBoolPref(PREF_UPDATE_APP_PERFORMED, true);
// Unset prefs used by the update service to signify application updates
if (pref.prefHasUserValue(PREF_UPDATE_APP_UPDATESAVAILABLE))
@ -173,6 +164,15 @@ var gUpdateWizard = {
pref.clearUserPref(PREF_UPDATE_APP_UPDATEDESCRIPTION);
if (pref.prefHasUserValue(PREF_UPDATE_APP_UPDATEURL))
pref.clearUserPref(PREF_UPDATE_APP_UPDATEURL);
// Lower the severity to reflect the fact that there are now only Extension/
// Theme updates available
var newCount = pref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT);
var threshold = pref.getIntPref(PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD);
if (newCount >= threshold)
pref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_MEDIUM);
else
pref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_LOW);
},
clearExtensionUpdatePrefs: function ()
@ -246,6 +246,13 @@ var gUpdateWizard = {
{
if (this.errorOnGeneric || this.errorItems.length > 0 || this.errorOnApp)
document.getElementById(aElementIDToShow).hidden = false;
},
onWizardClose: function (aEvent)
{
if (gInstallingPage._installing)
return false;
return true;
}
};
@ -349,7 +356,8 @@ var gVersionPage = {
case "Version:Extension:Ended":
gVersionPage.uninit();
if (gUpdateWizard.items.length == 0) {
if (gUpdateWizard.items.length == 0 &&
gSourceEvent == nsIUpdateService.SOURCE_EVENT_MISMATCH) {
// We've resolved all compatibilities in this Version Update, so
// close up.
var updateStrings = document.getElementById("updateStrings");
@ -359,7 +367,7 @@ var gVersionPage = {
var closeTimer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
closeTimer.initWithCallback(this, 2000,
Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
Components.interfaces.nsITimer.TYPE_ONE_SHOT);
break;
}
document.documentElement.advance();
@ -518,27 +526,6 @@ var gUpdatePage = {
case "Update:App:Ended":
// The "Updates Found" page of the update wizard needs to know if it there are app
// updates so it can list them first.
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
gUpdateWizard.appUpdatesAvailable = pref.getBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE);
if (gUpdateWizard.appUpdatesAvailable) {
var appID = pref.getCharPref(PREF_APP_ID);
var updates = Components.classes["@mozilla.org/updates/update-service;1"]
.getService(Components.interfaces.nsIUpdateService);
var brandShortName = document.getElementById("brandStrings").getString("brandShortName");
var item = Components.classes["@mozilla.org/updates/item;1"]
.createInstance(Components.interfaces.nsIUpdateItem);
item.init(appID, updates.appUpdateVersion,
"", "",
brandShortName, -1, updates.appUpdateURL,
"chrome://mozapps/skin/update/icon32.png",
"", "", nsIUpdateItem.TYPE_APP);
gUpdateWizard.itemsToUpdate.splice(0, 0, item);
}
++this._completeCount;
var progress = document.getElementById("checking.progress");
progress.value = Math.ceil((this._completeCount / this.totalCount) * 100);
@ -559,87 +546,379 @@ var gFoundPage = {
_appSelected: false,
_appItem: null,
_nonAppItems: [],
_newestInfo: null,
_currentInfo: null,
buildAddons: function ()
{
var hasExtensions = false;
var foundAddonsList = document.getElementById("found.addons.list");
var uri = Components.classes["@mozilla.org/network/standard-url;1"]
.createInstance(Components.interfaces.nsIURI);
var itemCount = gUpdateWizard.itemsToUpdate.length;
for (var i = 0; i < itemCount; ++i) {
var item = gUpdateWizard.itemsToUpdate[i];
var checkbox = document.createElement("checkbox");
foundAddonsList.appendChild(checkbox);
checkbox.setAttribute("type", "update");
checkbox.label = item.name + " " + item.version;
checkbox.URL = item.xpiURL;
checkbox.infoURL = "";
checkbox.internalName = "";
uri.spec = item.xpiURL;
checkbox.source = uri.host;
checkbox.checked = true;
hasExtensions = true;
}
if (hasExtensions) {
var addonsHeader = document.getElementById("addons");
var strings = document.getElementById("updateStrings");
addonsHeader.label = strings.getFormattedString("updateTypeExtensions", [itemCount]);
addonsHeader.collapsed = false;
}
},
buildPatches: function (aPatches)
{
var needsPatching = false;
var critical = document.getElementById("found.criticalUpdates.list");
var uri = Components.classes["@mozilla.org/network/standard-url;1"]
.createInstance(Components.interfaces.nsIURI);
var count = 0;
for (var i = 0; i < aPatches.length; ++i) {
var ver = InstallTrigger.getVersion(aPatches[i].internalName);
if (InstallTrigger.getVersion(aPatches[i].internalName)) {
// The user has already installed this patch since info
// about it exists in the Version Registry. Skip.
continue;
}
var checkbox = document.createElement("checkbox");
critical.appendChild(checkbox);
checkbox.setAttribute("type", "update");
checkbox.label = aPatches[i].name;
checkbox.URL = aPatches[i].URL;
checkbox.infoURL = aPatches[i].infoURL;
checkbox.internalName = aPatches[i].internalName;
uri.spec = checkbox.URL;
checkbox.source = uri.host;
checkbox.checked = true;
needsPatching = true;
++count;
}
if (needsPatching) {
var patchesHeader = document.getElementById("patches");
var strings = document.getElementById("updateStrings");
patchesHeader.label = strings.getFormattedString("updateTypePatches", [count]);
patchesHeader.collapsed = false;
}
},
buildApp: function (aFiles)
{
// A New version of the app is available.
var app = document.getElementById("app");
var strings = document.getElementById("updateStrings");
var brandStrings = document.getElementById("brandStrings");
var brandShortName = brandStrings.getString("brandShortName");
app.label = strings.getFormattedString("appNameAndVersionFormat",
[brandShortName,
this._newestInfo.updateDisplayVersion]);
app.accesskey = brandShortName.charAt(0);
app.collapsed = false;
var foundAppLabel = document.getElementById("found.app.label");
var text = strings.getFormattedString("foundAppLabel",
[brandShortName,
this._newestInfo.updateDisplayVersion])
foundAppLabel.appendChild(document.createTextNode(text));
var features = this._newestInfo.getCollection("features", { });
if (features) {
var foundAppFeatures = document.getElementById("found.app.features");
foundAppFeatures.hidden = false;
text = strings.getFormattedString("foundAppFeatures",
[brandShortName,
this._newestInfo.updateDisplayVersion]);
foundAppFeatures.appendChild(document.createTextNode(text));
var foundAppFeaturesList = document.getElementById("found.app.featuresList");
for (var i = 0; i < features.length; ++i) {
var feature = document.createElement("label");
foundAppFeaturesList.appendChild(feature);
feature.setAttribute("value", features[i].name);
}
}
var foundAppInfoLink = document.getElementById("found.app.infoLink");
foundAppInfoLink.href = this._newestInfo.updateInfoURL;
},
buildOptional: function (aComponents)
{
var needsOptional = false;
var critical = document.getElementById("found.components.list");
var uri = Components.classes["@mozilla.org/network/standard-url;1"]
.createInstance(Components.interfaces.nsIURI);
var count = 0;
for (var i = 0; i < aComponents.length; ++i) {
if (InstallTrigger.getVersion(aComponents[i].internalName)) {
// The user has already installed this patch since info
// about it exists in the Version Registry. Skip.
continue;
}
var checkbox = document.createElement("checkbox");
critical.appendChild(checkbox);
checkbox.setAttribute("type", "update");
checkbox.label = aComponents[i].name;
checkbox.URL = aComponents[i].URL;
checkbox.infoURL = aComponents[i].infoURL;
checkbox.internalName = aComponents[i].internalName;
uri.spec = checkbox.URL;
checkbox.source = uri.host;
needsOptional = true;
++count;
}
if (needsOptional) {
var optionalHeader = document.getElementById("components");
var strings = document.getElementById("updateStrings");
optionalHeader.label = strings.getFormattedString("updateTypeComponents", [count]);
optionalHeader.collapsed = false;
}
},
buildLanguages: function (aLanguages)
{
var hasLanguages = false;
var languageList = document.getElementById("found.languages.list");
var uri = Components.classes["@mozilla.org/network/standard-url;1"]
.createInstance(Components.interfaces.nsIURI);
var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
.getService(Components.interfaces.nsIXULChromeRegistry);
var selectedLocale = cr.getSelectedLocale("global");
var count = 0;
for (var i = 0; i < aLanguages.length; ++i) {
if (aLanguages[i].internalName == selectedLocale)
continue;
var checkbox = document.createElement("checkbox");
languageList.appendChild(checkbox);
checkbox.setAttribute("type", "update");
checkbox.label = aLanguages[i].name;
checkbox.URL = aLanguages[i].URL;
checkbox.infoURL = aLanguages[i].infoURL;
checkbox.internalName = aLanguages[i].internalName;
uri.spec = checkbox.URL;
checkbox.source = uri.host;
hasLanguages = true;
++count;
}
if (hasLanguages) {
var languagesHeader = document.getElementById("found.languages.header");
var strings = document.getElementById("updateStrings");
languagesHeader.label = strings.getFormattedString("updateTypeLangPacks", [count]);
languagesHeader.collapsed = false;
}
},
_initialized: false,
onPageShow: function ()
{
gUpdateWizard.setButtonLabels(null, true,
"installButtonText", false,
null, true);
document.documentElement.getButton("next").focus();
if (this._initialized)
return;
this._initialized = true;
var updates = document.getElementById("found.updates");
updates.computeSizes();
// Don't show the app update option or critical updates if the user has
// already installed an app update but has not yet restarted.
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var updatePerformed = pref.getBoolPref(PREF_UPDATE_APP_PERFORMED);
var updatesvc = Components.classes["@mozilla.org/updates/update-service;1"]
.getService(Components.interfaces.nsIUpdateService);
this._currentInfo = updatesvc.currentVersion;
if (this._currentInfo) {
var patches = this._currentInfo.getCollection("patches", { });
if (patches.length > 0 && !updatePerformed)
this.buildPatches(patches);
var components = this._currentInfo.getCollection("optional", { });
if (components.length > 0)
this.buildOptional(components);
var languages = this._currentInfo.getCollection("languages", { });
if (languages.length > 0)
this.buildLanguages(languages);
}
this._newestInfo = updatesvc.newestVersion;
if (this._newestInfo) {
var languages = this._newestInfo.getCollection("languages", { });
var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
.getService(Components.interfaces.nsIXULChromeRegistry);
var selectedLocale = cr.getSelectedLocale("global");
var haveLanguage = false;
for (var i = 0; i < languages.length; ++i) {
if (languages[i].internalName == selectedLocale)
haveLanguage = true;
}
var files = this._newestInfo.getCollection("files", { });
if (files.length > 0 && haveLanguage && !updatePerformed)
this.buildApp(files);
// When the user upgrades the application, any optional components that
// they have installed are automatically installed. If there are remaining
// optional components that are not currently installed, then these
// are offered as an option.
var components = this._newestInfo.getCollection("optional", { });
for (var i = 0; i < components.length; ++i) {
if (InstallTrigger.getVersion(components[i].internalName))
gUpdateWizard.appComps.upgraded.optional.push(components[i]);
else
gUpdateWizard.appComps.optional.optional.push(components[i]);
}
var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
.getService(Components.interfaces.nsIXULChromeRegistry);
var selectedLocale = cr.getSelectedLocale("global");
gUpdateWizard.selectedLocaleAvailable = false;
var languages = this._newestInfo.getCollection("languages", { });
for (i = 0; i < languages.length; ++i) {
if (languages[i].internalName == selectedLocale) {
gUpdateWizard.selectedLocaleAvailable = true;
gUpdateWizard.appComps.upgraded.languages.push(languages[i]);
}
}
if (!gUpdateWizard.selectedLocaleAvailable)
gUpdateWizard.appComps.optional.languages = gUpdateWizard.appComps.optional.languages.concat(languages);
gUpdateWizard.appComps.upgraded.core = gUpdateWizard.appComps.upgraded.core.concat(files);
}
this.buildAddons();
var kids = updates._getRadioChildren();
for (var i = 0; i < kids.length; ++i) {
if (kids[i].collapsed == false) {
updates.selectedIndex = i;
break;
}
}
},
onSelect: function (aEvent)
{
var updates = document.getElementById("found.updates");
var oneChecked = true;
if (updates.selectedItem.id != "app") {
oneChecked = false;
var items = updates.selectedItem.getElementsByTagName("checkbox");
for (var i = 0; i < items.length; ++i) {
if (items[i].checked) {
oneChecked = true;
break;
}
}
}
var strings = document.getElementById("updateStrings");
var text;
if (aEvent.target.selectedItem.id == "app") {
if (gUpdateWizard.appComps.optional.optional.length > 0) {
gUpdateWizard.setButtonLabels(null, true,
"nextButtonText", true,
null, true);
text = strings.getString("foundInstructionsAppComps");
document.getElementById("found").setAttribute("next", "optional");
}
gUpdateWizard.updatingApp = true;
}
else {
gUpdateWizard.setButtonLabels(null, true,
"installButtonText", true,
null, true);
text = strings.getString("foundInstructions");
document.getElementById("found").setAttribute("next", "installing");
gUpdateWizard.updatingApp = false;
}
document.documentElement.getButton("next").disabled = !oneChecked;
var foundInstructions = document.getElementById("foundInstructions");
while (foundInstructions.hasChildNodes())
foundInstructions.removeChild(foundInstructions.firstChild);
foundInstructions.appendChild(document.createTextNode(text));
}
};
var gOptionalPage = {
onPageShow: function ()
{
gUpdateWizard.setButtonLabels(null, true,
"installButtonText", false,
null, false);
document.documentElement.getButton("next").focus();
var list = document.getElementById("foundList");
for (var i = 0; i < gUpdateWizard.itemsToUpdate.length; ++i) {
var updateitem = document.createElement("updateitem");
list.appendChild(updateitem);
var item = gUpdateWizard.itemsToUpdate[i];
updateitem.name = item.name + " " + item.version;
updateitem.url = item.xpiURL;
// If we have an App entry in the list, check it and uncheck
// the others since the two are mutually exclusive installs.
updateitem.type = item.type;
if (item.type & nsIUpdateItem.TYPE_APP) {
updateitem.checked = true;
this._appUpdateExists = true;
this._appSelected = true;
this._appItem = updateitem;
document.getElementById("found").setAttribute("next", "appupdate");
}
else {
updateitem.checked = !this._appUpdateExists;
this._nonAppItems.push(updateitem);
}
if (item.iconURL != "")
updateitem.icon = item.iconURL;
var optionalItemsList = document.getElementById("optionalItemsList");
for (var i = 0; i < gUpdateWizard.appComps.optional.optional.length; ++i) {
var checkbox = document.createElement("checkbox");
checkbox.setAttribute("label", gUpdateWizard.appComps.optional.optional[i].name);
checkbox.setAttribute("index", i);
optionalItemsList.appendChild(checkbox);
}
gUpdateWizard.checkForErrors("updateCheckErrorNotFound");
},
onCommand: function (aEvent)
{
var i;
if (this._appUpdateExists) {
if (aEvent.target.type & nsIUpdateItem.TYPE_APP) {
for (i = 0; i < this._nonAppItems.length; ++i) {
var nonAppItem = this._nonAppItems[i];
nonAppItem.checked = !aEvent.target.checked;
}
document.getElementById("found").setAttribute("next", "appupdate");
}
else {
this._appItem.checked = false;
document.getElementById("found").setAttribute("next", "installing");
}
if (aEvent.target.localName == "checkbox") {
var index = parseInt(aEvent.target.getAttribute("index"));
var item = gUpdateWizard.appComps.optional.optional[index];
gUpdateWizard.appComps.upgraded.optional.push(item);
}
var next = document.documentElement.getButton("next");
next.disabled = true;
var foundList = document.getElementById("foundList");
for (i = 0; i < foundList.childNodes.length; ++i) {
var listitem = foundList.childNodes[i];
if (listitem.checked) {
next.disabled = false;
break;
}
}
}
};
var gAppUpdatePage = {
onPageShow: function ()
},
onListMouseOver: function (aEvent)
{
gUpdateWizard.setButtonLabels(null, true,
null, true,
null, true);
gUpdateWizard.updatingApp = true;
document.documentElement.getButton("finish").focus();
if (aEvent.target.localName == "checkbox") {
var index = parseInt(aEvent.target.getAttribute("index"));
var desc = gUpdateWizard.appComps.optional.optional[index].description;
var optionalDescription = document.getElementById("optionalDescription");
while (optionalDescription.hasChildNodes())
optionalDescription.removeChild(optionalDescription.firstChild);
optionalDescription.appendChild(document.createTextNode(desc));
}
},
onListMouseOut: function (aEvent)
{
if (aEvent.target.localName == "vbox") {
var optionalDescription = document.getElementById("optionalDescription");
while (optionalDescription.hasChildNodes())
optionalDescription.removeChild(optionalDescription.firstChild);
}
}
};
var gInstallingPage = {
_installing : false,
_restartRequired : false,
onPageShow: function ()
{
gUpdateWizard.setButtonLabels(null, true,
@ -650,14 +929,39 @@ var gInstallingPage = {
// process, registering us as an observer.
var items = [];
this._restartRequired = false;
gUpdateWizard.remainingExtensionUpdateCount = gUpdateWizard.itemsToUpdate.length;
var foundList = document.getElementById("foundList");
for (var i = 0; i < foundList.childNodes.length; ++i) {
var item = foundList.childNodes[i];
if (!(item.type & nsIUpdateItem.TYPE_APP) && item.checked) {
items.push(item.url);
this._objs.push({ name: item.name });
var updates = document.getElementById("found.updates");
if (updates.selectedItem.id != "app") {
var checkboxes = updates.selectedItem.getElementsByTagName("checkbox");
for (var i = 0; i < checkboxes.length; ++i) {
if (checkboxes[i].type == "update" && checkboxes[i].checked) {
items.push(checkboxes[i].URL);
this._objs.push({ name: checkboxes[i].label });
}
}
}
else {
// To install an app update we need to collect together the following
// sets of files:
// - core files
// - optional components (we need to show another page)
// - selected language, if the available language set does not match
// the one currently selected for the "global" package
// Order is *probably* important here.
for (var i = 0; i < gUpdateWizard.appComps.upgraded.core.length; ++i) {
items.push(gUpdateWizard.appComps.upgraded.core[i].URL);
this._objs.push({ name: gUpdateWizard.appComps.upgraded.core[i].name });
}
for (var i = 0; i < gUpdateWizard.appComps.upgraded.languages.length; ++i) {
items.push(gUpdateWizard.appComps.upgraded.languages[i].URL);
this._objs.push({ name: gUpdateWizard.appComps.upgraded.languages[i].name });
}
for (var i = 0; i < gUpdateWizard.appComps.upgraded.optional.length; ++i) {
items.push(gUpdateWizard.appComps.upgraded.optional[i].URL);
this._objs.push({ name: gUpdateWizard.appComps.upgraded.optional[i].name });
}
}
@ -684,17 +988,29 @@ var gInstallingPage = {
var label = strings.getFormattedString("installingPrefix", [this._objs[aIndex].name]);
var actionItem = document.getElementById("actionItem");
actionItem.value = label;
this._installing = true;
break;
case nsIXPIProgressDialog.INSTALL_DONE:
if (aValue) {
this._objs[aIndex].error = aValue;
this._errors = true;
}
else
switch (aValue) {
case 999:
this._restartRequired = true;
break;
case 0:
--gUpdateWizard.remainingExtensionUpdateCount;
break;
default:
// XXXben ignore chrome registration errors hack!
if (!(aValue == -239 && gUpdateWizard.updatingApp)) {
this._objs[aIndex].error = aValue;
this._errors = true;
}
break;
}
break;
case nsIXPIProgressDialog.DIALOG_CLOSE:
document.getElementById("installing").setAttribute("next", this._errors ? "errors" : "finished");
this._installing = false;
var nextPage = this._errors ? "errors" : (this._restartRequired ? "restart" : "finished");
document.getElementById("installing").setAttribute("next", nextPage);
document.documentElement.advance();
break;
}
@ -751,6 +1067,15 @@ var gFinishedPage = {
}
};
var gRestartPage = {
onPageShow: function ()
{
gUpdateWizard.setButtonLabels(null, true, null, true, null, true);
// XXXben - we should really have a way to restart the app now from here!
}
};
var gNoUpdatesPage = {
onPageShow: function (aEvent)
{

View File

@ -53,7 +53,8 @@
onload="gUpdateWizard.init();"
onunload="gUpdateWizard.uninit();"
onwizardfinish="gUpdateWizard.onWizardFinish();"
style="width: 40em;"
onclose="return gUpdateWizard.onWizardClose(event);"
style="width: 47em; min-height: 35em;"
buttons="accept,cancel">
<script type="application/x-javascript" src="chrome://mozapps/content/update/update.js"/>
@ -150,42 +151,75 @@
onpageshow="gFoundPage.onPageShow();">
<label>&found.intro.label;</label>
<vbox id="foundList" flex="1" style="height: 16em; overflow: auto;"
oncommand="gFoundPage.onCommand(event);"/>
<separator class="thin"/>
<radiogroup type="update-types" id="found.updates" flex="1" _uninitialized="true"
onselect="gFoundPage.onSelect(event);">
<radio type="update-type" id="patches" accesskey="&found.updatetype.patches.accesskey;" collapsed="true">
<description>&found.criticalUpdates.label;</description>
<separator class="thin"/>
<vbox id="found.criticalUpdates.list"/>
<separator class="thin"/>
<description>&found.criticalUpdates.info;</description>
<label>.</label>
</radio>
<radio type="update-type" id="app" collapsed="true">
<label id="found.app.label"/>
<separator class="thin"/>
<label id="found.app.features" hidden="true"/>
<vbox id="found.app.featuresList"/>
<separator class="thin"/>
<link id="found.app.infoLink" label="&found.app.infoLink;"/>
<label>.</label>
</radio>
<radio type="update-type" id="components" accesskey="&found.updatetype.components.accesskey;" collapsed="true">
<description>&found.components.label;</description>
<separator class="thin"/>
<vbox id="found.components.list"/>
<separator class="thin"/>
<description>&found.components.info;</description>
<label>.</label>
</radio>
<radio type="update-type" id="addons" accesskey="&found.updatetype.addons.accesskey;" collapsed="true">
<description>&found.addons.label;</description>
<separator class="thin"/>
<vbox id="found.addons.list"/>
<label>.</label>
</radio>
<radio type="update-type" id="found.languages.header" accesskey="&found.updatetype.languages.accesskey;" collapsed="true">
<description>&found.languages.label;</description>
<separator class="thin"/>
<vbox id="found.languages.list"/>
<label>.</label>
</radio>
</radiogroup>
<separator class="thin"/>
<label id="foundInstructions"/>
<label>&found.instructions.label;</label>
<hbox id="updateCheckErrorFound" hidden="true" align="center">
<description flex="1">
&updateCheckError.description;
</description>
<button label="&updateCheckError.label;" accesskey="&updateCheckError.accesskey;"
oncommand="gUpdateWizard.showUpdateCheckErrors();"/>
</hbox>
</wizardpage>
<wizardpage id="appupdate" pageid="appupdate"
label="&appupdate.title;"
onpageshow="gAppUpdatePage.onPageShow();">
<hbox>
<label flex="1">&appupdate.intro.label;</label>
<separator/>
<image src="chrome://mozapps/skin/update/icon32.png"/>
</hbox>
<wizardpage id="optional" pageid="optional" next="installing"
label="&optional.title;"
onpageshow="gOptionalPage.onPageShow();">
<label>&optional.intro.label;</label>
<separator class="thin"/>
<vbox id="optionalItemsList" flex="1" align="left"
style="overflow: auto;"
onmouseover="gOptionalPage.onListMouseOver(event);"
onmouseout="gOptionalPage.onListMouseOut(event);"
oncommand="gOptionalPage.onCommand(event);"/>
<separator/>
<description id="optionalDescription" style="height: 3em;"/>
</wizardpage>
<wizardpage id="installing" pageid="installing" next="finished"
label="&installing.title;"
onpageshow="gInstallingPage.onPageShow();">
<label>&installing.intro.label;</label>
<label id="actionItem"/>
<progressmeter id="downloadProgress"/>
<hbox align="center">
<image id="installing.throbber" class="throbber"/>
<label id="actionItem" flex="1" crop="right"/>
</hbox>
<separator/>
</wizardpage>
@ -219,5 +253,13 @@
</wizardpage>
<wizardpage id="restart" pageid="restart"
label="&restart.title;"
onpageshow="gRestartPage.onPageShow();">
<label>&restart.updated.label;</label>
</wizardpage>
</wizard>

View File

@ -106,68 +106,195 @@
</handler>
</handlers>
</binding>
<binding id="updateItem">
<binding id="updateCategorySet" extends="chrome://global/content/bindings/radio.xml#radiogroup">
<implementation>
<method name="computeSizes">
<body>
<![CDATA[
var kids = this._getRadioChildren();
for (var i = 0; i < kids.length; ++i)
kids[i].expandedHeight = kids[i]._content.boxObject.height;
this.removeAttribute("_uninitialized");
]]>
</body>
</method>
<field name="lastSelectedItem">null</field>
</implementation>
</binding>
<binding id="updateCategory" extends="chrome://global/content/bindings/radio.xml#radio">
<resources>
<stylesheet src="chrome://global/skin/radio.css"/>
<stylesheet src="chrome://mozapps/skin/update/update.css"/>
</resources>
<content>
<xul:hbox flex="1">
<xul:stack>
<xul:vbox align="center">
<xul:image class="updateItemIcon" xbl:inherits="src=icon"/>
</xul:vbox>
<xul:vbox align="right">
<xul:checkbox class="updateItemChecked" anonid="updateItemChecked" xbl:inherits="checked"/>
</xul:vbox>
</xul:stack>
<xul:vbox flex="1">
<xul:hbox class="updateItemNameRow" align="center">
<xul:label class="updateItemName" xbl:inherits="value=name" flex="1" crop="right"/>
<xul:hbox class="updateCategoryBox" xbl:inherits="selected,checked,disabled">
<xul:hbox class="radio-check-box1" xbl:inherits="selected,checked,disabled">
<xul:hbox class="radio-check-box2" flex="1">
<xul:image class="radio-check" xbl:inherits="selected,checked,disabled"/>
</xul:hbox>
<xul:hbox class="updateItemInfoRow" anonid="updateItemInfoRow" align="center" hidden="true">
<xul:label class="updateItemInfo" anonid="updateItemText" flex="1" crop="right">&appInfo.label;</xul:label>
</xul:hbox>
<xul:hbox class="updateItemDetailsRow" align="center">
<xul:label class="updateItemFromLabel">&from.label;</xul:label>
<xul:textbox class="updateItemURL" xbl:inherits="value=url" flex="1" readonly="true" crop="right"/>
</xul:hbox>
</xul:vbox>
</xul:hbox>
<xul:image class="updateCategoryIcon" xbl:inherits="src"/>
<xul:label class="updateCategoryLabel" xbl:inherits="xbl:text=label,accesskey,crop,selected" flex="1"/>
</xul:hbox>
<xul:vbox flex="1" class="updateCategoryContent">
<children/>
</xul:vbox>
</content>
<implementation implements="nsITimerCallback">
<property name="expandedHeight"
onget="return this.getAttribute('expandedHeight');"
onset="this.setAttribute('expandedHeight', val); return val;"/>
<method name="notify">
<parameter name="aTimer"/>
<body>
<![CDATA[
var newHeight;
if (this._destinationSize == 0) {
if (this._content.boxObject.height > 0) {
newHeight = this._content.boxObject.height - this._animateIncrement;
newHeight = newHeight < 0 ? 0 : newHeight;
this._content.style.height = newHeight + "px";
this._timer.initWithCallback(this, this._animateDelay,
Components.interfaces.nsITimer.TYPE_ONE_SHOT);
}
else {
this._timer.cancel();
this._content.style.visibility = "collapse";
}
}
else {
if (this._content.boxObject.height <= this._destinationSize) {
newHeight = this._content.boxObject.height + this._animateIncrement;
newHeight = newHeight > this.expandedHeight ? this.expandedHeight : newHeight;
this._content.style.height = newHeight + "px";
this._timer.initWithCallback(this, this._animateDelay,
Components.interfaces.nsITimer.TYPE_ONE_SHOT);
}
else
this._timer.cancel();
}
]]>
</body>
</method>
<method name="_setUpTimer">
<parameter name="aSelected"/>
<body>
<![CDATA[
if (!this._timer)
this._timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
else
this._timer.cancel();
this._content.style.visibility = "visible";
this._destinationSize = aSelected ? this.expandedHeight : 0;
this._timer.initWithCallback(this, this._animateDelay,
Components.interfaces.nsITimer.TYPE_ONE_SHOT);
]]>
</body>
</method>
<field name="_content">
document.getAnonymousElementByAttribute(this, "class", "updateCategoryContent");
</field>
<field name="_timer">null</field>
<field name="_animateDelay">50</field>
<field name="_animateIncrement">25</field>
<field name="_destinationSize">0</field>
</implementation>
<handlers>
<handler event="RadioStateChange">
<![CDATA[
/*
this._content.style.height = "0px";
if (this.radioGroup.lastSelectedItem)
this.radioGroup.lastSelectedItem._setUpTimer(false);
this.radioGroup.lastSelectedItem = this;
this._setUpTimer(true);*/
]]>
</handler>
</handlers>
</binding>
<binding id="updateItem" extends="chrome://global/content/bindings/checkbox.xml#checkbox">
<content>
<xul:image class="checkbox-check" xbl:inherits="checked,disabled"/>
<xul:hbox class="checkbox-label-box" flex="1">
<xul:label class="checkbox-label foundLabel" xbl:inherits="xbl:text=label,accesskey" flex="1"/>
<xul:label class="checkbox-label" value="&from.label;"/>
<xul:label class="checkbox-label foundSource" xbl:inherits="xbl:text=source,infoURL,accesskey,crop"/>
</xul:hbox>
</content>
<implementation>
<property name="name" onset="this.setAttribute('name', val); return val;"
onget="return this.getAttribute('name');"/>
<property name="url" onset="this.setAttribute('url', val); return val;"
onget="return this.getAttribute('url');"/>
<property name="icon" onset="this.setAttribute('icon', val); return val;"
onget="return this.getAttribute('icon');"/>
<property name="type" onget="return parseInt(this.getAttribute('type'));">
<setter>
<![CDATA[
this.setAttribute("type", val);
if (val == Components.interfaces.nsIUpdateItem.TYPE_APP) {
var infoRow = document.getAnonymousElementByAttribute(this, "anonid", "updateItemInfoRow");
infoRow.removeAttribute("hidden");
}
return val;
]]>
</setter>
</property>
<property name="checked">
<setter>
var checkbox = document.getAnonymousElementByAttribute(this, "anonid", "updateItemChecked");
checkbox.checked = val;
return val;
</setter>
<getter>
var checkbox = document.getAnonymousElementByAttribute(this, "anonid", "updateItemChecked");
return checkbox.checked;
</getter>
</property>
<property name="type"
onget="return this.getAttribute('type');"
onset="this.setAttribute('type', val); return val;"/>
<property name="source"
onget="return this.getAttribute('source');"
onset="this.setAttribute('source', val); return val;"/>
<property name="URL"
onget="return this.getAttribute('URL');"
onset="this.setAttribute('URL', val); return val;"/>
<property name="infoURL"
onget="return this.getAttribute('infoURL');"
onset="this.setAttribute('infoURL', val); return val;"/>
<property name="internalName"
onget="return this.getAttribute('internalName');"
onset="this.setAttribute('internalName', val); return val;"/>
</implementation>
</binding>
<binding id="link" extends="chrome://global/content/bindings/text.xml#text-base">
<content>
<xul:label xbl:inherits="value=label,crop" class="linkLabel" flex="1"/>
</content>
<implementation>
<property name="href"
onget="return this.getAttribute('href');"
onset="this.setAttribute('href', val); return val;"/>
</implementation>
<handlers>
<handler event="keypress" keycode="VK_ENTER" action="this.click()" />
<handler event="keypress" keycode="VK_RETURN" action="this.click()" />
<handler event="click">
<![CDATA[
if (event.button != 0)
return;
# If we're not a browser, use the external protocol service to load the URI.
#ifndef MOZ_PHOENIX
var uri = Components.classes["@mozilla.org/network/standard-url;1"]
.createInstance(Components.interfaces.nsIURI);
uri.spec = this.getAttribute("href");
var protocolSvc = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
.getService(Components.interfaces.nsIExternalProtocolService);
if (protocolSvc.isExposedProtocol(uri.scheme))
protocolSvc.loadUrl(uri);
# If we're a browser, open a new browser window instead.
#else
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
var ary = Components.classes["@mozilla.org/supports-array;1"]
.createInstance(Components.interfaces.nsISupportsArray);
var url = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
url.data = this.getAttribute("href")
ary.AppendElement(url);
ww.openWindow(null, "chrome://browser/content/browser.xul",
"_blank", "chrome,all,dialog=no", ary);
#endif
]]>
</handler>
</handlers>
</binding>
</bindings>

View File

@ -18,9 +18,20 @@
<!ENTITY found.title "Updates Found">
<!ENTITY found.intro.label "&brandShortName; found the following available updates:">
<!ENTITY found.instructions.label "Choose the ones you want to install and click Install Now to install them.">
<!ENTITY from.label "from: ">
<!ENTITY found.updatetype.patches.accesskey "C">
<!ENTITY found.updatetype.components.accesskey "O">
<!ENTITY found.updatetype.addons.accesskey "E">
<!ENTITY found.updatetype.languages.accesskey "L">
<!ENTITY found.criticalUpdates.label "The following Critical Updates are available for Firefox:">
<!ENTITY found.criticalUpdates.info "You should install these updates immediately to protect your computer from attack.">
<!ENTITY found.app.infoLink "More Information...">
<!ENTITY found.components.label "The following components and plugins are available to install:">
<!ENTITY found.components.info "Installing these components may improve your browsing experience.">
<!ENTITY found.addons.label "The following updates are available to Extensions and Themes that you already have installed">
<!ENTITY found.languages.label "The following language packs are available: ">
<!ENTITY installing.title "Installing Updates">
<!ENTITY installing.intro.label "Now downloading and installing updates...">
<!ENTITY installing.disclaimer.label "XXXben - this will not work until we have a scriptable API to XPInstall.">
@ -51,13 +62,9 @@
<!ENTITY finished.enableChecking.label "Allow &brandShortName; to check for updates.">
<!ENTITY finished.mismatch.label "Click Finish to continue starting &brandShortName;.">
<!ENTITY appInfo.label "This update must be installed separately from any others.">
<!ENTITY optional.title "Optional Components">
<!ENTITY optional.intro.label "Choose additional components you want to install, then click Install Now.">
<!ENTITY appupdate.title "&brandShortName; Update">
<!ENTITY appupdate.intro.label "&brandShortName; Update will now close and take you to the
web site where you can download the latest version of
&brandShortName;.">
<!ENTITY errors.title "Problems During Update">
<!ENTITY errors.intro.label "&brandShortName; encountered problems when updating your
software, and as a result not all components could be updated.">
@ -71,4 +78,7 @@
<!ENTITY resolveMaxVersion.title "Checking for Compatible Extensions and Themes...">
<!ENTITY resolveMaxVersion.intro1.label "&brandShortName; is checking for compatibility updates to your Extensions and Themes...">
<!ENTITY restart.title "Upgrade Complete">
<!ENTITY restart.updated.label "&brandShortName; successfully downloaded and installed updates. You will have to restart &brandShortName; to complete the update.">

View File

@ -8,7 +8,7 @@ nextButtonText=Next >
nextButtonTextAccesskey=N
cancelButtonText=Cancel
cancelButtonTextAccesskey=C
update.app.url=http://update.mozilla.org/update.rdf
update.app.url=http://update.mozilla.org/update/firefox/en-US.rdf
updatesAvailableTitle=New Updates Available
updatesAvailableText=Click Here to View
@ -30,3 +30,21 @@ updatesAvailableTooltip-2=Critical Update(s) Available
updatesCheckForUpdatesTooltip=Double-click here to check for Updates
installTextNoFurtherActions=Choose the ones you want to install and click Install Now to install them.
installTextFurtherCations=Choose the ones you want to install and click Next to continue.
appNameAndVersionFormat=%S %S
updateTypePatches=Critical Updates (%S)
updateTypeComponents=Optional Components (%S)
updateTypeExtensions=Extensions and Themes (%S)
updateTypeLangPacks=Language Packs (%S)
foundAppLabel=%S %S is available. We strongly recommend that you install this upgrade as soon as possible.
foundAppFeatures=%S %S features:
foundAppInfoLink=More information about %S %S ...
foundInstructions=Choose the ones you want to install and click Install Now to install them.
foundInstructionsAppComps=Choose the ones you want to install and click Next to continue.
appupdateperformedtitle=Restart Required
appupdateperformedmessage=%S has been updated this session. Please restart %S before performing any more updates.

View File

@ -74,6 +74,27 @@ interface nsIUpdateItem : nsISupports
readonly attribute wstring objectSource;
};
[scriptable, uuid(24aee3ca-a274-4247-bd3b-d0acbb5a98aa)]
interface nsIAppUpdateInfoItem : nsISupports
{
readonly attribute wstring internalName;
readonly attribute wstring name;
readonly attribute wstring URL;
readonly attribute wstring infoURL;
readonly attribute wstring description;
};
[scriptable, uuid(2daab124-9bc7-4c35-bb7b-0fecdea03ce8)]
interface nsIAppUpdateInfo : nsISupports
{
readonly attribute wstring updateVersion;
readonly attribute wstring updateDisplayVersion;
readonly attribute wstring updateInfoURL;
void getCollection(in string aCollectionName, out unsigned long aItemCount,
[retval, array, size_is(aItemCount)] out nsIAppUpdateInfoItem aItems);
};
[scriptable, uuid(c8a2339e-770a-417d-ab9c-efde1f23ba24)]
interface nsIUpdateService : nsISupports
{
@ -96,13 +117,16 @@ interface nsIUpdateService : nsISupports
readonly attribute long updateCount;
readonly attribute unsigned short updateSeverity;
readonly attribute string appUpdateVersion;
readonly attribute wstring appUpdateDescription;
readonly attribute wstring appUpdateURL;
// these are per-session settings
attribute boolean appUpdatesAvailable;
attribute long extensionUpdatesAvailable;
readonly attribute nsIAppUpdateInfo newestVersion;
readonly attribute nsIAppUpdateInfo currentVersion;
const unsigned short SEVERITY_HIGH = 2;
const unsigned short SEVERITY_MEDIUM = 1;
const unsigned short SEVERITY_LOW = 0;
};
[scriptable, uuid(22d35700-5765-42e1-914b-a0da7c911a8c)]

View File

@ -26,9 +26,12 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = update
MODULE = extensions
EXTRA_COMPONENTS = nsBackgroundUpdateService.js
EXTRA_COMPONENTS = nsUpdateService.js
include $(topsrcdir)/config/rules.mk
nsUpdateService.js: nsUpdateService.js.in
$(PERL) $(MOZILLA_DIR)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) $^ > $@

View File

@ -56,6 +56,7 @@ const PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD = "update.extensions.severity.th
const PREF_UPDATE_INTERVAL = "update.interval";
const PREF_UPDATE_SEVERITY = "update.severity";
const PREF_UPDATE_APP_PERFORMED = "update.app.performed";
const nsIExtensionManager = Components.interfaces.nsIExtensionManager;
const nsIUpdateService = Components.interfaces.nsIUpdateService;
@ -64,17 +65,40 @@ const nsIUpdateItem = Components.interfaces.nsIUpdateItem;
const UPDATED_EXTENSIONS = 0x01;
const UPDATED_APP = 0x02;
const SEVERITY_HIGH = 2;
const SEVERITY_MEDIUM = 1;
const SEVERITY_LOW = 0;
function APP_NS(aProperty)
{
return "http://www.mozilla.org/2004/app-rdf#" + aProperty;
}
function getOSKey()
{
#ifdef XP_UNIX
#ifdef XP_MACOSX
return "mac";
#else
return "lin";
#endif
#else
return "win";
#endif
}
var gPref = null;
var gOS = null;
var gRDF = null;
function nsUpdateService()
{
this._pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
gPref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
gOS = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
gRDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]
.getService(Components.interfaces.nsIRDFService);
this.watchForUpdates();
var pbi = this._pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
var pbi = gPref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
pbi.addObserver(PREF_UPDATE_APP_ENABLED, this, false);
pbi.addObserver(PREF_UPDATE_EXTENSIONS_ENABLED, this, false);
pbi.addObserver(PREF_UPDATE_INTERVAL, this, false);
@ -83,13 +107,14 @@ function nsUpdateService()
// Observe xpcom-shutdown to unhook pref branch observers above to avoid
// shutdown leaks.
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.addObserver(this, "xpcom-shutdown", false);
gOS.addObserver(this, "xpcom-shutdown", false);
// Reset update state from previous session if an app update was installed.
if (gPref.prefHasUserValue(PREF_UPDATE_APP_PERFORMED))
gPref.clearUserPref(PREF_UPDATE_APP_PERFORMED);
}
nsUpdateService.prototype = {
_pref: null,
_updateObserver: null,
_appUpdatesEnabled: true,
_extUpdatesEnabled: true,
@ -101,12 +126,12 @@ nsUpdateService.prototype = {
// This is called when the app starts, so check to see if the time interval
// expired between now and the last time an automated update was performed.
// now is the same one that was started last time.
this._appUpdatesEnabled = this._pref.getBoolPref(PREF_UPDATE_APP_ENABLED);
this._extUpdatesEnabled = this._pref.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED);
this._appUpdatesEnabled = gPref.getBoolPref(PREF_UPDATE_APP_ENABLED);
this._extUpdatesEnabled = gPref.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED);
if (!this._appUpdatesEnabled && !this._extUpdatesEnabled)
return;
this._makeTimer(this._pref.getIntPref(PREF_UPDATE_INTERVAL));
this._makeTimer(gPref.getIntPref(PREF_UPDATE_INTERVAL));
},
checkForUpdates: function nsUpdateService_checkForUpdates (aItems, aItemCount, aUpdateTypes, aSourceEvent, aParentWindow)
@ -114,6 +139,24 @@ nsUpdateService.prototype = {
switch (aSourceEvent) {
case nsIUpdateService.SOURCE_EVENT_MISMATCH:
case nsIUpdateService.SOURCE_EVENT_USER:
if (aSourceEvent == nsIUpdateService.SOURCE_EVENT_USER &&
gPref.getBoolPref(PREF_UPDATE_APP_PERFORMED)) {
var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
.getService(Components.interfaces.nsIStringBundleService);
var bundle = sbs.createBundle("chrome://mozapps/locale/update/update.properties");
var brandBundle = sbs.createBundle("chrome://global/locale/brand.properties");
var brandShortName = brandBundle.GetStringFromName("brandShortName");
var message = bundle.formatStringFromName("appupdateperformedmessage",
[brandShortName, brandShortName], 2);
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
ps.alert(aParentWindow,
bundle.GetStringFromName("appupdateperformedtitle"),
message);
return;
}
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
var ary = Components.classes["@mozilla.org/supports-array;1"]
@ -166,38 +209,28 @@ nsUpdateService.prototype = {
{
// Listen for notifications sent out by the app updater (implemented here) and the
// extension updater (implemented in nsExtensionItemUpdater)
if (this._updateObserver) {
this._updateObserver.destroy();
this._updateObserver = null;
}
var canUpdate;
this._updateObserver = new nsUpdateObserver(aUpdateTypes, aSourceEvent, this);
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
if ((aUpdateTypes & nsIUpdateItem.TYPE_ANY) || (aUpdateTypes & nsIUpdateItem.TYPE_APP)) {
if (this._canUpdate(this._appUpdatesEnabled, aSourceEvent)) {
os.addObserver(this._updateObserver, "Update:App:Ended", false);
gOS.addObserver(this._updateObserver, "Update:App:Ended", false);
this._currentVersion = new nsAppUpdateInfo();
this._newestVersion = new nsAppUpdateInfo();
var dsURI = this._pref.getComplexValue(PREF_UPDATE_APP_URI,
Components.interfaces.nsIPrefLocalizedString).data;
var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
.getService(Components.interfaces.nsIRDFService);
var ds = rdf.GetDataSource(dsURI);
var rds = ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource)
if (rds.loaded)
this.datasourceLoaded(ds);
else {
var sink = ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
sink.addXMLSinkObserver(new nsAppUpdateXMLRDFDSObserver(this));
if (!this._updateObserver.appUpdater) {
this._updateObserver.appUpdater = new nsAppUpdater(this);
this._updateObserver.appUpdater.checkForUpdates();
}
}
}
if (!(aUpdateTypes & nsIUpdateItem.TYPE_APP)) { // TYPE_EXTENSION, TYPE_ANY, etc.
if (this._canUpdate(this._extUpdatesEnabled, aSourceEvent)) {
os.addObserver(this._updateObserver, "Update:Extension:Started", false);
os.addObserver(this._updateObserver, "Update:Extension:Item-Ended", false);
os.addObserver(this._updateObserver, "Update:Extension:Ended", false);
gOS.addObserver(this._updateObserver, "Update:Extension:Started", false);
gOS.addObserver(this._updateObserver, "Update:Extension:Item-Ended", false);
gOS.addObserver(this._updateObserver, "Update:Extension:Ended", false);
var em = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager);
@ -215,101 +248,12 @@ nsUpdateService.prototype = {
if (aSourceEvent == nsIUpdateService.SOURCE_EVENT_BACKGROUND &&
(this._appUpdatesEnabled || this._extUpdatesEnabled)) {
if (aUpdateTypes & nsIUpdateItem.TYPE_ADDON)
this._pref.setIntPref(PREF_UPDATE_EXTENSIONS_LASTUPDATEDATE, this._nowInMilliseconds / 1000);
gPref.setIntPref(PREF_UPDATE_EXTENSIONS_LASTUPDATEDATE, this._nowInMilliseconds / 1000);
if (aUpdateTypes & nsIUpdateItem.TYPE_APP)
this._pref.setIntPref(PREF_UPDATE_APP_LASTUPDATEDATE, this._nowInMilliseconds / 1000);
gPref.setIntPref(PREF_UPDATE_APP_LASTUPDATEDATE, this._nowInMilliseconds / 1000);
}
},
_rdf: null,
_ncR: function nsUpdateService__ncR (aProperty)
{
return this._rdf.GetResource("http://home.netscape.com/NC-rdf#" + aProperty);
},
_getProperty: function nsUpdateService__getProperty (aDS, aAppID, aProperty)
{
var app = this._rdf.GetResource("urn:mozilla:app:" + aAppID);
return aDS.GetTarget(app, this._ncR(aProperty), true).QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
},
// This is called when the remote update datasource is ready to be parsed.
datasourceLoaded: function nsUpdateService_datasourceLoaded (aDataSource)
{
if (!this._rdf) {
this._rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"]
.getService(Components.interfaces.nsIRDFService);
}
// <?xml version="1.0"?>
// <RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
// xmlns:NC="http://home.netscape.com/NC-rdf#">
// <RDF:Description about="urn:mozilla:app:{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
// <NC:version>1.2</NC:version>
// <NC:severity>0</NC:severity>
// <NC:URL>http://www.mozilla.org/products/firefox/</NC:URL>
// <NC:description>Firefox 1.2 features new goats.</NC:description>
// </RDF:Description>
// </RDF:RDF>
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var appID = pref.getCharPref(PREF_APP_ID);
var appVersion = pref.getCharPref(PREF_APP_VERSION);
// do update checking here, parsing something like this format:
var version = this._getProperty(aDataSource, appID, "version");
var versionChecker = Components.classes["@mozilla.org/updates/version-checker;1"]
.getService(Components.interfaces.nsIVersionChecker);
if (versionChecker.compare(appVersion, version) < 0) {
pref.setCharPref(PREF_UPDATE_APP_UPDATEVERSION, version);
var severity = this._getProperty(aDataSource, appID, "severity");
// Synthesize the real severity value using the hint from the web site
// and the version.
pref.setIntPref(PREF_UPDATE_SEVERITY, severity);
pref.setBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE, true);
var urlStr = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
urlStr.data = this._getProperty(aDataSource, appID, "URL");
pref.setComplexValue(PREF_UPDATE_APP_UPDATEURL,
Components.interfaces.nsISupportsString,
urlStr);
var descStr = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
descStr.data = this._getProperty(aDataSource, appID, "description");
pref.setComplexValue(PREF_UPDATE_APP_UPDATEDESCRIPTION,
Components.interfaces.nsISupportsString,
descStr);
}
else {
this._clearAppUpdatePrefs();
// Lower the severity to reflect the fact that there are now only Extension/
// Theme updates available
var newCount = this._pref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT);
var threshold = this._pref.getIntPref(PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD);
if (newCount >= threshold)
this._pref.setIntPref(PREF_UPDATE_SEVERITY, SEVERITY_MEDIUM);
else
this._pref.setIntPref(PREF_UPDATE_SEVERITY, SEVERITY_LOW);
}
// The Update Wizard uses this notification to determine that the application
// update process is now complete.
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.notifyObservers(null, "Update:App:Ended", "");
},
datasourceError: function nsUpdateService_datasourceError ()
{
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.notifyObservers(null, "Update:App:Error", "");
os.notifyObservers(null, "Update:App:Ended", "");
},
get updateCount()
{
// The number of available updates is the number of extension/theme/other
@ -322,33 +266,15 @@ nsUpdateService.prototype = {
get updateSeverity()
{
return this._pref.getIntPref(PREF_UPDATE_SEVERITY);
},
get appUpdateVersion()
{
return this._pref.getComplexValue(PREF_UPDATE_APP_UPDATEVERSION,
Components.interfaces.nsIPrefLocalizedString).data;
},
get appUpdateDescription()
{
return this._pref.getComplexValue(PREF_UPDATE_APP_UPDATEDESCRIPTION,
Components.interfaces.nsIPrefLocalizedString).data;
},
get appUpdateURL()
{
return this._pref.getComplexValue(PREF_UPDATE_APP_UPDATEURL,
Components.interfaces.nsIPrefLocalizedString).data;
return gPref.getIntPref(PREF_UPDATE_SEVERITY);
},
_appUpdatesAvailable: undefined,
get appUpdatesAvailable()
{
if (this._appUpdatesAvailable === undefined) {
return (this._pref.prefHasUserValue(PREF_UPDATE_APP_UPDATESAVAILABLE) &&
this._pref.getBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE));
return (gPref.prefHasUserValue(PREF_UPDATE_APP_UPDATESAVAILABLE) &&
gPref.getBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE));
}
return this._appUpdatesAvailable;
},
@ -362,7 +288,7 @@ nsUpdateService.prototype = {
get extensionUpdatesAvailable()
{
if (this._extensionUpdatesAvailable === undefined)
return this._pref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT);
return gPref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT);
return this._extensionUpdatesAvailable;
},
set extensionUpdatesAvailable(aValue)
@ -371,13 +297,24 @@ nsUpdateService.prototype = {
return aValue;
},
_newestVersion: null,
get newestVersion()
{
return this._newestVersion;
},
_currentVersion: null,
get currentVersion()
{
return this._currentVersion;
},
/////////////////////////////////////////////////////////////////////////////
// nsITimerCallback
_shouldUpdate: function nsUpdateService__shouldUpdate (aIntervalPref, aLastCheckPref)
{
var interval = this._pref.getIntPref(aIntervalPref);
var lastUpdateTime = this._pref.getIntPref(aLastCheckPref);
return ((Math.round(this._nowInMilliseconds/1000) - lastUpdateTime) > interval);
var interval = gPref.getIntPref(aIntervalPref);
var lastUpdateTime = gPref.getIntPref(aLastCheckPref);
return ((Math.round(this._nowInMilliseconds/1000) - lastUpdateTime) > Math.round(interval/1000));
},
notify: function nsUpdateService_notify (aTimer)
@ -405,7 +342,7 @@ nsUpdateService.prototype = {
var needsNotification = false;
switch (aData) {
case PREF_UPDATE_APP_ENABLED:
this._appUpdatesEnabled = this._pref.getBoolPref(PREF_UPDATE_APP_ENABLED);
this._appUpdatesEnabled = gPref.getBoolPref(PREF_UPDATE_APP_ENABLED);
if (!this._appUpdatesEnabled) {
this._clearAppUpdatePrefs();
needsNotification = true;
@ -418,11 +355,11 @@ nsUpdateService.prototype = {
}
break;
case PREF_UPDATE_EXTENSIONS_ENABLED:
this._extUpdatesEnabled = this._pref.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED);
this._extUpdatesEnabled = gPref.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED);
if (!this._extUpdatesEnabled) {
// Unset prefs used by the update service to signify extension updates
if (this._pref.prefHasUserValue(PREF_UPDATE_EXTENSIONS_COUNT))
this._pref.clearUserPref(PREF_UPDATE_EXTENSIONS_COUNT);
if (gPref.prefHasUserValue(PREF_UPDATE_EXTENSIONS_COUNT))
gPref.clearUserPref(PREF_UPDATE_EXTENSIONS_COUNT);
needsNotification = true;
}
else {
@ -435,7 +372,7 @@ nsUpdateService.prototype = {
case PREF_UPDATE_INTERVAL:
case PREF_UPDATE_APP_INTERVAL:
case PREF_UPDATE_EXTENSIONS_INTERVAL:
this._makeTimer(this._pref.getIntPref(PREF_UPDATE_INTERVAL));
this._makeTimer(gPref.getIntPref(PREF_UPDATE_INTERVAL));
break;
}
@ -443,20 +380,29 @@ nsUpdateService.prototype = {
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
var backgroundEvt = Components.interfaces.nsIUpdateService.SOURCE_EVENT_BACKGROUND;
os.notifyObservers(null, "Update:Ended", backgroundEvt.toString());
gOS.notifyObservers(null, "Update:Ended", backgroundEvt.toString());
}
break;
case "xpcom-shutdown":
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
gOS.removeObserver(this, "xpcom-shutdown");
// Clean up held observers etc to avoid leaks.
var pbi = this._pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
var pbi = gPref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
pbi.removeObserver(PREF_UPDATE_APP_ENABLED, this);
pbi.removeObserver(PREF_UPDATE_EXTENSIONS_ENABLED, this);
pbi.removeObserver(PREF_UPDATE_INTERVAL, this);
pbi.removeObserver(PREF_UPDATE_EXTENSIONS_INTERVAL, this);
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.removeObserver(this, "xpcom-shutdown");
// Release strongly held services.
gPref = null;
gRDF = null;
gOS = null;
if (this._timer) {
this._timer.cancel();
this._timer = null;
}
break;
}
},
@ -489,14 +435,14 @@ nsUpdateService.prototype = {
_clearAppUpdatePrefs: function nsUpdateService__clearAppUpdatePrefs ()
{
// Unset prefs used by the update service to signify application updates
if (this._pref.prefHasUserValue(PREF_UPDATE_APP_UPDATESAVAILABLE))
this._pref.clearUserPref(PREF_UPDATE_APP_UPDATESAVAILABLE);
if (this._pref.prefHasUserValue(PREF_UPDATE_APP_UPDATEVERSION))
this._pref.clearUserPref(PREF_UPDATE_APP_UPDATEVERSION);
if (this._pref.prefHasUserValue(PREF_UPDATE_APP_UPDATEURL))
this._pref.clearUserPref(PREF_UPDATE_APP_UPDATEDESCRIPTION);
if (this._pref.prefHasUserValue(PREF_UPDATE_APP_UPDATEURL))
this._pref.clearUserPref(PREF_UPDATE_APP_UPDATEURL);
if (gPref.prefHasUserValue(PREF_UPDATE_APP_UPDATESAVAILABLE))
gPref.clearUserPref(PREF_UPDATE_APP_UPDATESAVAILABLE);
if (gPref.prefHasUserValue(PREF_UPDATE_APP_UPDATEVERSION))
gPref.clearUserPref(PREF_UPDATE_APP_UPDATEVERSION);
if (gPref.prefHasUserValue(PREF_UPDATE_APP_UPDATEURL))
gPref.clearUserPref(PREF_UPDATE_APP_UPDATEDESCRIPTION);
if (gPref.prefHasUserValue(PREF_UPDATE_APP_UPDATEURL))
gPref.clearUserPref(PREF_UPDATE_APP_UPDATEURL);
},
/////////////////////////////////////////////////////////////////////////////
@ -513,8 +459,6 @@ nsUpdateService.prototype = {
function nsUpdateObserver(aUpdateTypes, aSourceEvent, aService)
{
this._pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
this._updateTypes = aUpdateTypes;
this._sourceEvent = aSourceEvent;
this._service = aService;
@ -526,6 +470,8 @@ nsUpdateObserver.prototype = {
_updateState: 0,
_endedTimer : null,
appUpdater: null,
get _doneUpdating()
{
var appUpdatesEnabled = this._service._appUpdatesEnabled;
@ -553,17 +499,17 @@ nsUpdateObserver.prototype = {
switch (aTopic) {
case "Update:Extension:Started":
// Reset the count
this._pref.setIntPref(PREF_UPDATE_EXTENSIONS_COUNT, 0);
gPref.setIntPref(PREF_UPDATE_EXTENSIONS_COUNT, 0);
break;
case "Update:Extension:Item-Ended":
var newCount = this._pref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT) + 1;
this._pref.setIntPref(PREF_UPDATE_EXTENSIONS_COUNT, newCount);
var threshold = this._pref.getIntPref(PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD);
if (this._service.updateSeverity < SEVERITY_HIGH) {
var newCount = gPref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT) + 1;
gPref.setIntPref(PREF_UPDATE_EXTENSIONS_COUNT, newCount);
var threshold = gPref.getIntPref(PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD);
if (this._service.updateSeverity < nsIUpdateService.SEVERITY_HIGH) {
if (newCount > threshold)
this._pref.setIntPref(PREF_UPDATE_SEVERITY, SEVERITY_MEDIUM);
gPref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_MEDIUM);
else
this._pref.setIntPref(PREF_UPDATE_SEVERITY, SEVERITY_LOW);
gPref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_LOW);
}
break;
case "Update:Extension:Ended":
@ -571,6 +517,9 @@ nsUpdateObserver.prototype = {
break;
case "Update:App:Ended":
this._updateState |= UPDATED_APP;
this.appUpdater.destroy();
this.appUpdater = null;
break;
}
@ -590,9 +539,7 @@ nsUpdateObserver.prototype = {
{
// The Inline Browser Update UI uses this notification to refresh its update
// UI if necessary.
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.notifyObservers(null, "Update:Ended", this._sourceEvent.toString());
gOS.notifyObservers(null, "Update:Ended", this._sourceEvent.toString());
// Show update notification UI if:
// We were updating any types and any item was found
@ -600,14 +547,14 @@ nsUpdateObserver.prototype = {
// We were updating app and an app update was found.
var updatesAvailable = (((this._updateTypes & nsIUpdateItem.TYPE_EXTENSION) ||
(this._updateTypes & nsIUpdateItem.TYPE_ANY)) &&
this._pref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT) != 0);
gPref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT) != 0);
if (!updatesAvailable) {
updatesAvailable = ((this._updateTypes & nsIUpdateItem.TYPE_APP) ||
(this._updateTypes & nsIUpdateItem.TYPE_ANY)) &&
this._pref.getBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE);
gPref.getBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE);
}
var showNotification = this._pref.getBoolPref(PREF_UPDATE_SHOW_SLIDING_NOTIFICATION);
var showNotification = gPref.getBoolPref(PREF_UPDATE_SHOW_SLIDING_NOTIFICATION);
if (showNotification && updatesAvailable &&
this._sourceEvent == nsIUpdateService.SOURCE_EVENT_BACKGROUND) {
var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
@ -628,13 +575,15 @@ nsUpdateObserver.prototype = {
destroy: function nsUpdateObserver_destroy ()
{
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
try { os.removeObserver(this, "Update:Extension:Started"); } catch (e) { }
try { os.removeObserver(this, "Update:Extension:Item-Ended"); } catch (e) { }
try { os.removeObserver(this, "Update:Extension:Ended"); } catch (e) { }
try { os.removeObserver(this, "Update:App:Ended"); } catch (e) { }
try { gOS.removeObserver(this, "Update:Extension:Started"); } catch (e) { }
try { gOS.removeObserver(this, "Update:Extension:Item-Ended"); } catch (e) { }
try { gOS.removeObserver(this, "Update:Extension:Ended"); } catch (e) { }
try { gOS.removeObserver(this, "Update:App:Ended"); } catch (e) { }
if (this._endedTimer) {
this._endedTimer.cancel();
this._endedTimer = null;
}
},
////////////////////////////////////////////////////////////////////////////
@ -664,14 +613,231 @@ nsUpdateObserver.prototype = {
}
};
function nsAppUpdateXMLRDFDSObserver(aUpdateService)
///////////////////////////////////////////////////////////////////////////////
// App Updater
function nsAppUpdater(aUpdateService)
{
this._updateService = aUpdateService;
this._service = aUpdateService;
}
nsAppUpdateXMLRDFDSObserver.prototype =
{
_updateService: null,
nsAppUpdater.prototype = {
_service : null,
checkForUpdates: function ()
{
var dsURI = gPref.getComplexValue(PREF_UPDATE_APP_URI,
Components.interfaces.nsIPrefLocalizedString).data;
dsURI += "?" + Math.round(Math.random() * 1000);
this._ds = gRDF.GetDataSource(dsURI);
var rds = this._ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource)
if (rds.loaded)
this.onDatasourceLoaded(this._ds);
else {
var sink = this._ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
// Creates a strong ref that holds this object past when it falls out of
// scope in the calling function
sink.addXMLSinkObserver(this);
}
},
destroy: function ()
{
var sink = this._ds.QueryInterface(Components.interfaces.nsIRDFXMLSink);
sink.removeXMLSinkObserver(this);
this._service = null;
},
/////////////////////////////////////////////////////////////////////////////
//
_ncR: function nsUpdateService__ncR (aProperty)
{
return gRDF.GetResource("http://home.netscape.com/NC-rdf#" + aProperty);
},
_getPropertyFromResource: function nsAppUpdater__getPropertyFromResource (aDataSource,
aSourceResource,
aProperty)
{
var rv;
try {
var property = gRDF.GetResource(APP_NS(aProperty));
rv = this._stringData(aDataSource.GetTarget(aSourceResource, property, true));
if (rv == "--")
throw Components.results.NS_ERROR_FAILURE;
}
catch (e) {
return null;
}
return rv;
},
_stringData: function nsAppUpdater__stringData (aLiteralOrResource)
{
try {
var obj = aLiteralOrResource.QueryInterface(Components.interfaces.nsIRDFLiteral);
return obj.Value;
}
catch (e) {
try {
obj = aLiteralOrResource.QueryInterface(Components.interfaces.nsIRDFResource);
return obj.Value;
}
catch (e) {}
}
return "--";
},
/////////////////////////////////////////////////////////////////////////////
//
onDatasourceLoaded: function nsAppUpdater_onDatasourceLoaded (aDataSource)
{
var appID = gPref.getCharPref(PREF_APP_ID);
var appVersion = gPref.getCharPref(PREF_APP_VERSION);
var appResource = gRDF.GetResource("urn:mozilla:app:" + appID);
var updatesArc = gRDF.GetResource(APP_NS("updates"));
var updatesResource = aDataSource.GetTarget(appResource, updatesArc, true);
try {
updatesResource = updatesResource.QueryInterface(Components.interfaces.nsIRDFResource);
}
catch (e) { return; }
var cu = Components.classes["@mozilla.org/rdf/container-utils;1"]
.getService(Components.interfaces.nsIRDFContainerUtils);
if (cu.IsContainer(aDataSource, updatesResource)) {
var c = Components.classes["@mozilla.org/rdf/container;1"]
.getService(Components.interfaces.nsIRDFContainer);
c.Init(aDataSource, updatesResource);
var versionChecker = Components.classes["@mozilla.org/updates/version-checker;1"]
.getService(Components.interfaces.nsIVersionChecker);
var newestVersionObj = { version: appVersion, resource: null };
var updates = c.GetElements();
while (updates.hasMoreElements()) {
var update = updates.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
var version = this._getPropertyFromResource(aDataSource, update, "version");
if (!version)
continue;
if (versionChecker.compare(appVersion, version) == 0)
this._parseVersionData(aDataSource, update, this._service._currentVersion);
else if (versionChecker.compare(newestVersionObj.version, version) < 0) {
newestVersionObj.version = version;
newestVersionObj.resource = update;
}
}
this._parseVersionData(aDataSource, newestVersionObj.resource, this._service._newestVersion);
// There is a newer version of the app available or there are any critical
// patches available update the severity and available updates preferences.
// XXXben also note if there are langpacks available that match the user's
// preference if they previously installed an app update when a
// langpack for their language was not available and they used another
// in the meantime.
var patches = this._service._currentVersion.patches;
var languages = this._service._newestVersion.languages;
var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
.getService(Components.interfaces.nsIXULChromeRegistry);
var selectedLocale = cr.getSelectedLocale("global");
var haveLanguage = false;
for (var i = 0; i < languages.length; ++i) {
if (languages[i].internalName == selectedLocale)
haveLanguage = true;
}
if (haveLanguage &&
(newestVersionObj.version != appVersion || (patches && patches.length > 0))) {
gPref.setIntPref(PREF_UPDATE_SEVERITY, 2);
gPref.setBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE, true);
}
else
gPref.setBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE, false);
if (!gPref.getBoolPref(PREF_UPDATE_APP_UPDATESAVAILABLE)) {
this._service._clearAppUpdatePrefs();
// Lower the severity to reflect the fact that there are now only Extension/
// Theme updates available
var newCount = gPref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT);
var threshold = gPref.getIntPref(PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD);
if (newCount >= threshold)
gPref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_MEDIUM);
else
gPref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_LOW);
}
}
// The Update Wizard uses this notification to determine that the application
// update process is now complete.
gOS.notifyObservers(null, "Update:App:Ended", "");
},
_parseVersionData: function nsAppUpdater__parseVersionData (aDataSource,
aUpdateResource,
aTargetObj)
{
aTargetObj.updateVersion = this._getPropertyFromResource(aDataSource, aUpdateResource, "version");
aTargetObj.updateDisplayVersion = this._getPropertyFromResource(aDataSource, aUpdateResource, "displayVersion");
if (!aTargetObj.updateDisplayVersion)
aTargetObj.updateDisplayVersion = this._getPropertyFromResource(aDataSource, aUpdateResource, "version");
aTargetObj.updateInfoURL = this._getPropertyFromResource(aDataSource, aUpdateResource, "infoURL");
aTargetObj.features = this._parseUpdateCollection(aDataSource, aUpdateResource, "features");
aTargetObj.files = this._parseUpdateCollection(aDataSource, aUpdateResource, "files");
aTargetObj.optional = this._parseUpdateCollection(aDataSource, aUpdateResource, "optional");
aTargetObj.languages = this._parseUpdateCollection(aDataSource, aUpdateResource, "languages");
aTargetObj.patches = this._parseUpdateCollection(aDataSource, aUpdateResource, "patches");
},
_parseUpdateCollection: function nsAppUpdater__parseUpdateCollection (aDataSource,
aUpdateResource,
aCollectionName)
{
if (!aUpdateResource)
return null;
var result = [];
var collectionArc = gRDF.GetResource(APP_NS(aCollectionName));
var collectionResource = aDataSource.GetTarget(aUpdateResource, collectionArc, true);
try {
collectionResource = collectionResource.QueryInterface(Components.interfaces.nsIRDFResource);
}
catch (e) { return; }
var cu = Components.classes["@mozilla.org/rdf/container-utils;1"]
.getService(Components.interfaces.nsIRDFContainerUtils);
if (cu.IsContainer(aDataSource, collectionResource)) {
var c = Components.classes["@mozilla.org/rdf/container;1"]
.getService(Components.interfaces.nsIRDFContainer);
c.Init(aDataSource, collectionResource);
var elements = c.GetElements();
while (elements.hasMoreElements()) {
var element = elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
var info = new nsAppUpdateInfoItem();
info.name = this._getPropertyFromResource(aDataSource, element, "name");
info.internalName = this._getPropertyFromResource(aDataSource, element, "internalName");
info.URL = this._getPropertyFromResource(aDataSource, element, getOSKey() + "URL");
if (!info.URL)
info.URL = this._getPropertyFromResource(aDataSource, element, "URL");
info.infoURL = this._getPropertyFromResource(aDataSource, element, "infoURL");
info.description = this._getPropertyFromResource(aDataSource, element, "description");
result.push(info);
}
}
return result;
},
onDatasourceError: function (aStatus, aErrorMsg)
{
gOS.notifyObservers(null, "Update:App:Error", "");
gOS.notifyObservers(null, "Update:App:Ended", "");
},
/////////////////////////////////////////////////////////////////////////////
// nsIRDFXMLSinkObserver
@ -687,17 +853,24 @@ nsAppUpdateXMLRDFDSObserver.prototype =
onEndLoad: function(aSink)
{
aSink.removeXMLSinkObserver(this);
var ds = aSink.QueryInterface(Components.interfaces.nsIRDFDataSource);
this._updateService.datasourceLoaded(ds);
this._ds = aSink.QueryInterface(Components.interfaces.nsIRDFDataSource);
this.onDatasourceLoaded(this._ds);
},
onError: function(aSink, aStatus, aErrorMsg)
{
aSink.removeXMLSinkObserver(this);
this._updateService.datasourceError();
this._ds = aSink.QueryInterface(Components.interfaces.nsIRDFDataSource);
this.onDatasourceError(aStatus, aErrorMsg);
},
/////////////////////////////////////////////////////////////////////////////
// nsISupports
QueryInterface: function nsAppUpdater_QueryInterface (aIID)
{
if (!aIID.equals(Components.interfaces.nsIRDFXMLSinkObserver) &&
!aIID.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
}
@ -770,6 +943,58 @@ UpdateItem.prototype = {
}
};
function nsAppUpdateInfoItem ()
{
}
nsAppUpdateInfoItem.prototype = {
internalName: "",
name : "",
URL : "",
infoURL : "",
/////////////////////////////////////////////////////////////////////////////
// nsISupports
QueryInterface: function nsAppUpdater_QueryInterface (aIID)
{
if (!aIID.equals(Components.interfaces.nsIAppUpdateInfo) &&
!aIID.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
function nsAppUpdateInfo ()
{
}
nsAppUpdateInfo.prototype = {
updateVersion : "",
updateDisplayVersion: "",
updateInfoURL : "",
features : [],
files : [],
optional : [],
languages : [],
patches : [],
getCollection: function (aCollectionName, aItemCount)
{
var collection = aCollectionName in this ? this[aCollectionName] : null;
aItemCount.value = collection ? collection.length : 0;
return collection;
},
/////////////////////////////////////////////////////////////////////////////
// nsISupports
QueryInterface: function nsAppUpdater_QueryInterface (aIID)
{
if (!aIID.equals(Components.interfaces.nsIAppUpdateInfoCollection) &&
!aIID.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
function Version(aMajor, aMinor, aRelease, aBuild, aPlus)
{
this.major = aMajor || 0;

View File

@ -95,3 +95,81 @@ updateitem {
margin-right: 3px;
padding: 5px;
}
/* Updates View */
radio[type="update-type"] {
margin: 2px;
-moz-appearance: none;
}
.updateCategoryBox {
background-color: #DFDFDF;
padding: 3px;
-moz-appearance: radio-container;
}
.updateCategoryContent {
padding: 5px;
}
.updateCategoryLabel[selected="true"] {
font-weight: bold;
}
.updateCategoryIcon {
}
radiogroup[type="update-types"] {
-moz-appearance: listbox;
margin: 2px 4px;
border: 2px solid;
-moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
background-color: -moz-Field;
color: -moz-FieldText;
}
radio[type="update-type"][selected="true"] .updateCategoryBox {
background-color: #C0C0C0;
}
.foundSource {
border-bottom: 1px dotted #000000;
color: #000000;
cursor: pointer;
}
link {
text-decoration: underline !important;
color: #0000FF;
cursor: pointer;
}
link:active {
color: #FF0000;
}
.linkLabel {
cursor: pointer;
}
.updateCategoryContent {
margin-left: 12px;
}
#optionalItemsList {
-moz-appearance: listbox;
margin: 2px 4px;
border: 2px solid;
-moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
background-color: -moz-Field;
color: -moz-FieldText;
}