mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-06 15:27:30 +09:00
[PALEMOON] Bug 1117141 - Part 2 of 2 - Refactor notifications and remove the DownloadsDataItem object
This commit is contained in:
parent
5705b9b36a
commit
63e8a36496
4 changed files with 234 additions and 593 deletions
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"DownloadsCommon",
|
||||
"DownloadsDataItem",
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -22,14 +21,9 @@ this.EXPORTED_SYMBOLS = [
|
|||
*
|
||||
* DownloadsData
|
||||
* Retrieves the list of past and completed downloads from the underlying
|
||||
* Download Manager data, and provides asynchronous notifications allowing
|
||||
* Downloads API data, and provides asynchronous notifications allowing
|
||||
* to build a consistent view of the available data.
|
||||
*
|
||||
* DownloadsDataItem
|
||||
* Represents a single item in the list of downloads. This object wraps the
|
||||
* Download object from the JavaScript API for downloads. A specialized version
|
||||
* of this object is implemented in the Places front-end view.
|
||||
*
|
||||
* DownloadsIndicatorData
|
||||
* This object registers itself with DownloadsData as a view, and transforms the
|
||||
* notifications it receives into overall status data, that is then broadcast to
|
||||
|
|
@ -399,10 +393,10 @@ this.DownloadsCommon = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Given an iterable collection of DownloadDataItems, generates and returns
|
||||
* Given an iterable collection of Download objects, generates and returns
|
||||
* statistics about that collection.
|
||||
*
|
||||
* @param aDataItems An iterable collection of DownloadDataItems.
|
||||
* @param downloads An iterable collection of Download objects.
|
||||
*
|
||||
* @return Object whose properties are the generated statistics. Currently,
|
||||
* we return the following properties:
|
||||
|
|
@ -419,7 +413,7 @@ this.DownloadsCommon = {
|
|||
* complete.
|
||||
* percentComplete : The percentage of bytes successfully downloaded.
|
||||
*/
|
||||
summarizeDownloads: function DC_summarizeDownloads(aDataItems)
|
||||
summarizeDownloads(downloads) {
|
||||
{
|
||||
let summary = {
|
||||
numActive: 0,
|
||||
|
|
@ -431,14 +425,13 @@ this.DownloadsCommon = {
|
|||
// slowestSpeed is Infinity so that we can use Math.min to
|
||||
// find the slowest speed. We'll set this to 0 afterwards if
|
||||
// it's still at Infinity by the time we're done iterating all
|
||||
// dataItems.
|
||||
// download.
|
||||
slowestSpeed: Infinity,
|
||||
rawTimeLeft: -1,
|
||||
percentComplete: -1
|
||||
}
|
||||
|
||||
for (let dataItem of aDataItems) {
|
||||
let download = dataItem.download;
|
||||
for (let download of downloads) {
|
||||
let state = DownloadsCommon.stateOfDownload(download);
|
||||
let maxBytes = DownloadsCommon.maxBytesOfDownload(download);
|
||||
|
||||
|
|
@ -670,16 +663,12 @@ XPCOMUtils.defineLazyGetter(DownloadsCommon, "useJSTransfer", function () {
|
|||
function DownloadsDataCtor(aPrivate) {
|
||||
this._isPrivate = aPrivate;
|
||||
|
||||
// Contains all the available DownloadsDataItem objects.
|
||||
this.dataItems = new Set();
|
||||
// Contains all the available Download objects and their integer state.
|
||||
this.oldDownloadStates = new Map();
|
||||
|
||||
// Array of view objects that should be notified when the available download
|
||||
// data changes.
|
||||
this._views = [];
|
||||
|
||||
// Maps Download objects to DownloadDataItem objects.
|
||||
this._downloadToDataItemMap = new Map();
|
||||
}
|
||||
|
||||
DownloadsDataCtor.prototype = {
|
||||
|
|
@ -705,13 +694,18 @@ DownloadsDataCtor.prototype = {
|
|||
return;
|
||||
},
|
||||
|
||||
/**
|
||||
* Iterator for all the available Download objects. This is empty until the
|
||||
* data has been loaded using the JavaScript API for downloads.
|
||||
*/
|
||||
get downloads() this.oldDownloadStates.keys(),
|
||||
|
||||
/**
|
||||
* True if there are finished downloads that can be removed from the list.
|
||||
*/
|
||||
get canRemoveFinished()
|
||||
{
|
||||
for (let dataItem of this.dataItems) {
|
||||
let download = dataItem.download;
|
||||
for (let download of this.oldDownloadStates.keys()) {
|
||||
// Stopped, paused, and failed downloads with partial data are removed.
|
||||
if (download.stopped && !(download.canceled && download.hasPartialData)) {
|
||||
return true;
|
||||
|
|
@ -734,37 +728,32 @@ DownloadsDataCtor.prototype = {
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Integration with the asynchronous Downloads back-end
|
||||
|
||||
onDownloadAdded: function (aDownload)
|
||||
{
|
||||
let dataItem = new DownloadsDataItem(aDownload);
|
||||
this._downloadToDataItemMap.set(aDownload, dataItem);
|
||||
this.dataItems.add(dataItem);
|
||||
this.oldDownloadStates.set(aDownload,
|
||||
DownloadsCommon.stateOfDownload(aDownload));
|
||||
onDownloadAdded(download) {
|
||||
// Download objects do not store the end time of downloads, as the Downloads
|
||||
// API does not need to persist this information for all platforms. Once a
|
||||
// download terminates on a Desktop browser, it becomes a history download,
|
||||
// for which the end time is stored differently, as a Places annotation.
|
||||
download.endTime = Date.now();
|
||||
|
||||
this.oldDownloadStates.set(download,
|
||||
DownloadsCommon.stateOfDownload(download));
|
||||
|
||||
for (let view of this._views) {
|
||||
view.onDataItemAdded(dataItem, true);
|
||||
view.onDownloadAdded(download, true);
|
||||
}
|
||||
},
|
||||
|
||||
onDownloadChanged: function (aDownload)
|
||||
{
|
||||
let aDataItem = this._downloadToDataItemMap.get(aDownload);
|
||||
if (!aDataItem) {
|
||||
Cu.reportError("Download doesn't exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
let oldState = this.oldDownloadStates.get(aDownload);
|
||||
let newState = DownloadsCommon.stateOfDownload(aDownload);
|
||||
this.oldDownloadStates.set(aDownload, newState);
|
||||
onDownloadChanged(download) {
|
||||
let oldState = this.oldDownloadStates.get(download);
|
||||
let newState = DownloadsCommon.stateOfDownload(download);
|
||||
this.oldDownloadStates.set(download, newState);
|
||||
|
||||
if (oldState != newState) {
|
||||
if (aDownload.succeeded ||
|
||||
(aDownload.canceled && !aDownload.hasPartialData) ||
|
||||
aDownload.error) {
|
||||
if (download.succeeded ||
|
||||
(download.canceled && !download.hasPartialData) ||
|
||||
download.error) {
|
||||
// Store the end time that may be displayed by the views.
|
||||
aDownload.endTime = Date.now();
|
||||
download.endTime = Date.now();
|
||||
|
||||
// This state transition code should actually be located in a Downloads
|
||||
// API module (bug 941009). Moreover, the fact that state is stored as
|
||||
|
|
@ -773,17 +762,17 @@ DownloadsDataCtor.prototype = {
|
|||
if (!this._isPrivate) {
|
||||
try {
|
||||
let downloadMetaData = {
|
||||
state: DownloadsCommon.stateOfDownload(aDownload),
|
||||
endTime: aDownload.endTime,
|
||||
state: DownloadsCommon.stateOfDownload(download),
|
||||
endTime: download.endTime,
|
||||
};
|
||||
if (aDownload.succeeded ||
|
||||
(aDownload.error && aDownload.error.becauseBlocked)) {
|
||||
if (download.succeeded ||
|
||||
(download.error && download.error.becauseBlocked)) {
|
||||
downloadMetaData.fileSize =
|
||||
DownloadsCommon.maxBytesOfDownload(aDataItem.download);
|
||||
DownloadsCommon.maxBytesOfDownload(download);
|
||||
}
|
||||
|
||||
PlacesUtils.annotations.setPageAnnotation(
|
||||
NetUtil.newURI(aDownload.source.url),
|
||||
NetUtil.newURI(download.source.url),
|
||||
"downloads/metaData",
|
||||
JSON.stringify(downloadMetaData), 0,
|
||||
PlacesUtils.annotations.EXPIRE_WITH_HISTORY);
|
||||
|
|
@ -795,41 +784,33 @@ DownloadsDataCtor.prototype = {
|
|||
|
||||
for (let view of this._views) {
|
||||
try {
|
||||
view.onDataItemStateChanged(aDataItem);
|
||||
view.onDownloadStateChanged(download);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (aDownload.succeeded ||
|
||||
(aDownload.error && aDownload.error.becauseBlocked)) {
|
||||
if (download.succeeded ||
|
||||
(download.error && download.error.becauseBlocked)) {
|
||||
this._notifyDownloadEvent("finish");
|
||||
}
|
||||
}
|
||||
|
||||
if (!aDownload.newDownloadNotified) {
|
||||
aDownload.newDownloadNotified = true;
|
||||
if (!download.newDownloadNotified) {
|
||||
download.newDownloadNotified = true;
|
||||
this._notifyDownloadEvent("start");
|
||||
}
|
||||
|
||||
for (let view of this._views) {
|
||||
view.onDataItemChanged(aDataItem);
|
||||
view.onDownloadChanged(download);
|
||||
}
|
||||
},
|
||||
|
||||
onDownloadRemoved: function (aDownload)
|
||||
{
|
||||
let dataItem = this._downloadToDataItemMap.get(aDownload);
|
||||
if (!dataItem) {
|
||||
Cu.reportError("Download doesn't exist.");
|
||||
return;
|
||||
}
|
||||
onDownloadRemoved(download) {
|
||||
this.oldDownloadStates.delete(download);
|
||||
|
||||
this._downloadToDataItemMap.delete(aDownload);
|
||||
this.dataItems.delete(dataItem);
|
||||
this.oldDownloadStates.delete(aDownload);
|
||||
for (let view of this._views) {
|
||||
view.onDataItemRemoved(dataItem);
|
||||
view.onDownloadRemoved(download);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -881,12 +862,9 @@ DownloadsDataCtor.prototype = {
|
|||
//let loadedItemsArray = [dataItem
|
||||
// for each (dataItem in this.dataItems)
|
||||
// if (dataItem)];
|
||||
let loadedItemsArray = [...this.dataItems];
|
||||
|
||||
loadedItemsArray.sort(function(a, b) b.download.startTime - a.download.startTime);
|
||||
loadedItemsArray.forEach(
|
||||
function (dataItem) aView.onDataItemAdded(dataItem, false)
|
||||
);
|
||||
let downloadsArray = [...this.oldDownloadStates.keys()];
|
||||
downloadsArray.sort((a, b) => b.startTime - a.startTime);
|
||||
downloadsArray.forEach(download => aView.onDownloadAdded(download, false));
|
||||
|
||||
// Notify the view that all data is available unless loading is in progress.
|
||||
if (!this._pendingStatement) {
|
||||
|
|
@ -1337,254 +1315,6 @@ XPCOMUtils.defineLazyGetter(this, "DownloadsData", function() {
|
|||
return new DownloadsDataCtor(false);
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadsDataItem
|
||||
|
||||
/**
|
||||
* Represents a single item in the list of downloads. This object either wraps
|
||||
* an existing nsIDownload from the Download Manager, or provides the same
|
||||
* information read directly from the downloads database, with the possibility
|
||||
* of querying the nsIDownload lazily, for performance reasons.
|
||||
*
|
||||
* @param aSource
|
||||
* Object containing the data with which the item should be initialized.
|
||||
* This should implement either nsIDownload or mozIStorageRow. If the
|
||||
* JavaScript API for downloads is enabled, this is a Download object.
|
||||
*/
|
||||
function DownloadsDataItem(aSource)
|
||||
{
|
||||
this._initFromJSDownload(aSource);
|
||||
}
|
||||
|
||||
DownloadsDataItem.prototype = {
|
||||
get state() DownloadsCommon.stateOfDownload(this.download),
|
||||
|
||||
/**
|
||||
* Initializes this object from the JavaScript API for downloads.
|
||||
*
|
||||
* The endTime property is initialized to the current date and time.
|
||||
*
|
||||
* @param aDownload
|
||||
* The Download object with the current state.
|
||||
*/
|
||||
_initFromJSDownload: function (aDownload)
|
||||
{
|
||||
this.download = aDownload;
|
||||
this.download.endTime = Date.now();
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes this object from a download object of the Download Manager.
|
||||
*
|
||||
* The endTime property is initialized to the current date and time.
|
||||
*
|
||||
* @param aDownload
|
||||
* The nsIDownload with the current state.
|
||||
*/
|
||||
_initFromDownload: function DDI_initFromDownload(aDownload)
|
||||
{
|
||||
this._download = aDownload;
|
||||
|
||||
// Fetch all the download properties eagerly.
|
||||
this.downloadGuid = aDownload.guid;
|
||||
this.file = aDownload.target.spec;
|
||||
this.target = aDownload.displayName;
|
||||
this.uri = aDownload.source.spec;
|
||||
this.referrer = aDownload.referrer && aDownload.referrer.spec;
|
||||
this.state = aDownload.state;
|
||||
this.startTime = Math.round(aDownload.startTime / 1000);
|
||||
this.endTime = Date.now();
|
||||
this.currBytes = aDownload.amountTransferred;
|
||||
this.maxBytes = aDownload.size;
|
||||
this.resumable = aDownload.resumable;
|
||||
this.speed = aDownload.speed;
|
||||
this.percentComplete = aDownload.percentComplete;
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes this object from a data row in the downloads database, without
|
||||
* querying the associated nsIDownload object, to improve performance when
|
||||
* loading the list of downloads asynchronously.
|
||||
*
|
||||
* When this object is initialized in this way, accessing the "download"
|
||||
* property loads the underlying nsIDownload object synchronously, and should
|
||||
* be avoided unless the object is really required.
|
||||
*
|
||||
* @param aStorageRow
|
||||
* The mozIStorageRow from the downloads database.
|
||||
*/
|
||||
_initFromDataRow: function DDI_initFromDataRow(aStorageRow)
|
||||
{
|
||||
// Get the download properties from the data row.
|
||||
this._download = null;
|
||||
this.downloadGuid = aStorageRow.getResultByName("guid");
|
||||
this.file = aStorageRow.getResultByName("target");
|
||||
this.target = aStorageRow.getResultByName("name");
|
||||
this.uri = aStorageRow.getResultByName("source");
|
||||
this.referrer = aStorageRow.getResultByName("referrer");
|
||||
this.state = aStorageRow.getResultByName("state");
|
||||
this.startTime = Math.round(aStorageRow.getResultByName("startTime") / 1000);
|
||||
this.endTime = Math.round(aStorageRow.getResultByName("endTime") / 1000);
|
||||
this.currBytes = aStorageRow.getResultByName("currBytes");
|
||||
this.maxBytes = aStorageRow.getResultByName("maxBytes");
|
||||
|
||||
// Now we have to determine if the download is resumable, but don't want to
|
||||
// access the underlying download object unnecessarily. The only case where
|
||||
// the property is relevant is when we are currently downloading data, and
|
||||
// in this case the download object is already loaded in memory or will be
|
||||
// loaded very soon in any case. In all the other cases, including a paused
|
||||
// download, we assume that the download is resumable. The property will be
|
||||
// updated as soon as the underlying download state changes.
|
||||
|
||||
// We'll start by assuming we're resumable, and then if we're downloading,
|
||||
// update resumable property in case we were wrong.
|
||||
this.resumable = true;
|
||||
|
||||
if (this.state == nsIDM.DOWNLOAD_DOWNLOADING) {
|
||||
this.getDownload(function(aDownload) {
|
||||
this.resumable = aDownload.resumable;
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
// Compute the other properties without accessing the download object.
|
||||
this.speed = 0;
|
||||
this.percentComplete = this.maxBytes <= 0
|
||||
? -1
|
||||
: Math.round(this.currBytes / this.maxBytes * 100);
|
||||
},
|
||||
|
||||
/**
|
||||
* Asynchronous getter for the download object corresponding to this data item.
|
||||
*
|
||||
* @param aCallback
|
||||
* A callback function which will be called when the download object is
|
||||
* available. It should accept one argument which will be the download
|
||||
* object.
|
||||
*/
|
||||
getDownload: function DDI_getDownload(aCallback) {
|
||||
if (this._download) {
|
||||
// Return the download object asynchronously to the caller
|
||||
let download = this._download;
|
||||
Services.tm.mainThread.dispatch(function () aCallback(download),
|
||||
Ci.nsIThread.DISPATCH_NORMAL);
|
||||
} else {
|
||||
Services.downloads.getDownloadByGUID(this.downloadGuid,
|
||||
function(aStatus, aResult) {
|
||||
if (!Components.isSuccessCode(aStatus)) {
|
||||
Cu.reportError(
|
||||
new Components.Exception("Cannot retrieve download for GUID: " +
|
||||
this.downloadGuid));
|
||||
} else {
|
||||
this._download = aResult;
|
||||
aCallback(aResult);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Indicates whether the download is proceeding normally, and not finished
|
||||
* yet. This includes paused downloads. When this property is true, the
|
||||
* "progress" property represents the current progress of the download.
|
||||
*/
|
||||
get inProgress()
|
||||
{
|
||||
return [
|
||||
nsIDM.DOWNLOAD_NOTSTARTED,
|
||||
nsIDM.DOWNLOAD_QUEUED,
|
||||
nsIDM.DOWNLOAD_DOWNLOADING,
|
||||
nsIDM.DOWNLOAD_PAUSED,
|
||||
nsIDM.DOWNLOAD_SCANNING,
|
||||
].indexOf(this.state) != -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* This is true during the initial phases of a download, before the actual
|
||||
* download of data bytes starts.
|
||||
*/
|
||||
get starting()
|
||||
{
|
||||
return this.state == nsIDM.DOWNLOAD_NOTSTARTED ||
|
||||
this.state == nsIDM.DOWNLOAD_QUEUED;
|
||||
},
|
||||
|
||||
/**
|
||||
* Indicates whether the download is paused.
|
||||
*/
|
||||
get paused()
|
||||
{
|
||||
return this.state == nsIDM.DOWNLOAD_PAUSED;
|
||||
},
|
||||
|
||||
/**
|
||||
* Indicates whether the download is in a final state, either because it
|
||||
* completed successfully or because it was blocked.
|
||||
*/
|
||||
get done()
|
||||
{
|
||||
return [
|
||||
nsIDM.DOWNLOAD_FINISHED,
|
||||
nsIDM.DOWNLOAD_BLOCKED_PARENTAL,
|
||||
nsIDM.DOWNLOAD_BLOCKED_POLICY,
|
||||
nsIDM.DOWNLOAD_DIRTY,
|
||||
].indexOf(this.state) != -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Indicates whether the download stopped because of an error, and can be
|
||||
* resumed manually.
|
||||
*/
|
||||
get canRetry()
|
||||
{
|
||||
return this.state == nsIDM.DOWNLOAD_CANCELED ||
|
||||
this.state == nsIDM.DOWNLOAD_FAILED;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the nsILocalFile for the download target.
|
||||
*
|
||||
* @throws if the native path is not valid. This can happen if the same
|
||||
* profile is used on different platforms, for example if a native
|
||||
* Windows path is stored and then the item is accessed on a Mac.
|
||||
*
|
||||
* @deprecated Callers should use OS.File and "download.target.path".
|
||||
*/
|
||||
get localFile()
|
||||
{
|
||||
// We should remove should use this.download.target.partFilePath and check asyncrhonously.
|
||||
return new FileUtils.File(this.download.target.path);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the nsILocalFile for the partially downloaded target.
|
||||
*
|
||||
* @throws if the native path is not valid. This can happen if the same
|
||||
* profile is used on different platforms, for example if a native
|
||||
* Windows path is stored and then the item is accessed on a Mac.
|
||||
*
|
||||
* @deprecated Callers should use OS.File and "download.target.partFilePath".
|
||||
*/
|
||||
get partFile()
|
||||
{
|
||||
return new FileUtils.File(this.download.target.path + kPartialDownloadSuffix);
|
||||
},
|
||||
|
||||
/**
|
||||
* Support function that deletes the local file for a download. This is
|
||||
* used in cases where the Download Manager service doesn't delete the file
|
||||
* from disk when cancelling. See bug 732924.
|
||||
*/
|
||||
_ensureLocalFileRemoved: function DDI__ensureLocalFileRemoved()
|
||||
{
|
||||
try {
|
||||
let localFile = this.localFile;
|
||||
if (localFile.exists()) {
|
||||
localFile.remove(false);
|
||||
}
|
||||
} catch (ex) { }
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadsViewPrototype
|
||||
|
||||
|
|
@ -1712,9 +1442,9 @@ const DownloadsViewPrototype = {
|
|||
* Called when a new download data item is available, either during the
|
||||
* asynchronous data load or when a new download is started.
|
||||
*
|
||||
* @param aDataItem
|
||||
* DownloadsDataItem object that was just added.
|
||||
* @param aNewest
|
||||
* @param download
|
||||
* Download object that was just added.
|
||||
* @param newest
|
||||
* When true, indicates that this item is the most recent and should be
|
||||
* added in the topmost position. This happens when a new download is
|
||||
* started. When false, indicates that the item is the least recent
|
||||
|
|
@ -1723,7 +1453,33 @@ const DownloadsViewPrototype = {
|
|||
*
|
||||
* @note Subclasses should override this.
|
||||
*/
|
||||
onDataItemAdded: function DVP_onDataItemAdded(aDataItem, aNewest)
|
||||
onDownloadAdded(download, newest) {
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the overall state of a Download has changed. In particular,
|
||||
* this is called only once when the download succeeds or is blocked
|
||||
* permanently, and is never called if only the current progress changed.
|
||||
*
|
||||
* The onDownloadChanged notification will always be sent afterwards.
|
||||
*
|
||||
* @note Subclasses should override this.
|
||||
*/
|
||||
onDownloadStateChanged(download) {
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called every time any state property of a Download may have changed,
|
||||
* including progress properties.
|
||||
*
|
||||
* Note that progress notification changes are throttled at the Downloads.jsm
|
||||
* API level, and there is no throttling mechanism in the front-end.
|
||||
*
|
||||
* @note Subclasses should override this.
|
||||
*/
|
||||
onDownloadChanged(download) {
|
||||
{
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
|
@ -1732,37 +1488,12 @@ const DownloadsViewPrototype = {
|
|||
* Called when a data item is removed, ensures that the widget associated with
|
||||
* the view item is removed from the user interface.
|
||||
*
|
||||
* @param aDataItem
|
||||
* DownloadsDataItem object that is being removed.
|
||||
* @param download
|
||||
* Download object that is being removed.
|
||||
*
|
||||
* @note Subclasses should override this.
|
||||
*/
|
||||
onDataItemRemoved: function DVP_onDataItemRemoved(aDataItem)
|
||||
{
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the "state" property of a DownloadsDataItem has changed.
|
||||
*
|
||||
* The onDataItemChanged notification will be sent afterwards.
|
||||
*
|
||||
* @note Subclasses should override this.
|
||||
*/
|
||||
onDataItemStateChanged(aDataItem) {
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called every time any state property of a DownloadsDataItem may have
|
||||
* changed, including progress properties and the "state" property.
|
||||
*
|
||||
* Note that progress notification changes are throttled at the Downloads.jsm
|
||||
* API level, and there is no throttling mechanism in the front-end.
|
||||
*
|
||||
* @note Subclasses should override this.
|
||||
*/
|
||||
onDataItemChanged(aDataItem) {
|
||||
onDownloadRemoved(download) {
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
|
|
@ -1826,9 +1557,6 @@ DownloadsIndicatorDataCtor.prototype = {
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Callback functions from DownloadsData
|
||||
|
||||
/**
|
||||
* Called after data loading finished.
|
||||
*/
|
||||
onDataLoadCompleted: function DID_onDataLoadCompleted()
|
||||
{
|
||||
DownloadsViewPrototype.onDataLoadCompleted.call(this);
|
||||
|
|
@ -1845,42 +1573,13 @@ DownloadsIndicatorDataCtor.prototype = {
|
|||
this._itemCount = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a new download data item is available, either during the
|
||||
* asynchronous data load or when a new download is started.
|
||||
*
|
||||
* @param aDataItem
|
||||
* DownloadsDataItem object that was just added.
|
||||
* @param aNewest
|
||||
* When true, indicates that this item is the most recent and should be
|
||||
* added in the topmost position. This happens when a new download is
|
||||
* started. When false, indicates that the item is the least recent
|
||||
* with regard to the items that have been already added. The latter
|
||||
* generally happens during the asynchronous data load.
|
||||
*/
|
||||
onDataItemAdded: function DID_onDataItemAdded(aDataItem, aNewest)
|
||||
onDownloadAdded(download, newest) {
|
||||
{
|
||||
this._itemCount++;
|
||||
this._updateViews();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a data item is removed, ensures that the widget associated with
|
||||
* the view item is removed from the user interface.
|
||||
*
|
||||
* @param aDataItem
|
||||
* DownloadsDataItem object that is being removed.
|
||||
*/
|
||||
onDataItemRemoved: function DID_onDataItemRemoved(aDataItem)
|
||||
{
|
||||
this._itemCount--;
|
||||
this._updateViews();
|
||||
},
|
||||
|
||||
// DownloadsView
|
||||
onDataItemStateChanged(aDataItem) {
|
||||
let download = aDataItem.download;
|
||||
|
||||
onDownloadStateChanged(download) {
|
||||
if (download.succeeded || download.error) {
|
||||
this.attention = true;
|
||||
}
|
||||
|
|
@ -1890,8 +1589,12 @@ DownloadsIndicatorDataCtor.prototype = {
|
|||
this._lastTimeLeft = -1;
|
||||
},
|
||||
|
||||
// DownloadsView
|
||||
onDataItemChanged() {
|
||||
onDownloadChanged(download) {
|
||||
this._updateViews();
|
||||
},
|
||||
|
||||
onDownloadRemoved(download) {
|
||||
this._itemCount--;
|
||||
this._updateViews();
|
||||
},
|
||||
|
||||
|
|
@ -1983,22 +1686,17 @@ DownloadsIndicatorDataCtor.prototype = {
|
|||
_lastTimeLeft: -1,
|
||||
|
||||
/**
|
||||
* A generator function for the dataItems that this summary is currently
|
||||
* A generator function for the Download objects this summary is currently
|
||||
* interested in. This generator is passed off to summarizeDownloads in order
|
||||
* to generate statistics about the dataItems we care about - in this case,
|
||||
* it's all dataItems for active downloads.
|
||||
* to generate statistics about the downloads we care about - in this case,
|
||||
* it's all active downloads.
|
||||
*/
|
||||
_activeDataItems: function DID_activeDataItems()
|
||||
{
|
||||
let dataItems = this._isPrivate ? PrivateDownloadsData.dataItems
|
||||
: DownloadsData.dataItems;
|
||||
for (let dataItem of dataItems) {
|
||||
if (!dataItem) {
|
||||
continue;
|
||||
}
|
||||
let download = dataItem.download;
|
||||
_activeDownloads() {
|
||||
let downloads = this._isPrivate ? PrivateDownloadsData.downloads
|
||||
: DownloadsData.downloads;
|
||||
for (let download of downloads) {
|
||||
if (!download.stopped || (download.canceled && download.hasPartialData)) {
|
||||
yield dataItem;
|
||||
yield download;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -2009,7 +1707,7 @@ DownloadsIndicatorDataCtor.prototype = {
|
|||
_refreshProperties: function DID_refreshProperties()
|
||||
{
|
||||
let summary =
|
||||
DownloadsCommon.summarizeDownloads(this._activeDataItems());
|
||||
DownloadsCommon.summarizeDownloads(this._activeDownloads());
|
||||
|
||||
// Determine if the indicator should be shown or get attention.
|
||||
this._hasDownloads = (this._itemCount > 0);
|
||||
|
|
@ -2070,7 +1768,7 @@ function DownloadsSummaryData(aIsPrivate, aNumToExclude) {
|
|||
// completely separated from one another.
|
||||
this._loading = false;
|
||||
|
||||
this._dataItems = [];
|
||||
this._downloads = [];
|
||||
|
||||
// Floating point value indicating the last number of seconds estimated until
|
||||
// the longest download will finish. We need to store this value so that we
|
||||
|
|
@ -2110,9 +1808,9 @@ DownloadsSummaryData.prototype = {
|
|||
DownloadsViewPrototype.removeView.call(this, aView);
|
||||
|
||||
if (this._views.length == 0) {
|
||||
// Clear out our collection of DownloadDataItems. If we ever have
|
||||
// Clear out our collection of Download objects. If we ever have
|
||||
// another view registered with us, this will get re-populated.
|
||||
this._dataItems = [];
|
||||
this._downloads = [];
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -2132,33 +1830,29 @@ DownloadsSummaryData.prototype = {
|
|||
this._dataItems = [];
|
||||
},
|
||||
|
||||
onDataItemAdded: function DSD_onDataItemAdded(aDataItem, aNewest)
|
||||
{
|
||||
if (aNewest) {
|
||||
this._dataItems.unshift(aDataItem);
|
||||
onDownloadAdded(download, newest) {
|
||||
if (newest) {
|
||||
this._downloads.unshift(download);
|
||||
} else {
|
||||
this._dataItems.push(aDataItem);
|
||||
this._downloads.push(download);
|
||||
}
|
||||
|
||||
this._updateViews();
|
||||
},
|
||||
|
||||
onDataItemRemoved: function DSD_onDataItemRemoved(aDataItem)
|
||||
{
|
||||
let itemIndex = this._dataItems.indexOf(aDataItem);
|
||||
this._dataItems.splice(itemIndex, 1);
|
||||
this._updateViews();
|
||||
},
|
||||
|
||||
// DownloadsView
|
||||
onDataItemStateChanged() {
|
||||
onDownloadStateChanged() {
|
||||
// Since the state of a download changed, reset the estimated time left.
|
||||
this._lastRawTimeLeft = -1;
|
||||
this._lastTimeLeft = -1;
|
||||
},
|
||||
|
||||
// DownloadsView
|
||||
onDataItemChanged() {
|
||||
onDownloadChanged() {
|
||||
this._updateViews();
|
||||
},
|
||||
|
||||
onDownloadRemoved(download) {
|
||||
let itemIndex = this._downloads.indexOf(download);
|
||||
this._downloads.splice(itemIndex, 1);
|
||||
this._updateViews();
|
||||
},
|
||||
|
||||
|
|
@ -2197,17 +1891,16 @@ DownloadsSummaryData.prototype = {
|
|||
//// Property updating based on current download status
|
||||
|
||||
/**
|
||||
* A generator function for the dataItems that this summary is currently
|
||||
* A generator function for the Download objects this summary is currently
|
||||
* interested in. This generator is passed off to summarizeDownloads in order
|
||||
* to generate statistics about the dataItems we care about - in this case,
|
||||
* it's the dataItems in this._dataItems after the first few to exclude,
|
||||
* to generate statistics about the downloads we care about - in this case,
|
||||
* it's the downloads in this._downloads after the first few to exclude,
|
||||
* which was set when constructing this DownloadsSummaryData instance.
|
||||
*/
|
||||
_dataItemsForSummary: function DSD_dataItemsForSummary()
|
||||
{
|
||||
if (this._dataItems.length > 0) {
|
||||
for (let i = this._numToExclude; i < this._dataItems.length; ++i) {
|
||||
yield this._dataItems[i];
|
||||
_downloadsForSummary() {
|
||||
if (this._downloads.length > 0) {
|
||||
for (let i = this._numToExclude; i < this._downloads.length; ++i) {
|
||||
yield this._downloads[i];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -2219,7 +1912,7 @@ DownloadsSummaryData.prototype = {
|
|||
{
|
||||
// Pre-load summary with default values.
|
||||
let summary =
|
||||
DownloadsCommon.summarizeDownloads(this._dataItemsForSummary());
|
||||
DownloadsCommon.summarizeDownloads(this._downloadsForSummary());
|
||||
|
||||
this._description = DownloadsCommon.strings
|
||||
.otherDownloads2(summary.numActive);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue