Bug 913118 - Add a combined list of public and private downloads. r=enn

This commit is contained in:
Paolo Amadini 2013-09-12 21:20:30 +02:00
parent a01046b97f
commit a78cae2649
17 changed files with 459 additions and 300 deletions

View File

@ -322,11 +322,8 @@ Sanitizer.prototype = {
}
// Clear all completed/cancelled downloads
let publicList = yield Downloads.getPublicDownloadList();
publicList.removeFinished(filterByTime);
let privateList = yield Downloads.getPrivateDownloadList();
privateList.removeFinished(filterByTime);
let list = yield Downloads.getList(Downloads.ALL);
list.removeFinished(filterByTime);
}.bind(this)).then(null, Components.utils.reportError);
}
else {

View File

@ -96,7 +96,7 @@ function onHistoryReady() {
itemPrefs.setBoolPref("sessions", false);
itemPrefs.setBoolPref("siteSettings", false);
let publicList = yield Downloads.getPublicDownloadList();
let publicList = yield Downloads.getList(Downloads.PUBLIC);
let downloadPromise = promiseDownloadRemoved(publicList);
// Clear 10 minutes ago
@ -612,7 +612,7 @@ function setupFormHistory() {
function setupDownloads() {
let publicList = yield Downloads.getPublicDownloadList();
let publicList = yield Downloads.getList(Downloads.PUBLIC);
let download = yield Downloads.createDownload({
source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",

View File

@ -912,7 +912,7 @@ WindowHelper.prototype = {
* The download will be downloaded this many minutes ago
*/
function addDownloadWithMinutesAgo(aExpectedPathList, aMinutesAgo) {
let publicList = yield Downloads.getPublicDownloadList();
let publicList = yield Downloads.getList(Downloads.PUBLIC);
let name = "fakefile-" + aMinutesAgo + "-minutes-ago";
let download = yield Downloads.createDownload({
@ -984,7 +984,7 @@ function blankSlate() {
let formHistoryDone = false, downloadsDone = false;
Task.spawn(function deleteAllDownloads() {
let publicList = yield Downloads.getPublicDownloadList();
let publicList = yield Downloads.getList(Downloads.PUBLIC);
let downloads = yield publicList.getAll();
for (let download of downloads) {
publicList.remove(download);
@ -1037,7 +1037,7 @@ function boolPrefIs(aPrefName, aExpectedVal, aMsg) {
function downloadExists(aPath)
{
return Task.spawn(function() {
let publicList = yield Downloads.getPublicDownloadList();
let publicList = yield Downloads.getList(Downloads.PUBLIC);
let listArray = yield publicList.getAll();
throw new Task.Result(listArray.some(i => i.target.path == aPath));
});

View File

@ -640,8 +640,8 @@ DownloadsDataCtor.prototype = {
// Start receiving real-time events.
if (DownloadsCommon.useJSTransfer) {
if (!this._dataLinkInitialized) {
let promiseList = this._isPrivate ? Downloads.getPrivateDownloadList()
: Downloads.getPublicDownloadList();
let promiseList = Downloads.getList(this._isPrivate ? Downloads.PRIVATE
: Downloads.PUBLIC);
promiseList.then(list => list.addView(this)).then(null, Cu.reportError);
this._dataLinkInitialized = true;
}
@ -697,8 +697,8 @@ DownloadsDataCtor.prototype = {
removeFinished: function DD_removeFinished()
{
if (DownloadsCommon.useJSTransfer) {
let promiseList = this._isPrivate ? Downloads.getPrivateDownloadList()
: Downloads.getPublicDownloadList();
let promiseList = Downloads.getList(this._isPrivate ? Downloads.PRIVATE
: Downloads.PUBLIC);
promiseList.then(list => list.removeFinished())
.then(null, Cu.reportError);
} else {
@ -1715,12 +1715,10 @@ DownloadsDataItem.prototype = {
*/
remove: function DDI_remove() {
if (DownloadsCommon.useJSTransfer) {
let promiseList = this._download.source.isPrivate
? Downloads.getPrivateDownloadList()
: Downloads.getPublicDownloadList();
promiseList.then(list => list.remove(this._download))
.then(() => this._download.finalize(true))
.then(null, Cu.reportError);
Downloads.getList(Downloads.ALL)
.then(list => list.remove(this._download))
.then(() => this._download.finalize(true))
.then(null, Cu.reportError);
return;
}

View File

@ -72,7 +72,7 @@ function promisePanelOpened()
function task_resetState()
{
// Remove all downloads.
let publicList = yield Downloads.getPublicDownloadList();
let publicList = yield Downloads.getList(Downloads.PUBLIC);
let downloads = yield publicList.getAll();
for (let download of downloads) {
publicList.remove(download);
@ -88,7 +88,7 @@ function task_addDownloads(aItems)
{
let startTimeMs = Date.now();
let publicList = yield Downloads.getPublicDownloadList();
let publicList = yield Downloads.getList(Downloads.PUBLIC);
for (let item of aItems) {
publicList.add(yield Downloads.createDownload({
source: "http://www.example.com/test-download.txt",

View File

@ -51,7 +51,7 @@
if (useJSTransfer) {
var Downloads = SpecialPowers.Cu.import("resource://gre/modules/Downloads.jsm").Downloads;
Downloads.getPublicDownloadList().then(list => {
Downloads.getList(Downloads.PUBLIC).then(list => {
list = SpecialPowers.wrap(list);
list.addView({
onDownloadAdded: function (aDownload) {

View File

@ -39,6 +39,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
@ -47,6 +49,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gDownloadPlatform",
"@mozilla.org/toolkit/download-platform;1",
"mozIDownloadPlatform");
@ -59,7 +62,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "gMIMEService",
XPCOMUtils.defineLazyServiceGetter(this, "gExternalProtocolService",
"@mozilla.org/uriloader/external-protocol-service;1",
"nsIExternalProtocolService");
XPCOMUtils.defineLazyGetter(this, "gParentalControlsService", function() {
if ("@mozilla.org/parental-controls-service;1" in Cc) {
return Cc["@mozilla.org/parental-controls-service;1"]
@ -161,6 +164,9 @@ this.DownloadIntegration = {
initializePublicDownloadList: function(aList) {
return Task.spawn(function task_DI_initializePublicDownloadList() {
if (this.dontLoadList) {
// In tests, only register the history observer. This object is kept
// alive by the history service, so we don't keep a reference to it.
new DownloadHistoryObserver(aList);
return;
}
@ -207,9 +213,12 @@ this.DownloadIntegration = {
}
// After the list of persisten downloads have been loaded, add
// the DownloadAutoSaveView (even if the load operation failed).
// After the list of persistent downloads has been loaded, add the
// DownloadAutoSaveView and the DownloadHistoryObserver (even if the load
// operation failed). These objects are kept alive by the underlying
// DownloadList and by the history service respectively.
new DownloadAutoSaveView(aList, this._store);
new DownloadHistoryObserver(aList);
}.bind(this));
},
@ -816,7 +825,7 @@ this.DownloadObserver = {
break;
case "last-pb-context-exited":
let deferred = Task.spawn(function() {
let list = yield Downloads.getPrivateDownloadList();
let list = yield Downloads.getList(Downloads.PRIVATE);
let downloads = yield list.getAll();
for (let download of downloads) {
@ -840,6 +849,56 @@ this.DownloadObserver = {
Ci.nsISupportsWeakReference])
};
////////////////////////////////////////////////////////////////////////////////
//// DownloadHistoryObserver
/**
* Registers a Places observer so that operations on download history are
* reflected on the provided list of downloads.
*
* You do not need to keep a reference to this object in order to keep it alive,
* because the history service already keeps a strong reference to it.
*
* @param aList
* DownloadList object linked to this observer.
*/
function DownloadHistoryObserver(aList)
{
this._list = aList;
PlacesUtils.history.addObserver(this, false);
}
DownloadHistoryObserver.prototype = {
/**
* DownloadList object linked to this observer.
*/
_list: null,
////////////////////////////////////////////////////////////////////////////
//// nsISupports
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver]),
////////////////////////////////////////////////////////////////////////////
//// nsINavHistoryObserver
onDeleteURI: function DL_onDeleteURI(aURI, aGUID) {
this._list.removeFinished(download => aURI.equals(NetUtil.newURI(
download.source.url)));
},
onClearHistory: function DL_onClearHistory() {
this._list.removeFinished();
},
onTitleChanged: function () {},
onBeginUpdateBatch: function () {},
onEndUpdateBatch: function () {},
onVisit: function () {},
onPageChanged: function () {},
onDeleteVisits: function () {},
};
////////////////////////////////////////////////////////////////////////////////
//// DownloadAutoSaveView
@ -847,6 +906,11 @@ this.DownloadObserver = {
* This view can be added to a DownloadList object to trigger a save operation
* in the given DownloadStore object when a relevant change occurs.
*
* You do not need to keep a reference to this object in order to keep it alive,
* because the DownloadList object already keeps a strong reference to it.
*
* @param aList
* The DownloadList object on which the view should be registered.
* @param aStore
* The DownloadStore object used for saving.
*/

View File

@ -219,13 +219,7 @@ DownloadLegacyTransfer.prototype = {
this._deferDownload.resolve(aDownload);
// Add the download to the list, allowing it to be seen and canceled.
let list;
if (aIsPrivate) {
list = Downloads.getPrivateDownloadList();
} else {
list = Downloads.getPublicDownloadList();
}
return list.then(function (aList) aList.add(aDownload));
return Downloads.getList(Downloads.ALL).then(list => list.add(aDownload));
}.bind(this)).then(null, Cu.reportError);
},

View File

@ -5,14 +5,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This file includes the following constructors and global objects:
*
* DownloadList
* Represents a collection of Download objects that can be viewed and managed by
* the user interface, and persisted across sessions.
*
* DownloadCombinedList
* Provides a unified, unordered list combining public and private downloads.
*/
"use strict";
this.EXPORTED_SYMBOLS = [
"DownloadList",
"DownloadCombinedList",
];
////////////////////////////////////////////////////////////////////////////////
@ -25,10 +32,6 @@ const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
@ -40,18 +43,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
/**
* Represents a collection of Download objects that can be viewed and managed by
* the user interface, and persisted across sessions.
*
* @param aIsPublic
* The boolean indicates it's a public download list or not.
*/
function DownloadList(aIsPublic) {
function DownloadList() {
this._downloads = [];
this._views = new Set();
// Only need to remove history entries for public downloads as no history
// entries are added for private downloads.
if (aIsPublic) {
PlacesUtils.history.addObserver(this, false);
}
}
DownloadList.prototype = {
@ -88,16 +83,7 @@ DownloadList.prototype = {
add: function DL_add(aDownload) {
this._downloads.push(aDownload);
aDownload.onchange = this._change.bind(this, aDownload);
for (let view of this._views) {
try {
if (view.onDownloadAdded) {
view.onDownloadAdded(aDownload);
}
} catch (ex) {
Cu.reportError(ex);
}
}
this._notifyAllViews("onDownloadAdded", aDownload);
},
/**
@ -117,16 +103,7 @@ DownloadList.prototype = {
if (index != -1) {
this._downloads.splice(index, 1);
aDownload.onchange = null;
for (let view of this._views) {
try {
if (view.onDownloadRemoved) {
view.onDownloadRemoved(aDownload);
}
} catch (ex) {
Cu.reportError(ex);
}
}
this._notifyAllViews("onDownloadRemoved", aDownload);
}
},
@ -137,15 +114,7 @@ DownloadList.prototype = {
* The Download object that changed.
*/
_change: function DL_change(aDownload) {
for (let view of this._views) {
try {
if (view.onDownloadChanged) {
view.onDownloadChanged(aDownload);
}
} catch (ex) {
Cu.reportError(ex);
}
}
this._notifyAllViews("onDownloadChanged", aDownload);
},
/**
@ -181,7 +150,7 @@ DownloadList.prototype = {
{
this._views.add(aView);
if (aView.onDownloadAdded) {
if ("onDownloadAdded" in aView) {
for (let download of this._downloads) {
try {
aView.onDownloadAdded(download);
@ -204,6 +173,26 @@ DownloadList.prototype = {
this._views.delete(aView);
},
/**
* Notifies all the views of a download addition, change, or removal.
*
* @param aMethodName
* String containing the name of the method to call on the view.
* @param aDownload
* The Download object that changed.
*/
_notifyAllViews: function (aMethodName, aDownload) {
for (let view of this._views) {
try {
if (aMethodName in view) {
view[aMethodName](aDownload);
}
} catch (ex) {
Cu.reportError(ex);
}
}
},
/**
* Removes downloads from the list that have finished, have failed, or have
* been canceled without keeping partial data. A filter function may be
@ -239,29 +228,107 @@ DownloadList.prototype = {
}
}.bind(this)).then(null, Cu.reportError);
},
////////////////////////////////////////////////////////////////////////////
//// nsISupports
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver]),
////////////////////////////////////////////////////////////////////////////
//// nsINavHistoryObserver
onDeleteURI: function DL_onDeleteURI(aURI, aGUID) {
this.removeFinished(download => aURI.equals(NetUtil.newURI(
download.source.url)));
},
onClearHistory: function DL_onClearHistory() {
this.removeFinished();
},
onTitleChanged: function () {},
onBeginUpdateBatch: function () {},
onEndUpdateBatch: function () {},
onVisit: function () {},
onPageChanged: function () {},
onDeleteVisits: function () {},
};
////////////////////////////////////////////////////////////////////////////////
//// DownloadCombinedList
/**
* Provides a unified, unordered list combining public and private downloads.
*
* Download objects added to this list are also added to one of the two
* underlying lists, based on their "source.isPrivate" property. Views on this
* list will receive notifications for both public and private downloads.
*
* @param aPublicList
* Underlying DownloadList containing public downloads.
* @param aPrivateList
* Underlying DownloadList containing private downloads.
*/
function DownloadCombinedList(aPublicList, aPrivateList)
{
DownloadList.call(this);
this._publicList = aPublicList;
this._privateList = aPrivateList;
aPublicList.addView(this);
aPrivateList.addView(this);
}
DownloadCombinedList.prototype = {
__proto__: DownloadList.prototype,
/**
* Underlying DownloadList containing public downloads.
*/
_publicList: null,
/**
* Underlying DownloadList containing private downloads.
*/
_privateList: null,
/**
* Adds a new download to the end of the items list.
*
* @note When a download is added to the list, its "onchange" event is
* registered by the list, thus it cannot be used to monitor the
* download. To receive change notifications for downloads that are
* added to the list, use the addView method to register for
* onDownloadChanged notifications.
*
* @param aDownload
* The Download object to add.
*/
add: function (aDownload)
{
if (aDownload.source.isPrivate) {
this._privateList.add(aDownload);
} else {
this._publicList.add(aDownload);
}
},
/**
* Removes a download from the list. If the download was already removed,
* this method has no effect.
*
* This method does not change the state of the download, to allow adding it
* to another list, or control it directly. If you want to dispose of the
* download object, you should cancel it afterwards, and remove any partially
* downloaded data if needed.
*
* @param aDownload
* The Download object to remove.
*/
remove: function (aDownload)
{
if (aDownload.source.isPrivate) {
this._privateList.remove(aDownload);
} else {
this._publicList.remove(aDownload);
}
},
//////////////////////////////////////////////////////////////////////////////
//// DownloadList view
onDownloadAdded: function (aDownload)
{
this._downloads.push(aDownload);
this._notifyAllViews("onDownloadAdded", aDownload);
},
onDownloadChanged: function (aDownload)
{
this._notifyAllViews("onDownloadChanged", aDownload);
},
onDownloadRemoved: function (aDownload)
{
let index = this._downloads.indexOf(aDownload);
if (index != -1) {
this._downloads.splice(index, 1);
}
this._notifyAllViews("onDownloadRemoved", aDownload);
},
};

View File

@ -25,6 +25,8 @@ const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/DownloadCore.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadCombinedList",
"resource://gre/modules/DownloadList.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadIntegration",
"resource://gre/modules/DownloadIntegration.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadList",
@ -44,6 +46,19 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
* and provides the only entry point to get references to back-end objects.
*/
this.Downloads = {
/**
* Work on downloads that were not started from a private browsing window.
*/
get PUBLIC() "{Downloads.PUBLIC}",
/**
* Work on downloads that were started from a private browsing window.
*/
get PRIVATE() "{Downloads.PRIVATE}",
/**
* Work on both Downloads.PRIVATE and Downloads.PUBLIC downloads.
*/
get ALL() "{Downloads.ALL}",
/**
* Creates a new Download object.
*
@ -128,76 +143,63 @@ this.Downloads = {
},
/**
* Retrieves the DownloadList object for downloads that were not started from
* a private browsing window.
* Retrieves the specified type of DownloadList object. There is one download
* list for each type, and this method always retrieves a reference to the
* same download list when called with the same argument.
*
* Calling this function may cause the download list to be reloaded from the
* previous session, if it wasn't loaded already.
* Calling this function may cause the list of public downloads to be reloaded
* from the previous session, if it wasn't loaded already.
*
* This method always retrieves a reference to the same download list.
* @param aType
* This can be Downloads.PUBLIC, Downloads.PRIVATE, or Downloads.ALL.
* Downloads added to the Downloads.PUBLIC and Downloads.PRIVATE lists
* are reflected in the Downloads.ALL list, and downloads added to the
* Downloads.ALL list are also added to either the Downloads.PUBLIC or
* the Downloads.PRIVATE list based on their properties.
*
* @return {Promise}
* @resolves The DownloadList object for public downloads.
* @resolves The requested DownloadList or DownloadCombinedList object.
* @rejects JavaScript exception.
*/
getPublicDownloadList: function D_getPublicDownloadList()
getList: function (aType)
{
if (!this._promisePublicDownloadList) {
this._promisePublicDownloadList = Task.spawn(
function task_D_getPublicDownloadList() {
let list = new DownloadList(true);
if (aType != Downloads.PUBLIC && aType != Downloads.PRIVATE &&
aType != Downloads.ALL) {
throw new Error("Invalid aType argument.");
}
if (!(aType in this._listPromises)) {
this._listPromises[aType] = Task.spawn(function () {
let list;
if (aType == Downloads.ALL) {
list = new DownloadCombinedList(
(yield this.getList(Downloads.PUBLIC)),
(yield this.getList(Downloads.PRIVATE)));
} else {
list = new DownloadList();
try {
yield DownloadIntegration.addListObservers(list, false);
yield DownloadIntegration.initializePublicDownloadList(list);
yield DownloadIntegration.addListObservers(
list, aType == Downloads.PRIVATE);
if (aType == Downloads.PUBLIC) {
yield DownloadIntegration.initializePublicDownloadList(list);
}
} catch (ex) {
Cu.reportError(ex);
}
throw new Task.Result(list);
});
}
throw new Task.Result(list);
}.bind(this));
}
return this._promisePublicDownloadList;
return this._listPromises[aType];
},
/**
* This promise is resolved with a reference to a DownloadList object that
* represents persistent downloads. This property is null before the list of
* downloads is requested for the first time.
* This object is populated by the getList method with one key for each type
* of object that can be returned (Downloads.PUBLIC, Downloads.PRIVATE, or
* Downloads.ALL). The values are the promises returned by the method.
*/
_promisePublicDownloadList: null,
/**
* Retrieves the DownloadList object for downloads that were started from
* a private browsing window.
*
* This method always retrieves a reference to the same download list.
*
* @return {Promise}
* @resolves The DownloadList object for private downloads.
* @rejects JavaScript exception.
*/
getPrivateDownloadList: function D_getPrivateDownloadList()
{
if (!this._promisePrivateDownloadList) {
this._promisePrivateDownloadList = Task.spawn(
function task_D_getPublicDownloadList() {
let list = new DownloadList(false);
try {
yield DownloadIntegration.addListObservers(list, true);
} catch (ex) {
Cu.reportError(ex);
}
throw new Task.Result(list);
});
}
return this._promisePrivateDownloadList;
},
/**
* This promise is resolved with a reference to a DownloadList object that
* represents private downloads. This property is null before the list of
* downloads is requested for the first time.
*/
_promisePrivateDownloadList: null,
_listPromises: {},
/**
* Returns the system downloads directory asynchronously.

View File

@ -364,10 +364,7 @@ function promiseStartLegacyDownload(aSourceUrl, aOptions) {
let deferred = Promise.defer();
let isPrivate = aOptions && aOptions.isPrivate;
let promise = isPrivate ? Downloads.getPrivateDownloadList()
: Downloads.getPublicDownloadList();
promise.then(function (aList) {
Downloads.getList(Downloads.ALL).then(function (aList) {
// Temporarily register a view that will get notified when the download we
// are controlling becomes visible in the list of downloads.
aList.addView({
@ -383,6 +380,8 @@ function promiseStartLegacyDownload(aSourceUrl, aOptions) {
},
});
let isPrivate = aOptions && aOptions.isPrivate;
// Initialize the components so they reference each other. This will cause
// the Download object to be created and added to the public downloads.
transfer.init(sourceURI, NetUtil.newURI(targetFile), null, mimeInfo, null,
@ -417,7 +416,7 @@ function promiseStartExternalHelperAppServiceDownload(aSourceUrl) {
let deferred = Promise.defer();
Downloads.getPublicDownloadList().then(function (aList) {
Downloads.getList(Downloads.PUBLIC).then(function (aList) {
// Temporarily register a view that will get notified when the download we
// are controlling becomes visible in the list of downloads.
aList.addView({
@ -490,29 +489,30 @@ function promiseDownloadStopped(aDownload) {
}
/**
* Returns a new public DownloadList object.
* Returns a new public or private DownloadList object.
*
* @param aIsPrivate
* True for the private list, false or undefined for the public list.
*
* @return {Promise}
* @resolves The newly created DownloadList object.
* @rejects JavaScript exception.
*/
function promiseNewDownloadList() {
// Force the creation of a new public download list.
Downloads._promisePublicDownloadList = null;
return Downloads.getPublicDownloadList();
}
function promiseNewList(aIsPrivate)
{
let type = aIsPrivate ? Downloads.PRIVATE : Downloads.PUBLIC;
/**
* Returns a new private DownloadList object.
*
* @return {Promise}
* @resolves The newly created DownloadList object.
* @rejects JavaScript exception.
*/
function promiseNewPrivateDownloadList() {
// Force the creation of a new public download list.
Downloads._promisePrivateDownloadList = null;
return Downloads.getPrivateDownloadList();
// Force the creation of a new list.
if (type in Downloads._listPromises) {
delete Downloads._listPromises[type];
}
// Invalidate the combined list, if any.
if (Downloads.ALL in Downloads._listPromises) {
delete Downloads._listPromises[Downloads.ALL];
}
return Downloads.getList(type);
}
/**

View File

@ -689,7 +689,7 @@ add_task(function test_downloadImport()
}
// Import items.
let list = yield promiseNewDownloadList();
let list = yield promiseNewList();
yield new DownloadImport(list, downloadsSqlite).import();
let items = yield list.getAll();

View File

@ -209,8 +209,7 @@ add_task(function test_notifications()
mustInterruptResponses();
for (let isPrivate of [false, true]) {
let list = isPrivate ? yield promiseNewPrivateDownloadList()
: yield promiseNewDownloadList();
let list = yield promiseNewList(isPrivate);
let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
let download3 = yield promiseNewDownload(httpUrl("interruptible.txt"));
@ -248,8 +247,7 @@ add_task(function test_no_notifications()
enableObserversTestMode();
for (let isPrivate of [false, true]) {
let list = isPrivate ? yield promiseNewPrivateDownloadList()
: yield promiseNewDownloadList();
let list = yield promiseNewList(isPrivate);
let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
download1.start();
@ -279,8 +277,8 @@ add_task(function test_mix_notifications()
enableObserversTestMode();
mustInterruptResponses();
let publicList = yield promiseNewDownloadList();
let privateList = yield promiseNewPrivateDownloadList();
let publicList = yield promiseNewList();
let privateList = yield promiseNewList(true);
let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
let promiseAttempt1 = download1.start();
@ -311,7 +309,7 @@ add_task(function test_exit_private_browsing()
enableObserversTestMode();
mustInterruptResponses();
let privateList = yield promiseNewPrivateDownloadList();
let privateList = yield promiseNewList(true);
let download1 = yield promiseNewDownload(httpUrl("source.txt"));
let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
let promiseAttempt1 = download1.start();

View File

@ -73,10 +73,10 @@ function promiseExpirableDownloadVisit(aSourceUrl)
*/
add_task(function test_construction()
{
let downloadListOne = yield promiseNewDownloadList();
let downloadListTwo = yield promiseNewDownloadList();
let privateDownloadListOne = yield promiseNewPrivateDownloadList();
let privateDownloadListTwo = yield promiseNewPrivateDownloadList();
let downloadListOne = yield promiseNewList();
let downloadListTwo = yield promiseNewList();
let privateDownloadListOne = yield promiseNewList(true);
let privateDownloadListTwo = yield promiseNewList(true);
do_check_neq(downloadListOne, downloadListTwo);
do_check_neq(privateDownloadListOne, privateDownloadListTwo);
@ -88,7 +88,7 @@ add_task(function test_construction()
*/
add_task(function test_add_getAll()
{
let list = yield promiseNewDownloadList();
let list = yield promiseNewList();
let downloadOne = yield promiseNewDownload();
list.add(downloadOne);
@ -114,7 +114,7 @@ add_task(function test_add_getAll()
*/
add_task(function test_remove()
{
let list = yield promiseNewDownloadList();
let list = yield promiseNewList();
list.add(yield promiseNewDownload());
list.add(yield promiseNewDownload());
@ -130,89 +130,149 @@ add_task(function test_remove()
});
/**
* Checks that views receive the download add and remove notifications, and that
* adding and removing views works as expected.
* Tests that the "add", "remove", and "getAll" methods on the global
* DownloadCombinedList object combine the contents of the global DownloadList
* objects for public and private downloads.
*/
add_task(function test_notifications_add_remove()
add_task(function test_DownloadCombinedList_add_remove_getAll()
{
let list = yield promiseNewDownloadList();
let publicList = yield promiseNewList();
let privateList = yield promiseNewList(true);
let combinedList = yield Downloads.getList(Downloads.ALL);
let downloadOne = yield promiseNewDownload();
let downloadTwo = yield promiseNewDownload();
list.add(downloadOne);
list.add(downloadTwo);
let publicDownload = yield promiseNewDownload();
let privateDownload = yield Downloads.createDownload({
source: { url: httpUrl("source.txt"), isPrivate: true },
target: getTempFile(TEST_TARGET_FILE_NAME).path,
});
// Check that we receive add notifications for existing elements.
let addNotifications = 0;
let viewOne = {
onDownloadAdded: function (aDownload) {
// The first download to be notified should be the first that was added.
if (addNotifications == 0) {
do_check_eq(aDownload, downloadOne);
} else if (addNotifications == 1) {
do_check_eq(aDownload, downloadTwo);
}
addNotifications++;
},
};
list.addView(viewOne);
do_check_eq(addNotifications, 2);
publicList.add(publicDownload);
privateList.add(privateDownload);
// Check that we receive add notifications for new elements.
list.add(yield promiseNewDownload());
do_check_eq(addNotifications, 3);
do_check_eq((yield combinedList.getAll()).length, 2);
// Check that we receive remove notifications.
let removeNotifications = 0;
let viewTwo = {
onDownloadRemoved: function (aDownload) {
do_check_eq(aDownload, downloadOne);
removeNotifications++;
},
};
list.addView(viewTwo);
list.remove(downloadOne);
do_check_eq(removeNotifications, 1);
combinedList.remove(publicDownload);
combinedList.remove(privateDownload);
// We should not receive remove notifications after the view is removed.
list.removeView(viewTwo);
list.remove(downloadTwo);
do_check_eq(removeNotifications, 1);
do_check_eq((yield combinedList.getAll()).length, 0);
// We should not receive add notifications after the view is removed.
list.removeView(viewOne);
list.add(yield promiseNewDownload());
do_check_eq(addNotifications, 3);
combinedList.add(publicDownload);
combinedList.add(privateDownload);
do_check_eq((yield publicList.getAll()).length, 1);
do_check_eq((yield privateList.getAll()).length, 1);
do_check_eq((yield combinedList.getAll()).length, 2);
publicList.remove(publicDownload);
privateList.remove(privateDownload);
do_check_eq((yield combinedList.getAll()).length, 0);
});
/**
* Checks that views receive the download change notifications.
* Checks that views receive the download add and remove notifications, and that
* adding and removing views works as expected, both for a normal and a combined
* list.
*/
add_task(function test_notifications_add_remove()
{
for (let isCombined of [false, true]) {
// Force creating a new list for both the public and combined cases.
let list = yield promiseNewList();
if (isCombined) {
list = yield Downloads.getList(Downloads.ALL);
}
let downloadOne = yield promiseNewDownload();
let downloadTwo = yield Downloads.createDownload({
source: { url: httpUrl("source.txt"), isPrivate: true },
target: getTempFile(TEST_TARGET_FILE_NAME).path,
});
list.add(downloadOne);
list.add(downloadTwo);
// Check that we receive add notifications for existing elements.
let addNotifications = 0;
let viewOne = {
onDownloadAdded: function (aDownload) {
// The first download to be notified should be the first that was added.
if (addNotifications == 0) {
do_check_eq(aDownload, downloadOne);
} else if (addNotifications == 1) {
do_check_eq(aDownload, downloadTwo);
}
addNotifications++;
},
};
list.addView(viewOne);
do_check_eq(addNotifications, 2);
// Check that we receive add notifications for new elements.
list.add(yield promiseNewDownload());
do_check_eq(addNotifications, 3);
// Check that we receive remove notifications.
let removeNotifications = 0;
let viewTwo = {
onDownloadRemoved: function (aDownload) {
do_check_eq(aDownload, downloadOne);
removeNotifications++;
},
};
list.addView(viewTwo);
list.remove(downloadOne);
do_check_eq(removeNotifications, 1);
// We should not receive remove notifications after the view is removed.
list.removeView(viewTwo);
list.remove(downloadTwo);
do_check_eq(removeNotifications, 1);
// We should not receive add notifications after the view is removed.
list.removeView(viewOne);
list.add(yield promiseNewDownload());
do_check_eq(addNotifications, 3);
}
});
/**
* Checks that views receive the download change notifications, both for a
* normal and a combined list.
*/
add_task(function test_notifications_change()
{
let list = yield promiseNewDownloadList();
for (let isCombined of [false, true]) {
// Force creating a new list for both the public and combined cases.
let list = yield promiseNewList();
if (isCombined) {
list = yield Downloads.getList(Downloads.ALL);
}
let downloadOne = yield promiseNewDownload();
let downloadTwo = yield promiseNewDownload();
list.add(downloadOne);
list.add(downloadTwo);
let downloadOne = yield promiseNewDownload();
let downloadTwo = yield Downloads.createDownload({
source: { url: httpUrl("source.txt"), isPrivate: true },
target: getTempFile(TEST_TARGET_FILE_NAME).path,
});
list.add(downloadOne);
list.add(downloadTwo);
// Check that we receive change notifications.
let receivedOnDownloadChanged = false;
list.addView({
onDownloadChanged: function (aDownload) {
do_check_eq(aDownload, downloadOne);
receivedOnDownloadChanged = true;
},
});
yield downloadOne.start();
do_check_true(receivedOnDownloadChanged);
// Check that we receive change notifications.
let receivedOnDownloadChanged = false;
list.addView({
onDownloadChanged: function (aDownload) {
do_check_eq(aDownload, downloadOne);
receivedOnDownloadChanged = true;
},
});
yield downloadOne.start();
do_check_true(receivedOnDownloadChanged);
// We should not receive change notifications after a download is removed.
receivedOnDownloadChanged = false;
list.remove(downloadTwo);
yield downloadTwo.start();
do_check_false(receivedOnDownloadChanged);
// We should not receive change notifications after a download is removed.
receivedOnDownloadChanged = false;
list.remove(downloadTwo);
yield downloadTwo.start();
do_check_false(receivedOnDownloadChanged);
}
});
/**
@ -220,7 +280,7 @@ add_task(function test_notifications_change()
*/
add_task(function test_notifications_this()
{
let list = yield promiseNewDownloadList();
let list = yield promiseNewList();
// Check that we receive change notifications.
let receivedOnDownloadAdded = false;
@ -271,7 +331,7 @@ add_task(function test_history_expiration()
// Set max pages to 0 to make the download expire.
Services.prefs.setIntPref("places.history.expiration.max_pages", 0);
let list = yield promiseNewDownloadList();
let list = yield promiseNewList();
let downloadOne = yield promiseNewDownload();
let downloadTwo = yield promiseNewDownload(httpUrl("interruptible.txt"));
@ -317,7 +377,7 @@ add_task(function test_history_expiration()
*/
add_task(function test_history_clear()
{
let list = yield promiseNewDownloadList();
let list = yield promiseNewList();
let downloadOne = yield promiseNewDownload();
let downloadTwo = yield promiseNewDownload();
list.add(downloadOne);
@ -349,7 +409,7 @@ add_task(function test_history_clear()
*/
add_task(function test_removeFinished()
{
let list = yield promiseNewDownloadList();
let list = yield promiseNewList();
let downloadOne = yield promiseNewDownload();
let downloadTwo = yield promiseNewDownload();
let downloadThree = yield promiseNewDownload();

View File

@ -29,8 +29,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "OS",
* @resolves Array [ Newly created DownloadList , associated DownloadStore ].
* @rejects JavaScript exception.
*/
function promiseNewListAndStore(aStorePath) {
return promiseNewDownloadList().then(function (aList) {
function promiseNewListAndStore(aStorePath)
{
return promiseNewList().then(function (aList) {
let path = aStorePath || getTempFile(TEST_STORE_FILE_NAME).path;
let store = new DownloadStore(aList, path);
return [aList, store];

View File

@ -99,42 +99,23 @@ add_task(function test_simpleDownload_string_arguments()
});
/**
* Tests that the getPublicDownloadList function returns the same list when
* called multiple times. More detailed tests are implemented separately for
* the DownloadList module.
* Tests that the getList function returns the same list when called multiple
* times with the same argument, but returns different lists when called with
* different arguments. More detailed tests are implemented separately for the
* DownloadList module.
*/
add_task(function test_getPublicDownloadList()
add_task(function test_getList()
{
let downloadListOne = yield Downloads.getPublicDownloadList();
let downloadListTwo = yield Downloads.getPublicDownloadList();
let publicListOne = yield Downloads.getList(Downloads.PUBLIC);
let privateListOne = yield Downloads.getList(Downloads.PRIVATE);
do_check_eq(downloadListOne, downloadListTwo);
});
let publicListTwo = yield Downloads.getList(Downloads.PUBLIC);
let privateListTwo = yield Downloads.getList(Downloads.PRIVATE);
/**
* Tests that the getPrivateDownloadList function returns the same list when
* called multiple times. More detailed tests are implemented separately for
* the DownloadList module.
*/
add_task(function test_getPrivateDownloadList()
{
let downloadListOne = yield Downloads.getPrivateDownloadList();
let downloadListTwo = yield Downloads.getPrivateDownloadList();
do_check_eq(publicListOne, publicListTwo);
do_check_eq(privateListOne, privateListTwo);
do_check_eq(downloadListOne, downloadListTwo);
});
/**
* Tests that the getPublicDownloadList and getPrivateDownloadList function
* and returns the different list. More detailed tests are implemented
* separately for the DownloadList module.
*/
add_task(function test_public_and_private_lists_differ()
{
let publicDownloadList = yield Downloads.getPublicDownloadList();
let privateDownloadList = yield Downloads.getPrivateDownloadList();
do_check_neq(publicDownloadList, privateDownloadList);
do_check_neq(publicListOne, privateListOne);
});
/**

View File

@ -103,12 +103,9 @@ this.ForgetAboutSite = {
if (useJSTransfer) {
Task.spawn(function() {
for (let promiseList of [Downloads.getPublicDownloadList(),
Downloads.getPrivateDownloadList()]) {
let list = yield promiseList;
list.removeFinished(download => hasRootDomain(
NetUtil.newURI(download.source.url).host, aDomain));
}
let list = yield Downloads.getList(Downloads.ALL);
list.removeFinished(download => hasRootDomain(
NetUtil.newURI(download.source.url).host, aDomain));
}).then(null, Cu.reportError);
}
else {