From beeede618586155d0f3fcb8e9313e076eef3e6e5 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Sun, 29 Jul 2018 12:41:33 +0200 Subject: [PALEMOON] Bug 1127867 - Use the new back-end property to get the size of downloads asynchronously --- .../components/downloads/DownloadsCommon.jsm | 69 +++++++--------------- .../downloads/content/allDownloadsViewOverlay.js | 69 ++++++++++++---------- .../components/downloads/content/downloads.js | 33 +---------- .../downloads/content/downloadsViewCommon.js | 28 ++++++--- 4 files changed, 79 insertions(+), 120 deletions(-) (limited to 'application/palemoon') diff --git a/application/palemoon/components/downloads/DownloadsCommon.jsm b/application/palemoon/components/downloads/DownloadsCommon.jsm index 652d2433b..73467e813 100644 --- a/application/palemoon/components/downloads/DownloadsCommon.jsm +++ b/application/palemoon/components/downloads/DownloadsCommon.jsm @@ -372,26 +372,6 @@ this.DownloadsCommon = { return nsIDM.DOWNLOAD_NOTSTARTED; }, - /** - * Returns the highest number of bytes transferred or the known size of the - * given Download object, or -1 if the size is not available. Callers should - * use Download properties directly when possible. - */ - maxBytesOfDownload(download) { - if (download.succeeded) { - // If the download succeeded, show the final size if available, otherwise - // use the last known number of bytes transferred. The final size on disk - // will be available when bug 941063 is resolved. - return download.hasProgress ? download.totalBytes : download.currentBytes; - } else if (download.hasProgress) { - // If the final size and progress are known, use them. - return download.totalBytes; - } else { - // The download final size and progress percentage is unknown. - return -1; - } - }, - /** * Given an iterable collection of Download objects, generates and returns * statistics about that collection. @@ -431,38 +411,31 @@ this.DownloadsCommon = { } for (let download of downloads) { - let state = DownloadsCommon.stateOfDownload(download); - let maxBytes = DownloadsCommon.maxBytesOfDownload(download); - summary.numActive++; - switch (state) { - case nsIDM.DOWNLOAD_PAUSED: - summary.numPaused++; - break; - case nsIDM.DOWNLOAD_SCANNING: - summary.numScanning++; - break; - case nsIDM.DOWNLOAD_DOWNLOADING: - summary.numDownloading++; - if (maxBytes > 0 && download.speed > 0) { - let sizeLeft = maxBytes - download.currentBytes; - summary.rawTimeLeft = Math.max(summary.rawTimeLeft, - sizeLeft / download.speed); - summary.slowestSpeed = Math.min(summary.slowestSpeed, - download.speed); - } - break; + + if (!download.stopped) { + summary.numDownloading++; + if (download.hasProgress && download.speed > 0) { + let sizeLeft = download.totalBytes - download.currentBytes; + summary.rawTimeLeft = Math.max(summary.rawTimeLeft, + sizeLeft / download.speed); + summary.slowestSpeed = Math.min(summary.slowestSpeed, + download.speed); + } + } else if (download.canceled && download.hasPartialData) { + summary.numPaused++; } // Only add to total values if we actually know the download size. - if (maxBytes > 0 && state != nsIDM.DOWNLOAD_CANCELED && - state != nsIDM.DOWNLOAD_FAILED) { - summary.totalSize += maxBytes; + if (download.succeeded) { + summary.totalSize += download.target.size; + summary.totalTransferred += download.target.size; + } else if (download.hasProgress) { + summary.totalSize += download.totalBytes; summary.totalTransferred += download.currentBytes; } } - if (summary.numActive != 0 && summary.totalSize != 0 && - summary.numActive != summary.numScanning) { + if (summary.totalSize != 0) { summary.percentComplete = (summary.totalTransferred / summary.totalSize) * 100; } @@ -764,10 +737,8 @@ DownloadsDataCtor.prototype = { state: DownloadsCommon.stateOfDownload(download), endTime: download.endTime, }; - if (download.succeeded || - (download.error && download.error.becauseBlocked)) { - downloadMetaData.fileSize = - DownloadsCommon.maxBytesOfDownload(download); + if (download.succeeded) { + downloadMetaData.fileSize = download.target.size; } PlacesUtils.annotations.setPageAnnotation( diff --git a/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js b/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js index a5cbb3a5f..50f77041b 100644 --- a/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js +++ b/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js @@ -28,8 +28,14 @@ const DOWNLOAD_VIEW_SUPPORTED_COMMANDS = */ function HistoryDownload(aPlacesNode) { // TODO (bug 829201): history downloads should get the referrer from Places. - this.source = { url: aPlacesNode.uri }; - this.target = { path: undefined, size: undefined }; + this.source = { + url: aPlacesNode.uri, + }; + this.target = { + path: undefined, + exists: false, + size: undefined, + }; // In case this download cannot obtain its end time from the Places metadata, // use the time from the Places node, that is the start time of the download. @@ -63,6 +69,10 @@ HistoryDownload.prototype = { this.canceled = metaData.state == nsIDM.DOWNLOAD_CANCELED || metaData.state == nsIDM.DOWNLOAD_PAUSED; this.endTime = metaData.endTime; + + // Normal history downloads are assumed to exist until the user interface + // is refreshed, at which point these values may be updated. + this.target.exists = true; this.target.size = metaData.fileSize; } catch (ex) { // Metadata might be missing from a download that has started but hasn't @@ -78,13 +88,11 @@ HistoryDownload.prototype = { this.succeeded = !this.target.path; this.error = this.target.path ? { message: "Unstarted download." } : null; this.canceled = false; - this.target.size = -1; - } - // This property is currently used to get the size of downloads, but will be - // replaced by download.target.size when available for session downloads. - this.totalBytes = this.target.size; - this.currentBytes = this.target.size; + // These properties may be updated if the user interface is refreshed. + this.exists = false; + this.target.size = undefined; + } }, /** @@ -123,6 +131,20 @@ HistoryDownload.prototype = { return Promise.resolve(); }, + + /** + * This method mimicks the "refresh" method of session downloads, except that + * it cannot notify that the data changed to the Downloads View. + */ + refresh: Task.async(function* () { + try { + this.target.size = (yield OS.File.stat(this.target.path)).size; + this.target.exists = true; + } catch (ex) { + // We keep the known file size from the metadata, if any. + this.target.exists = false; + } + }), }; /** @@ -267,20 +289,8 @@ HistoryDownloadElementShell.prototype = { return false; switch (aCommand) { case "downloadsCmd_open": - // We cannot open a session download file unless it's succeeded. - // If it's succeeded, we need to make sure the file was not removed, - // as we do for past downloads. - if (this._sessionDownload && !this.download.succeeded) { - return false; - } - - if (this._targetFileChecked) { - return this._targetFileExists; - } - - // If the target file information is not yet fetched, - // temporarily assume that the file is in place. - return this.download.succeeded; + // This property is false if the download did not succeed. + return this.download.target.exists; case "downloadsCmd_show": // TODO: Bug 827010 - Handle part-file asynchronously. if (this._sessionDownload && this.download.target.partFilePath) { @@ -290,13 +300,8 @@ HistoryDownloadElementShell.prototype = { } } - if (this._targetFileChecked) { - return this._targetFileExists; - } - - // If the target file information is not yet fetched, - // temporarily assume that the file is in place. - return this.download.succeeded; + // This property is false if the download did not succeed. + return this.download.target.exists; case "downloadsCmd_pauseResume": return this.download.hasPartialData && !this.download.error; case "downloadsCmd_retry": @@ -430,7 +435,7 @@ HistoryDownloadElementShell.prototype = { _checkTargetFileOnSelect: Task.async(function* () { try { - this._targetFileExists = yield OS.File.exists(this.download.target.path); + yield this.download.refresh(); } finally { // Do not try to check for existence again if this failed once. this._targetFileChecked = true; @@ -440,6 +445,10 @@ HistoryDownloadElementShell.prototype = { if (this.element.selected) { goUpdateDownloadCommands(); } + + // Ensure the interface has been updated based on the new values. We need to + // do this because history downloads can't trigger update notifications. + this._updateProgress(); }), }; diff --git a/application/palemoon/components/downloads/content/downloads.js b/application/palemoon/components/downloads/content/downloads.js index 01682d325..199324b6b 100644 --- a/application/palemoon/components/downloads/content/downloads.js +++ b/application/palemoon/components/downloads/content/downloads.js @@ -555,7 +555,7 @@ const DownloadsPanel = { // do these checks on a background thread, and don't prevent the panel to // be displayed while these checks are being performed. for (let viewItem of DownloadsView._visibleViewItems.values()) { - viewItem.verifyTargetExists(); + viewItem.download.refresh().catch(Cu.reportError); } if (aAnchor) { @@ -1063,7 +1063,6 @@ function DownloadsViewItem(download, aElement) { this.element.classList.add("download-state"); this._updateState(); - this.verifyTargetExists(); } DownloadsViewItem.prototype = { @@ -1078,41 +1077,11 @@ DownloadsViewItem.prototype = { this.element.setAttribute("image", this.image); this.element.setAttribute("state", DownloadsCommon.stateOfDownload(this.download)); - - if (this.download.succeeded) { - // We assume the existence of the target of a download that just completed - // successfully, without checking the condition in the background. If the - // panel is already open, this will take effect immediately. If the panel - // is opened later, a new background existence check will be performed. - this.element.setAttribute("exists", "true"); - } }, onChanged() { this._updateProgress(); }, - - /** - * Starts checking whether the target file of a finished download is still - * available on disk, and sets an attribute that controls how the item is - * presented visually. - * - * The existence check is executed on a background thread. - */ - verifyTargetExists: function DVI_verifyTargetExists() { - // We don't need to check if the download is not finished successfully. - if (!this.download.succeeded) { - return; - } - - OS.File.exists(this.download.target.path).then(aExists => { - if (aExists) { - this.element.setAttribute("exists", "true"); - } else { - this.element.removeAttribute("exists"); - } - }).catch(Cu.reportError); - }, }; //////////////////////////////////////////////////////////////////////////////// diff --git a/application/palemoon/components/downloads/content/downloadsViewCommon.js b/application/palemoon/components/downloads/content/downloadsViewCommon.js index 999d82317..7ae3eb850 100644 --- a/application/palemoon/components/downloads/content/downloadsViewCommon.js +++ b/application/palemoon/components/downloads/content/downloadsViewCommon.js @@ -142,6 +142,15 @@ DownloadElementShell.prototype = { * namely the progress bar and the status line. */ _updateProgress() { + if (this.download.succeeded) { + // We only need to add or remove this attribute for succeeded downloads. + if (this.download.target.exists) { + this.element.setAttribute("exists", "true"); + } else { + this.element.removeAttribute("exists"); + } + } + // The progress bar is only displayed for in-progress downloads. if (this.download.hasProgress) { this.element.setAttribute("progressmode", "normal"); @@ -182,26 +191,26 @@ DownloadElementShell.prototype = { let tip = ""; if (!this.download.stopped) { - let maxBytes = DownloadsCommon.maxBytesOfDownload(this.download); + let total = this.download.hasProgress ? this.download.totalBytes : -1; // By default, extended status information including the individual // download rate is displayed in the tooltip. The history view overrides // the getter and displays the detials in the main area instead. [text] = DownloadUtils.getDownloadStatusNoRate( this.download.currentBytes, - maxBytes, + total, this.download.speed, this.lastEstimatedSecondsLeft); let newEstimatedSecondsLeft; [tip, newEstimatedSecondsLeft] = DownloadUtils.getDownloadStatus( this.download.currentBytes, - maxBytes, + total, this.download.speed, this.lastEstimatedSecondsLeft); this.lastEstimatedSecondsLeft = newEstimatedSecondsLeft; } else if (this.download.canceled && this.download.hasPartialData) { - let maxBytes = DownloadsCommon.maxBytesOfDownload(this.download); + let total = this.download.hasProgress ? this.download.totalBytes : -1; let transfer = DownloadUtils.getTransferTotal(this.download.currentBytes, - maxBytes); + total); // We use the same XUL label to display both the state and the amount // transferred, for example "Paused - 1.1 MB". @@ -213,12 +222,13 @@ DownloadElementShell.prototype = { let stateLabel; if (this.download.succeeded) { - // For completed downloads, show the file size (e.g. "1.5 MB") - let maxBytes = DownloadsCommon.maxBytesOfDownload(this.download); - if (maxBytes >= 0) { - let [size, unit] = DownloadUtils.convertByteUnits(maxBytes); + // For completed downloads, show the file size (e.g. "1.5 MB"). + if (this.download.target.size !== undefined) { + let [size, unit] = DownloadUtils.convertByteUnits( + this.download.target.size); stateLabel = s.sizeWithUnits(size, unit); } else { + // History downloads may not have a size defined. stateLabel = s.sizeUnknown; } } else if (this.download.canceled) { -- cgit v1.2.3