This commit is contained in:
ben%bengoodger.com 2004-05-12 03:46:38 +00:00
Родитель f3889c559f
Коммит c62687dd9e
8 изменённых файлов: 721 добавлений и 30 удалений

Просмотреть файл

@ -8,18 +8,22 @@ extension {
-moz-box-orient: vertical;
}
extension[install-state="pending"] {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#extension-pending");
extension[state="waiting"] {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#extension-waiting");
}
extension[install-state="downloading"] {
extension[state="downloading"] {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#extension-downloading");
}
extension[install-state="installing"] {
extension[state="installing"] {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#extension-installing");
}
extension[state="done"] {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#extension-done");
}
extension[toBeDisabled="true"] {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#extension-tobedisabled");
}
@ -36,10 +40,28 @@ extension[toBeUninstalled="true"] {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#extension-tobeuninstalled");
}
extension[itemType="theme"] {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#theme");
}
extension[itemType="theme"][state="waiting"] {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#theme-waiting");
}
extension[itemType="theme"][state="downloading"] {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#theme-downloading");
}
extension[itemType="theme"][state="installing"] {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#theme-installing");
}
extension[itemType="theme"][state="done"] {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#theme-done");
}
.themePreviewArea {
width: 0px;
}

Просмотреть файл

@ -5,12 +5,14 @@ const kObserverServiceProgID = "@mozilla.org/observer-service;1";
const nsIUpdateItem = Components.interfaces.nsIUpdateItem;
var gExtensionManager = null;
var gDownloadListener = null;
var gExtensionssView = null;
var gWindowState = "";
var gURIPrefix = ""; // extension or theme prefix
var gDSRoot = ""; // extension or theme root
var gGetMoreURL = "";
var gCurrentTheme = "";
var gDownloadManager = null;
var gObserverIndex = -1;
const PREF_APP_ID = "app.id";
const PREF_EXTENSIONS_GETMORETHEMESURL = "extensions.getMoreThemesURL";
@ -63,7 +65,8 @@ function onExtensionSelect(aEvent)
// Startup, Shutdown
function Startup()
{
gWindowState = window.arguments[0];
gWindowState = window.location.search.substr("?type=".length, window.location.search.length);
var isExtensions = gWindowState == "extensions";
gURIPrefix = isExtensions ? "urn:mozilla:extension:" : "urn:mozilla:theme:";
gDSRoot = isExtensions ? "urn:mozilla:extension:root" : "urn:mozilla:theme:root";
@ -134,14 +137,225 @@ function Startup()
win.setAttribute("width", isExtensions ? 400 : 500);
win.setAttribute("height", isExtensions ? 300 : 380);
}
// Now look and see if we're being opened by XPInstall
var gDownloadManager = new XPInstallDownloadManager();
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.addObserver(gDownloadManager, "xpinstall-download-started", false);
gObserverIndex = gExtensionManager.addDownloadObserver(gDownloadManager);
if ("arguments" in window) {
try {
var params = window.arguments[0].QueryInterface(Components.interfaces.nsIDialogParamBlock);
gDownloadManager.addDownloads(params);
}
catch (e) { }
}
}
function Shutdown()
{
if (gWindowState != "extensions")
gExtensionsView.removeEventListener("richview-select", onThemeSelect, false);
gExtensionManager.removeDownloadObserverAt(gObserverIndex);
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.removeObserver(gObserver, "xpinstall-download-started");
}
///////////////////////////////////////////////////////////////////////////////
//
// XPInstall
//
function getURLSpecFromFile(aFile)
{
var ioServ = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var fph = ioServ.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
return fph.getURLSpecFromFile(aFile);
}
function XPInstallDownloadManager()
{
var extensionsStrings = document.getElementById("extensionsStrings");
this._statusFormatKBMB = extensionsStrings.getString("statusFormatKBMB");
this._statusFormatKBKB = extensionsStrings.getString("statusFormatKBKB");
this._statusFormatMBMB = extensionsStrings.getString("statusFormatMBMB");
}
XPInstallDownloadManager.prototype = {
_statusFormat : null,
_statusFormatKBMB : null,
_statusFormatKBKB : null,
_statusFormatMBMB : null,
observe: function (aSubject, aTopic, aData)
{
if (aTopic == "xpinstall-download-started") {
var params = aSubject.QueryInterface(Components.interfaces.nsISupportsArray);
var paramBlock = params.GetElementAt(0).QueryInterface(Components.interfaces.nsISupportsInterfacePointer);
paramBlock = paramBlock.data.QueryInterface(Components.interfaces.nsIDialogParamBlock);
this.addDownloads(paramBlock);
}
},
addDownloads: function (aParams)
{
var numXPInstallItems = aParams.GetInt(1);
var isExtensions = gWindowState == "extensions";
var items = [];
for (var i = 0; i < numXPInstallItems;) {
var displayName = aParams.GetString(i++);
var url = aParams.GetString(i++);
var iconURL = aParams.GetString(i++);
if (!iconURL) {
iconURL = isExtensions ? "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png" :
"chrome://mozapps/skin/extensions/themeGeneric.png";
}
var type = isExtensions ? nsIUpdateItem.TYPE_EXTENSION : nsIUpdateItem.TYPE_THEME;
// gExtensionManager.addDownload(displayName, url, iconURL, type);
var item = Components.classes["@mozilla.org/updates/item;1"]
.createInstance(Components.interfaces.nsIUpdateItem);
item.init(url, " ", displayName, -1, url, iconURL, "", type);
items.push(item);
// Advance the enumerator
var certName = aParams.GetString(i++);
}
gExtensionManager.addDownloads(items, items.length);
},
removeDownload: function (aEvent)
{
},
/////////////////////////////////////////////////////////////////////////////
// nsIExtensionDownloadProgressListener
onStateChange: function (aURL, aState, aValue)
{
const nsIXPIProgressDialog = Components.interfaces.nsIXPIProgressDialog;
var element = document.getElementById(aURL);
switch (aState) {
case nsIXPIProgressDialog.DOWNLOAD_START:
dump("*** download start\n");
element.setAttribute("state", "waiting");
element.setAttribute("progress", "0");
break;
case nsIXPIProgressDialog.DOWNLOAD_DONE:
dump("*** download done\n");
element.setAttribute("progress", "100");
break;
case nsIXPIProgressDialog.INSTALL_START:
dump("*** install start\n");
element.setAttribute("state", "installing");
break;
case nsIXPIProgressDialog.INSTALL_DONE:
dump("*** install done\n");
element.setAttribute("state", "done");
var msg;
if (aValue != 0) {
var xpinstallStrings = document.getElementById("xpinstallStrings");
try {
msg = xpinstallStrings.getString("error" + aValue);
}
catch (e) {
msg = xpinstallStrings.getFormattedString("unknown.error", [aValue]);
}
element.setAttribute("error", msg);
}
else {
// Remove the dummy, since we installed successfully
var type = gWindowState == "extensions" ? nsIUpdateItem.TYPE_EXTENSION
: nsIUpdateItem.TYPE_THEME;
gExtensionManager.removeDownload(aURL, type);
}
break;
case nsIXPIProgressDialog.DIALOG_CLOSE:
break;
}
},
_urls: { },
onProgress: function (aURL, aValue, aMaxValue)
{
var element = document.getElementById(aURL);
var percent = Math.round((aValue / aMaxValue) * 100);
if (percent > 1 && !(aURL in this._urls)) {
this._urls[aURL] = true;
element.setAttribute("state", "downloading");
}
element.setAttribute("progress", percent);
var KBProgress = parseInt(aValue/1024 + .5);
var KBTotal = parseInt(aMaxValue/1024 + .5);
element.setAttribute("status", this._formatKBytes(KBProgress, KBTotal));
},
_replaceInsert: function ( text, index, value )
{
var result = text;
var regExp = new RegExp( "#"+index );
result = result.replace( regExp, value );
return result;
},
// aBytes aTotalKBytes returns:
// x, < 1MB y < 1MB x of y KB
// x, < 1MB y >= 1MB x KB of y MB
// x, >= 1MB y >= 1MB x of y MB
_formatKBytes: function (aKBytes, aTotalKBytes)
{
var progressHasMB = parseInt(aKBytes/1000) > 0;
var totalHasMB = parseInt(aTotalKBytes/1000) > 0;
var format = "";
if (!progressHasMB && !totalHasMB) {
format = this._statusFormatKBKB;
format = this._replaceInsert(format, 1, aKBytes);
format = this._replaceInsert(format, 2, aTotalKBytes);
}
else if (progressHasMB && totalHasMB) {
format = this._statusFormatMBMB;
format = this._replaceInsert(format, 1, (aKBytes / 1000).toFixed(1));
format = this._replaceInsert(format, 2, (aTotalKBytes / 1000).toFixed(1));
}
else if (totalHasMB && !progressHasMB) {
format = this._statusFormatKBMB;
format = this._replaceInsert(format, 1, aKBytes);
format = this._replaceInsert(format, 2, (aTotalKBytes / 1000).toFixed(1));
}
else {
// This is an undefined state!
dump("*** huh?!\n");
}
return format;
},
/////////////////////////////////////////////////////////////////////////////
// nsISupports
QueryInterface: function (aIID)
{
if (!aIID.equals(Components.interfaces.nsIExtensionDownloadProgressListener) &&
!aIID.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
///////////////////////////////////////////////////////////////////////////////
//
// View Event Handlers
//
function onViewDoubleClick()
{
switch (gWindowState) {

Просмотреть файл

@ -189,6 +189,111 @@
</implementation>
</binding>
<binding id="extension-waiting" extends="chrome://mozapps/content/shared/richview.xml#richview-item">
<resources>
<stylesheet src="chrome://mozapps/skin/extensions/extensions.css"/>
</resources>
<content>
<xul:hbox flex="1">
<xul:vbox pack="start">
<xul:image class="extension-icon" xbl:inherits="src=image"
style="width: 32px; max-width: 32px; height: 32px; max-height: 32px;"/>
</xul:vbox>
<xul:vbox pack="start" flex="1">
<xul:hbox>
<xul:label class="extension-item-name" xbl:inherits="value=name" crop="center"/>
<xul:label class="extension-item-version" xbl:inherits="value=version"/>
</xul:hbox>
<xul:description class="extension-item-description">
&extensionItem.waiting.label;
</xul:description>
<xul:label value=" "/>
</xul:vbox>
</xul:hbox>
</content>
<implementation>
<field name="eventPrefix">"extension-"</field>
</implementation>
</binding>
<binding id="extension-downloading" extends="chrome://mozapps/content/shared/richview.xml#richview-item">
<resources>
<stylesheet src="chrome://mozapps/skin/extensions/extensions.css"/>
</resources>
<content>
<xul:hbox flex="1">
<xul:vbox pack="start">
<xul:image class="extension-icon" xbl:inherits="src=image"
style="width: 32px; max-width: 32px; height: 32px; max-height: 32px;"/>
</xul:vbox>
<xul:vbox pack="start" flex="1">
<xul:hbox>
<xul:label class="extension-item-name" xbl:inherits="value=name" crop="center"/>
<xul:label class="extension-item-version" xbl:inherits="value=version"/>
</xul:hbox>
<xul:progressmeter class="extension-item-progress" xbl:inherits="value=progress"/>
<xul:label class="extension-item-status" xbl:inherits="value=status"/>
</xul:vbox>
</xul:hbox>
</content>
<implementation>
<field name="eventPrefix">"extension-"</field>
</implementation>
</binding>
<binding id="extension-installing" extends="chrome://mozapps/content/shared/richview.xml#richview-item">
<resources>
<stylesheet src="chrome://mozapps/skin/extensions/extensions.css"/>
</resources>
<content>
<xul:hbox flex="1">
<xul:vbox pack="start">
<xul:image class="extension-icon" xbl:inherits="src=image"
style="width: 32px; max-width: 32px; height: 32px; max-height: 32px;"/>
</xul:vbox>
<xul:vbox pack="start" flex="1">
<xul:hbox>
<xul:label class="extension-item-name" xbl:inherits="value=name" crop="center"/>
<xul:label class="extension-item-version" xbl:inherits="value=version"/>
</xul:hbox>
<xul:description class="extension-item-description">
&extensionItem.installing.label;
</xul:description>
<xul:label value=" "/>
</xul:vbox>
</xul:hbox>
</content>
<implementation>
<field name="eventPrefix">"extension-"</field>
</implementation>
</binding>
<binding id="extension-done" extends="chrome://mozapps/content/shared/richview.xml#richview-item">
<resources>
<stylesheet src="chrome://mozapps/skin/extensions/extensions.css"/>
</resources>
<content>
<xul:hbox flex="1">
<xul:vbox pack="start">
<xul:image class="extension-icon" xbl:inherits="src=image"
style="width: 32px; max-width: 32px; height: 32px; max-height: 32px;"/>
</xul:vbox>
<xul:vbox pack="start" flex="1">
<xul:hbox>
<xul:label class="extension-item-name" xbl:inherits="value=name" crop="center"/>
<xul:label class="extension-item-version" xbl:inherits="value=version"/>
</xul:hbox>
<xul:label class="extension-item-description" xbl:inherits="value=error"
value="&extensionItem.done.label;"/>
<xul:label value=" "/>
</xul:vbox>
</xul:hbox>
</content>
<implementation>
<field name="eventPrefix">"extension-"</field>
</implementation>
</binding>
<binding id="theme" extends="chrome://mozapps/content/shared/richview.xml#richview-item">
<resources>
<stylesheet src="chrome://mozapps/skin/extensions/extensions.css"/>
@ -213,5 +318,101 @@
</implementation>
</binding>
<binding id="theme-waiting" extends="chrome://mozapps/content/shared/richview.xml#richview-item">
<resources>
<stylesheet src="chrome://mozapps/skin/extensions/extensions.css"/>
</resources>
<content>
<xul:hbox flex="1">
<xul:vbox pack="start">
<xul:image class="extension-icon" xbl:inherits="src=image"
style="width: 32px; max-width: 32px; height: 32px; max-height: 32px;"/>
</xul:vbox>
<xul:vbox pack="start" flex="1">
<xul:hbox>
<xul:label class="extension-item-name" xbl:inherits="value=name" crop="center"/>
<xul:label class="extension-item-version" xbl:inherits="value=version"/>
</xul:hbox>
<xul:label class="extension-item-status" crop="right">&extensionItem.waiting.label;</xul:label>
</xul:vbox>
</xul:hbox>
</content>
<implementation>
<field name="eventPrefix">"extension-"</field>
</implementation>
</binding>
<binding id="theme-downloading" extends="chrome://mozapps/content/shared/richview.xml#richview-item">
<resources>
<stylesheet src="chrome://mozapps/skin/extensions/extensions.css"/>
</resources>
<content>
<xul:hbox flex="1">
<xul:vbox pack="start">
<xul:image class="extension-icon" xbl:inherits="src=image"
style="width: 32px; max-width: 32px; height: 32px; max-height: 32px;"/>
</xul:vbox>
<xul:vbox pack="start" flex="1">
<xul:hbox>
<xul:label class="extension-item-name" xbl:inherits="value=name" crop="center"/>
<xul:label class="extension-item-version" xbl:inherits="value=version"/>
</xul:hbox>
<xul:progressmeter class="extension-item-progress" xbl:inherits="value=progress"/>
</xul:vbox>
</xul:hbox>
</content>
<implementation>
<field name="eventPrefix">"extension-"</field>
</implementation>
</binding>
<binding id="theme-installing" extends="chrome://mozapps/content/shared/richview.xml#richview-item">
<resources>
<stylesheet src="chrome://mozapps/skin/extensions/extensions.css"/>
</resources>
<content>
<xul:hbox flex="1">
<xul:vbox pack="start">
<xul:image class="extension-icon" xbl:inherits="src=image"
style="width: 32px; max-width: 32px; height: 32px; max-height: 32px;"/>
</xul:vbox>
<xul:vbox pack="start" flex="1">
<xul:hbox>
<xul:label class="extension-item-name" xbl:inherits="value=name" crop="center"/>
<xul:label class="extension-item-version" xbl:inherits="value=version"/>
</xul:hbox>
<xul:label class="extension-item-status" crop="right">&extensionItem.installing.label;</xul:label>
</xul:vbox>
</xul:hbox>
</content>
<implementation>
<field name="eventPrefix">"extension-"</field>
</implementation>
</binding>
<binding id="theme-done" extends="chrome://mozapps/content/shared/richview.xml#richview-item">
<resources>
<stylesheet src="chrome://mozapps/skin/extensions/extensions.css"/>
</resources>
<content>
<xul:hbox flex="1">
<xul:vbox pack="start">
<xul:image class="extension-icon" xbl:inherits="src=image"
style="width: 32px; max-width: 32px; height: 32px; max-height: 32px;"/>
</xul:vbox>
<xul:vbox pack="start" flex="1">
<xul:hbox>
<xul:label class="extension-item-name" xbl:inherits="value=name" crop="center"/>
<xul:label class="extension-item-version" xbl:inherits="value=version"/>
</xul:hbox>
<xul:label class="extension-item-status" crop="right">&extensionItem.done.label;</xul:label>
</xul:vbox>
</xul:hbox>
</content>
<implementation>
<field name="eventPrefix">"extension-"</field>
</implementation>
</binding>
</bindings>

Просмотреть файл

@ -64,6 +64,7 @@
<stringbundleset id="extensionsSet">
<stringbundle id="brandStrings" src="chrome://global/locale/brand.properties"/>
<stringbundle id="extensionsStrings" src="chrome://mozapps/locale/extensions/extensions.properties"/>
<stringbundle id="xpinstallStrings" src="chrome://communicator/locale/xpinstall/xpinstall.properties"/>
</stringbundleset>
<keyset id="extensionsKeys">
@ -190,8 +191,22 @@
<binding subject="?extension"
predicate="http://www.mozilla.org/2004/em-rdf#internalName"
object="?internalName"/>
<binding subject="?extension"
predicate="http://www.mozilla.org/2004/em-rdf#downloadURL"
object="?downloadURL"/>
<binding subject="?extension"
predicate="http://www.mozilla.org/2004/em-rdf#state"
object="?state"/>
<binding subject="?extension"
predicate="http://www.mozilla.org/2004/em-rdf#progress"
object="?progress"/>
<binding subject="?extension"
predicate="http://www.mozilla.org/2004/em-rdf#status"
object="?status"/>
</bindings>
<action>
<!-- XXXben - we could really use a variety of different templates
here to make each element not be so heavy. -->
<extension uri="?extension" context="extensionContextMenu"
image="?icon" name="?name" version="?version"
description="?description" creator="?creator"
@ -201,7 +216,8 @@
previewImage="?previewImage" internalName="?internalName"
toBeInstalled="?toBeInstalled" toBeUninstalled="?toBeUninstalled"
toBeEnabled="?toBeEnabled" toBeDisabled="?toBeDisabled"
itemType="?itemType"/>
itemType="?itemType" downloadURL="?downloadURL"
state="?state" progress="?progress" status="?status"/>
</action>
</rule>
</template>

Просмотреть файл

@ -46,6 +46,9 @@
<!ENTITY extensionItem.toBeEnabled.label "This item will be enabled after you restart &brandShortName;.">
<!ENTITY extensionItem.toBeInstalled.label "This item will be installed after you restart &brandShortName;.">
<!ENTITY extensionItem.toBeUninstalled.label "This item will be uninstalled after you restart &brandShortName;.">
<!ENTITY extensionItem.done.label "Install Success">
<!ENTITY extensionItem.waiting.label "Waiting...">
<!ENTITY extensionItem.installing.label "Installing...">
<!ENTITY getMoreExtensions.label "Get More Extensions">
<!ENTITY getMoreExtensions.tooltip "Get More Extensions from update.mozilla.org">

Просмотреть файл

@ -23,3 +23,9 @@ extensionsTitle=Extensions
globalItemList=The following items are available to all users. \nYou can start Firefox with -lock-item "{GUID}" to prevent users from uninstalling or disabling an item. To unlock an item, start Firefox with -unlock-item "{GUID}"
globalItemListExtensions=\n\nGlobally Available Extensions:\n==============================\n\n
globalItemListThemes=\n\nGlobally Available Themes:\n==========================\n\n
installSuccess=Installed Successfully
statusFormatKBKB=#1 of #2 KB
statusFormatKBMB=#1 KB of #2 MB
statusFormatMBMB=#1 of #2 MB

Просмотреть файл

@ -42,6 +42,14 @@ interface nsIFile;
interface nsIRDFDataSource;
interface nsIUpdateItem;
[scriptable, uuid(9048223f-ec50-49e5-9866-80ee8f26179d)]
interface nsIExtensionDownloadProgressListener : nsISupports
{
void onStateChange(in wstring aURL, in short aState, in long aValue);
void onProgress(in wstring aURL, in unsigned long aValue, in unsigned long aMaxValue);
};
[scriptable, uuid(c3515b0f-99f4-453b-805e-1fdf5724d6d9)]
interface nsIExtensionManager : nsISupports
{
@ -53,6 +61,12 @@ interface nsIExtensionManager : nsISupports
void enableExtension(in string aExtensionID);
void disableExtension(in string aExtensionID);
void addDownloads([array, size_is(aItemCount)] in nsIUpdateItem aItems,
in unsigned long aItemCount);
void removeDownload(in wstring aURL, in unsigned short aType);
long addDownloadObserver(in nsIExtensionDownloadProgressListener aObserver);
void removeDownloadObserverAt(in long aIndex);
void installTheme(in nsIFile aJARFile, in unsigned long aFlags);
void uninstallTheme(in string aThemeID);

Просмотреть файл

@ -171,7 +171,7 @@ function getItemRoots(aItemType)
function getItemType(aURI)
{
var type = 0;
var type = -1;
if (aURI.substr(0, PREFIX_EXTENSION.length) == PREFIX_EXTENSION)
type = nsIUpdateItem.TYPE_EXTENSION;
else if (aURI.substr(0, PREFIX_THEME.length) == PREFIX_THEME)
@ -850,11 +850,13 @@ nsThemeInstaller.prototype = {
var elts = ctr.GetElements();
while (elts.hasMoreElements()) {
var elt = elts.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
if (getItemType(elt.Value) != -1) {
var name = chromeMetadata.GetTarget(elt, nameArc, true);
name = name.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
this._writer.installSkin(name, aIsProfile);
}
}
this._writer.close();
@ -1604,6 +1606,90 @@ nsExtensionManager.prototype = {
return this._ds;
},
/////////////////////////////////////////////////////////////////////////////
// Downloads
_transactions: [],
addDownloads: function (aItems, aItemCount)
{
var txn = new nsItemDownloadTransaction(this);
for (var i = 0; i < aItemCount; ++i) {
var currItem = aItems[i];
txn.addDownload(currItem.name, currItem.updateURL, currItem.iconURL, currItem.type);
this._transactions.push(txn);
}
// Kick off the download process for this transaction
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.notifyObservers(txn, "xpinstall-progress", "open");
},
removeDownload: function (aURL, aType)
{
for (var i = 0; i < this._transactions.length; ++i) {
if (this._transactions[i].containsURL(aURL)) {
this._transactions[i].removeDownload(aURL, aType);
return;
}
}
},
// The nsIXPIProgressDialog implementation in the download transaction object
// forwards notifications through these methods which we then pass on to any
// front end objects implementing nsIExtensionDownloadProgressListener that
// are listening. We maintain the master state of download operations HERE,
// not in the front end, because if the user closes the extension or theme
// managers during the downloads we need to maintain state and not terminate
// the download/install process.
onStateChange: function (aTransaction, aURL, aState, aValue)
{
if (!(aURL in this._progressData))
this._progressData[aURL] = { };
this._progressData[aURL].state = aState;
for (var i = 0; i < this._downloadObservers.length; ++i)
this._downloadObservers[i].onStateChange(aURL, aState, aValue);
const nsIXPIProgressDialog = Components.interfaces.nsIXPIProgressDialog;
if (aState == nsIXPIProgressDialog.DIALOG_CLOSE) {
for (var i = 0; i < this._transactions.length; ++i) {
if (this._transactions[i] == aTransaction) {
this._transactions.splice(i, 1);
delete aTransaction;
break;
}
}
}
},
_progressData: { },
onProgress: function (aURL, aValue, aMaxValue)
{
for (var i = 0; i < this._downloadObservers.length; ++i)
this._downloadObservers[i].onProgress(aURL, aValue, aMaxValue);
if (!(aURL in this._progressData))
this._progressData[aURL] = { };
this._progressData[aURL].progress = Math.round((aValue / aMaxValue) * 100);
},
_downloadObservers: [],
addDownloadObserver: function (aXPIProgressDialog)
{
for (var i = 0; i < this._downloadObservers.length; ++i) {
if (this._downloadObservers[i] == aXPIProgressDialog)
return i;
}
this._downloadObservers.push(aXPIProgressDialog);
return this._downloadObservers.length - 1;
},
removeDownloadObserverAt: function (aIndex)
{
this._downloadObservers.splice(aIndex, 1);
this._ds.flushProgressInfo(this._progressData);
},
//
_ds: null,
@ -1631,6 +1717,7 @@ nsExtensionManager.prototype = {
getInterfaces: function (aCount)
{
var interfaces = [Components.interfaces.nsIExtensionManager,
Components.interfaces.nsIXPIProgressDialog,
Components.interfaces.nsIObserver];
aCount.value = interfaces.length;
return interfaces;
@ -1678,6 +1765,72 @@ nsExtensionManager.prototype = {
}
};
///////////////////////////////////////////////////////////////////////////////
//
// nsItemDownloadTransaction
//
// This object implements nsIXPIProgressDialog and represents a collection of
// XPI/JAR download and install operations. There is one
// nsItemDownloadTransaction per back-end XPInstallManager object. We maintain
// a collection of separate transaction objects because it's possible to have
// multiple separate XPInstall download/install operations going on
// simultaneously, each with its own XPInstallManager instance. For instance
// you could start downloading two extensions and then download a theme. Each
// of these operations would open the appropriate FE and have to be able to
// track each operation independently.
//
function nsItemDownloadTransaction(aManager)
{
this._manager = aManager;
}
nsItemDownloadTransaction.prototype = {
_manager : null,
_downloads : [],
addDownload: function (aName, aURL, aIconURL, aItemType)
{
this._downloads.push({ url: aURL, type: aItemType, waiting: true });
this._manager._ds.addDownload(aName, aURL, aIconURL, aItemType);
},
removeDownload: function (aURL, aItemType)
{
this._manager._ds.removeDownload(aURL, aItemType);
},
containsURL: function (aURL)
{
for (var i = 0; i < this._downloads.length; ++i) {
if (this._downloads[i].url == aURL)
return true;
}
return false;
},
/////////////////////////////////////////////////////////////////////////////
// nsIXPIProgressDialog
onStateChange: function (aIndex, aState, aValue)
{
this._manager.onStateChange(this, this._downloads[aIndex].url, aState, aValue);
},
onProgress: function (aIndex, aValue, aMaxValue)
{
this._manager.onProgress(this._downloads[aIndex].url, aValue, aMaxValue);
},
/////////////////////////////////////////////////////////////////////////////
// nsISupports
QueryInterface: function (aIID)
{
if (!aIID.equals(Components.interfaces.nsIXPIProgressDialog) &&
!aIID.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
///////////////////////////////////////////////////////////////////////////////
//
// nsExtensionItemUpdater
@ -1948,7 +2101,7 @@ nsExtensionsDataSource.prototype = {
var elements = ctr.GetElements();
while (elements.hasMoreElements()) {
var e = elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
if (!this.isCompatible(this, e)) {
if (getItemType(e.Value) != -1 && !this.isCompatible(this, e)) {
var itemType = getItemType(e.Value);
var id = stripPrefix(e.Value, itemType);
var item = Components.classes["@mozilla.org/updates/item;1"]
@ -1986,6 +2139,7 @@ nsExtensionsDataSource.prototype = {
var elements = ctr.GetElements();
while (elements.hasMoreElements()) {
var e = elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
if (getItemType(e.Value) != -1) {
var id = stripPrefix(e.Value, aType);
var item = Components.classes["@mozilla.org/updates/item;1"]
.createInstance(Components.interfaces.nsIUpdateItem);
@ -1997,6 +2151,7 @@ nsExtensionsDataSource.prototype = {
}
}
}
}
aCountRef.value = items.length;
return items;
},
@ -2026,12 +2181,13 @@ nsExtensionsDataSource.prototype = {
var elements = ctr.GetElements();
while (elements.hasMoreElements()) {
var e = elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
if (getItemType(e.Value) != -1) {
var value = this.GetTarget(e, this._emR(aFlag), true);
if (!value)
items.push(stripPrefix(e.Value, getItemType(e.Value)));
}
}
}
return items;
},
@ -2264,22 +2420,81 @@ nsExtensionsDataSource.prototype = {
this.removeItemFromContainer(aThemeID, nsIUpdateItem.TYPE_THEME, isProfile);
},
// Cleans the resource of all its assertionss
removeItemMetadata: function (aItemID, aItemType)
{
var item = this._rdf.GetResource(getItemPrefix(aItemType) + aItemID);
var isProfile = this.isProfileItem(aItemID);
var ds = isProfile ? this._profileExtensions : this._appExtensions;
this._cleanResource(item, ds);
},
_cleanResource: function (aResource, aDS)
{
// Remove outward arcs
var arcs = ds.ArcLabelsOut(item);
var arcs = aDS.ArcLabelsOut(aResource);
while (arcs.hasMoreElements()) {
var arc = arcs.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
var value = ds.GetTarget(item, arc, true);
var value = aDS.GetTarget(aResource, arc, true);
if (value)
ds.Unassert(item, arc, value);
aDS.Unassert(aResource, arc, value);
}
},
addDownload: function (aName, aURL, aIconURL, aItemType)
{
var root = this._rdf.GetResource(getItemRoot(aItemType));
var res = this._rdf.GetResource(aURL);
this._setProperty(this._profileExtensions, res,
this._emR("name"),
this._rdf.GetLiteral(aName))
this._setProperty(this._profileExtensions, res,
this._emR("version"),
this._rdf.GetLiteral(" "));
this._setProperty(this._profileExtensions, res,
this._emR("iconURL"),
this._rdf.GetLiteral(aIconURL));
this._setProperty(this._profileExtensions, res,
this._emR("downloadURL"),
this._rdf.GetLiteral(aURL));
var ctr = Components.classes["@mozilla.org/rdf/container;1"]
.createInstance(Components.interfaces.nsIRDFContainer);
ctr.Init(this._profileExtensions, root);
if (ctr.IndexOf(res) == -1)
ctr.InsertElementAt(res, 1, true);
this._flush(true);
},
removeDownload: function (aURL, aItemType)
{
var root = this._rdf.GetResource(getItemRoot(aItemType));
var res = this._rdf.GetResource(aURL);
var ctr = Components.classes["@mozilla.org/rdf/container;1"]
.createInstance(Components.interfaces.nsIRDFContainer);
ctr.Init(this._profileExtensions, root);
ctr.RemoveElement(res, true);
this._cleanResource(res, this._profileExtensions);
this._flush(true);
},
flushProgressInfo: function (aData)
{
for (var url in aData) {
var res = this._rdf.GetResource(url);
this._setProperty(this._profileExtensions, res,
this._emR("state"),
this._rdf.GetIntLiteral(aData[url].state));
this._setProperty(this._profileExtensions, res,
this._emR("progress"),
this._rdf.GetIntLiteral(aData[url].progress));
}
this._flush(true);
},
loadExtensions: function (aProfile)
{
var extensionsFile = getFile(getDirKey(aProfile),