michael@0: // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: const URI_GENERIC_ICON_DOWNLOAD = "chrome://browser/skin/images/alert-downloads-30.png"; michael@0: michael@0: var MetroDownloadsView = { michael@0: /** michael@0: * _downloadCount keeps track of the number of downloads that a single michael@0: * notification bar groups together. A download is grouped with other michael@0: * downloads if it starts before other downloads have completed. michael@0: */ michael@0: _downloadCount: 0, michael@0: _downloadsInProgress: 0, michael@0: _lastDownload: null, michael@0: _inited: false, michael@0: _progressAlert: null, michael@0: _lastSec: Infinity, michael@0: michael@0: _progressNotificationInfo: new Map(), michael@0: _runDownloadBooleanMap: new Map(), michael@0: michael@0: get manager() { michael@0: return Cc["@mozilla.org/download-manager;1"] michael@0: .getService(Ci.nsIDownloadManager); michael@0: }, michael@0: michael@0: _getReferrerOrSource: function dh__getReferrerOrSource(aDownload) { michael@0: return aDownload.referrer.spec || aDownload.source.spec; michael@0: }, michael@0: michael@0: _getLocalFile: function dh__getLocalFile(aFileURI) { michael@0: // XXX it's possible that using a null char-set here is bad michael@0: let spec = ('string' == typeof aFileURI) ? aFileURI : aFileURI.spec; michael@0: let fileUrl; michael@0: try { michael@0: fileUrl = Services.io.newURI(spec, null, null).QueryInterface(Ci.nsIFileURL); michael@0: } catch (ex) { michael@0: Util.dumpLn("_getLocalFile: Caught exception creating newURI from file spec: "+aFileURI.spec+": " + ex.message); michael@0: return; michael@0: } michael@0: return fileUrl.file.clone().QueryInterface(Ci.nsILocalFile); michael@0: }, michael@0: michael@0: init: function dh_init() { michael@0: if (this._inited) michael@0: return; michael@0: michael@0: this._inited = true; michael@0: michael@0: Services.obs.addObserver(this, "dl-start", true); michael@0: Services.obs.addObserver(this, "dl-done", true); michael@0: Services.obs.addObserver(this, "dl-run", true); michael@0: Services.obs.addObserver(this, "dl-failed", true); michael@0: michael@0: michael@0: this._progress = new DownloadProgressListener(this); michael@0: this.manager.addListener(this._progress); michael@0: michael@0: Elements.tabList.addEventListener("TabClose", this, false); michael@0: michael@0: this._downloadProgressIndicator = document.getElementById("download-progress"); michael@0: michael@0: if (this.manager.activeDownloadCount) { michael@0: setTimeout (this._restartWithActiveDownloads.bind(this), 0); michael@0: } michael@0: }, michael@0: michael@0: uninit: function dh_uninit() { michael@0: if (this._inited) { michael@0: Services.obs.removeObserver(this, "dl-start"); michael@0: Services.obs.removeObserver(this, "dl-done"); michael@0: Services.obs.removeObserver(this, "dl-run"); michael@0: Services.obs.removeObserver(this, "dl-failed"); michael@0: if (Elements && Elements.tabList) michael@0: Elements.tabList.removeEventListener("TabClose", this); michael@0: } michael@0: }, michael@0: michael@0: get _notificationBox() { michael@0: return Browser.getNotificationBox(Browser.selectedBrowser); michael@0: }, michael@0: michael@0: get _notificationBoxes() { michael@0: let currentBox = this._notificationBox; michael@0: let boxes = [ michael@0: currentBox michael@0: ]; michael@0: for (let { linkedBrowser } of Elements.tabList.children) { michael@0: if (linkedBrowser !== Browser.selectedBrowser) { michael@0: let notificationBox = Browser.getNotificationBox(linkedBrowser); michael@0: if (notificationBox) michael@0: boxes.push(notificationBox); michael@0: } michael@0: } michael@0: return boxes; michael@0: }, michael@0: michael@0: get _progressNotification() { michael@0: let notn = this._getNotificationWithValue("download-progress"); michael@0: let currentBox = this._notificationBox; michael@0: // move the progress notification if attached to a different browser michael@0: if (notn && notn.parentNode !== currentBox) { michael@0: notn.parentNode.removeNotification(notn); michael@0: currentBox.insertBefore(notn, currentBox.firstChild); michael@0: } michael@0: return notn; michael@0: }, michael@0: michael@0: _getNotificationWithValue: function(aValue) { michael@0: let notn; michael@0: let allNotificationBoxes = this._notificationBoxes; michael@0: for(let box of allNotificationBoxes) { michael@0: notn = box.getNotificationWithValue(aValue); michael@0: if (notn) { michael@0: break; michael@0: } michael@0: } michael@0: return notn; michael@0: }, michael@0: michael@0: _restartWithActiveDownloads: function() { michael@0: let activeDownloads = this.manager.activeDownloads; michael@0: michael@0: while (activeDownloads.hasMoreElements()) { michael@0: let dl = activeDownloads.getNext(); michael@0: switch (dl.state) { michael@0: case 0: // Downloading michael@0: case 5: // Queued michael@0: this.watchDownload(dl); michael@0: this.updateInfobar(); michael@0: break; michael@0: } michael@0: } michael@0: if (this.manager.activeDownloadCount) { michael@0: ContextUI.displayNavbar(); michael@0: } michael@0: }, michael@0: michael@0: openDownload: function dh_openDownload(aDownload) { michael@0: let fileURI = aDownload.target michael@0: michael@0: if (!(fileURI && fileURI.spec)) { michael@0: Util.dumpLn("Cant open download "+id+", fileURI is invalid"); michael@0: return; michael@0: } michael@0: michael@0: let file = this._getLocalFile(fileURI); michael@0: try { michael@0: file && Services.metro.launchInDesktop(aDownload.target.spec, ""); michael@0: } catch (ex) { michael@0: Util.dumpLn("Failed to open download, with id: "+id+", download target URI spec: " + fileURI.spec); michael@0: Util.dumpLn("Failed download source:"+(aDownload.source && aDownload.source.spec)); michael@0: } michael@0: }, michael@0: michael@0: removeDownload: function dh_removeDownload(aDownload) { michael@0: // aDownload is the XUL element here, michael@0: // and .target currently returns the target attribute (string value) michael@0: let id = aDownload.getAttribute("downloadId"); michael@0: let download = this.manager.getDownload(id); michael@0: michael@0: if (download) { michael@0: this.manager.removeDownload(id); michael@0: } michael@0: }, michael@0: michael@0: cancelDownload: function dh_cancelDownload(aDownload) { michael@0: let fileURI = aDownload.target; michael@0: if (!(fileURI && fileURI.spec)) { michael@0: Util.dumpLn("Cant remove download file for: "+aDownload.id+", fileURI is invalid"); michael@0: } michael@0: michael@0: try { michael@0: let file = this._getLocalFile(fileURI); michael@0: if (file && file.exists()) michael@0: file.remove(false); michael@0: this.manager.cancelDownload(aDownload.id); michael@0: michael@0: // If cancelling was successful, stop tracking the download. michael@0: this._progressNotificationInfo.delete(aDownload.guid); michael@0: this._runDownloadBooleanMap.delete(aDownload.targetFile.path); michael@0: this._downloadCount--; michael@0: this._downloadsInProgress--; michael@0: let notn = this._progressNotification; michael@0: if (notn && this._downloadsInProgress <= 0) { michael@0: this._notificationBox.removeNotification(notn); michael@0: } michael@0: } catch (ex) { michael@0: Util.dumpLn("Failed to cancel download, with id: "+aDownload.id+", download target URI spec: " + fileURI.spec); michael@0: Util.dumpLn("Failed download source:"+(aDownload.source && aDownload.source.spec)); michael@0: } michael@0: }, michael@0: michael@0: // Cancels all downloads. michael@0: cancelDownloads: function dh_cancelDownloads() { michael@0: for (let [guid, info] of this._progressNotificationInfo) { michael@0: this.cancelDownload(info.download); michael@0: } michael@0: this._downloadCount = 0; michael@0: this._progressNotificationInfo.clear(); michael@0: this._runDownloadBooleanMap.clear(); michael@0: }, michael@0: michael@0: pauseDownload: function dh_pauseDownload(aDownload) { michael@0: let id = aDownload.getAttribute("downloadId"); michael@0: this.manager.pauseDownload(id); michael@0: }, michael@0: michael@0: resumeDownload: function dh_resumeDownload(aDownload) { michael@0: let id = aDownload.getAttribute("downloadId"); michael@0: this.manager.resumeDownload(id); michael@0: }, michael@0: michael@0: showPage: function dh_showPage(aDownload) { michael@0: let id = aDownload.getAttribute("downloadId"); michael@0: let download = this.manager.getDownload(id); michael@0: let uri = this._getReferrerOrSource(download); michael@0: if (uri) michael@0: BrowserUI.addAndShowTab(uri, Browser.selectedTab); michael@0: }, michael@0: michael@0: showAlert: function dh_showAlert(aName, aMessage, aTitle, aObserver) { michael@0: var notifier = Cc["@mozilla.org/alerts-service;1"] michael@0: .getService(Ci.nsIAlertsService); michael@0: michael@0: if (!aTitle) michael@0: aTitle = Strings.browser.GetStringFromName("alertDownloads"); michael@0: michael@0: notifier.showAlertNotification("", aTitle, aMessage, true, "", aObserver, aName); michael@0: }, michael@0: michael@0: showNotification: function dh_showNotification(title, msg, buttons, priority) { michael@0: let notification = this._notificationBox.appendNotification(msg, michael@0: title, michael@0: URI_GENERIC_ICON_DOWNLOAD, michael@0: priority, michael@0: buttons); michael@0: return notification; michael@0: }, michael@0: michael@0: _showDownloadFailedNotification: function (aDownload) { michael@0: let tryAgainButtonText = michael@0: Strings.browser.GetStringFromName("downloadTryAgain"); michael@0: let cancelButtonText = michael@0: Strings.browser.GetStringFromName("downloadCancel"); michael@0: michael@0: let message = Strings.browser.formatStringFromName("alertDownloadFailed", michael@0: [aDownload.displayName], 1); michael@0: michael@0: let buttons = [ michael@0: { michael@0: isDefault: true, michael@0: label: tryAgainButtonText, michael@0: accessKey: "", michael@0: callback: function() { michael@0: MetroDownloadsView.manager.retryDownload(aDownload.id); michael@0: } michael@0: }, michael@0: { michael@0: label: cancelButtonText, michael@0: accessKey: "", michael@0: callback: function() { michael@0: MetroDownloadsView.cancelDownload(aDownload); michael@0: MetroDownloadsView._downloadProgressIndicator.reset(); michael@0: } michael@0: } michael@0: ]; michael@0: this.showNotification("download-failed", message, buttons, michael@0: this._notificationBox.PRIORITY_WARNING_HIGH); michael@0: }, michael@0: michael@0: _showDownloadCompleteNotification: function () { michael@0: let message = ""; michael@0: let showInFilesButtonText = Strings.browser.GetStringFromName("downloadShowInFiles"); michael@0: michael@0: let buttons = [ michael@0: { michael@0: label: showInFilesButtonText, michael@0: accessKey: "", michael@0: callback: function() { michael@0: let fileURI = MetroDownloadsView._lastDownload.target; michael@0: let file = MetroDownloadsView._getLocalFile(fileURI); michael@0: file.reveal(); michael@0: MetroDownloadsView._resetCompletedDownloads(); michael@0: } michael@0: } michael@0: ]; michael@0: michael@0: if (this._downloadCount > 1) { michael@0: message = PluralForm.get(this._downloadCount, michael@0: Strings.browser.GetStringFromName("alertMultipleDownloadsComplete")) michael@0: .replace("#1", this._downloadCount) michael@0: } else { michael@0: let runButtonText = michael@0: Strings.browser.GetStringFromName("downloadOpen"); michael@0: message = Strings.browser.formatStringFromName("alertDownloadsDone2", michael@0: [this._lastDownload.displayName], 1); michael@0: michael@0: buttons.unshift({ michael@0: isDefault: true, michael@0: label: runButtonText, michael@0: accessKey: "", michael@0: callback: function() { michael@0: MetroDownloadsView.openDownload(MetroDownloadsView._lastDownload); michael@0: MetroDownloadsView._resetCompletedDownloads(); michael@0: } michael@0: }); michael@0: } michael@0: this._removeNotification("download-complete"); michael@0: this.showNotification("download-complete", message, buttons, michael@0: this._notificationBox.PRIORITY_WARNING_MEDIUM); michael@0: }, michael@0: michael@0: _showDownloadCompleteToast: function () { michael@0: let name = "DownloadComplete"; michael@0: let msg = ""; michael@0: let title = ""; michael@0: let observer = null; michael@0: if (this._downloadCount > 1) { michael@0: title = PluralForm.get(this._downloadCount, michael@0: Strings.browser.GetStringFromName("alertMultipleDownloadsComplete")) michael@0: .replace("#1", this._downloadCount) michael@0: msg = PluralForm.get(2, Strings.browser.GetStringFromName("downloadShowInFiles")); michael@0: michael@0: observer = { michael@0: observe: function (aSubject, aTopic, aData) { michael@0: switch (aTopic) { michael@0: case "alertclickcallback": michael@0: let fileURI = MetroDownloadsView._lastDownload.target; michael@0: let file = MetroDownloadsView._getLocalFile(fileURI); michael@0: file.reveal(); michael@0: MetroDownloadsView._resetCompletedDownloads(); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: } else { michael@0: title = Strings.browser.formatStringFromName("alertDownloadsDone", michael@0: [this._lastDownload.displayName], 1); michael@0: msg = Strings.browser.GetStringFromName("downloadOpenNow"); michael@0: observer = { michael@0: observe: function (aSubject, aTopic, aData) { michael@0: switch (aTopic) { michael@0: case "alertclickcallback": michael@0: MetroDownloadsView.openDownload(MetroDownloadsView._lastDownload); michael@0: MetroDownloadsView._resetCompletedDownloads(); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: this.showAlert(name, msg, title, observer); michael@0: }, michael@0: michael@0: _resetCompletedDownloads: function () { michael@0: this._progressNotificationInfo.clear(); michael@0: this._downloadCount = 0; michael@0: this._lastDownload = null; michael@0: this._downloadProgressIndicator.reset(); michael@0: this._removeNotification("download-complete"); michael@0: }, michael@0: michael@0: _updateCircularProgressMeter: function dv_updateCircularProgressMeter() { michael@0: if (!this._progressNotificationInfo) { michael@0: return; michael@0: } michael@0: michael@0: let totPercent = 0; michael@0: for (let [guid, info] of this._progressNotificationInfo) { michael@0: // info.download => nsIDownload michael@0: totPercent += info.download.percentComplete; michael@0: } michael@0: michael@0: let percentComplete = totPercent / this._progressNotificationInfo.size; michael@0: this._downloadProgressIndicator.updateProgress(percentComplete); michael@0: }, michael@0: michael@0: _computeDownloadProgressString: function dv_computeDownloadProgressString() { michael@0: let totTransferred = 0, totSize = 0, totSecondsLeft = 0; michael@0: let guid, info; michael@0: for ([guid, info] of this._progressNotificationInfo) { michael@0: let size = info.download.size; michael@0: let amountTransferred = info.download.amountTransferred; michael@0: let speed = info.download.speed; michael@0: michael@0: totTransferred += amountTransferred; michael@0: totSize += size; michael@0: totSecondsLeft += ((size - amountTransferred) / speed); michael@0: } michael@0: michael@0: // Compute progress in bytes. michael@0: let amountTransferred = Util.getDownloadSize(totTransferred); michael@0: let size = Util.getDownloadSize(totSize); michael@0: let progress = amountTransferred + "/" + size; michael@0: michael@0: // Compute progress in time.; michael@0: let [timeLeft, newLast] = DownloadUtils.getTimeLeft(totSecondsLeft, this._lastSec); michael@0: this._lastSec = newLast; michael@0: michael@0: if (this._downloadCount == 1) { michael@0: return Strings.browser.GetStringFromName("alertDownloadsStart2") michael@0: .replace("#1", info.download.displayName) michael@0: .replace("#2", progress) michael@0: .replace("#3", timeLeft) michael@0: } michael@0: michael@0: let numDownloads = this._downloadCount; michael@0: return PluralForm.get(numDownloads, michael@0: Strings.browser.GetStringFromName("alertDownloadMultiple")) michael@0: .replace("#1", numDownloads) michael@0: .replace("#2", progress) michael@0: .replace("#3", timeLeft); michael@0: }, michael@0: michael@0: _saveDownloadData: function dv_saveDownloadData(aDownload) { michael@0: if (!this._progressNotificationInfo.get(aDownload.guid)) { michael@0: this._progressNotificationInfo.set(aDownload.guid, {}); michael@0: } michael@0: let infoObj = this._progressNotificationInfo.get(aDownload.guid); michael@0: infoObj.download = aDownload; michael@0: this._progressNotificationInfo.set(aDownload.guid, infoObj); michael@0: }, michael@0: michael@0: onDownloadButton: function dv_onDownloadButton() { michael@0: let progressNotification = this._getNotificationWithValue("download-progress"); michael@0: let wasProgressVisible = (progressNotification && michael@0: progressNotification.parentNode == this._notificationBox); michael@0: let completeNotification = this._getNotificationWithValue("download-complete"); michael@0: let wasCompleteVisible = (completeNotification && michael@0: completeNotification.parentNode == this._notificationBox); michael@0: michael@0: this._removeNotification("download-complete"); michael@0: this._removeNotification("download-progress"); michael@0: michael@0: if (this._downloadsInProgress && !wasProgressVisible) { michael@0: this.updateInfobar(); michael@0: } else if (this._downloadCount && !wasCompleteVisible) { michael@0: this._showDownloadCompleteNotification(); michael@0: } michael@0: }, michael@0: michael@0: _removeNotification: function (aValue) { michael@0: let notification = this._getNotificationWithValue(aValue); michael@0: return notification && michael@0: notification.parentNode.removeNotification(notification); michael@0: }, michael@0: michael@0: updateInfobar: function dv_updateInfobar() { michael@0: let message = this._computeDownloadProgressString(); michael@0: this._updateCircularProgressMeter(); michael@0: michael@0: let notn = this._progressNotification; michael@0: if (!notn) { michael@0: let cancelButtonText = michael@0: Strings.browser.GetStringFromName("downloadCancel"); michael@0: michael@0: let buttons = [ michael@0: { michael@0: isDefault: false, michael@0: label: cancelButtonText, michael@0: accessKey: "", michael@0: callback: function() { michael@0: MetroDownloadsView.cancelDownloads(); michael@0: MetroDownloadsView._downloadProgressIndicator.reset(); michael@0: } michael@0: } michael@0: ]; michael@0: michael@0: notn = this.showNotification("download-progress", message, buttons, michael@0: this._notificationBox.PRIORITY_WARNING_LOW); michael@0: michael@0: ContextUI.displayNavbar(); michael@0: } else { michael@0: notn.label = message; michael@0: } michael@0: }, michael@0: michael@0: updateDownload: function dv_updateDownload(aDownload) { michael@0: this._saveDownloadData(aDownload); michael@0: let notn = this._progressNotification; michael@0: if (notn) { michael@0: notn.label = michael@0: this._computeDownloadProgressString(aDownload); michael@0: } michael@0: this._updateCircularProgressMeter(); michael@0: }, michael@0: michael@0: watchDownload: function dv_watchDownload(aDownload) { michael@0: this._saveDownloadData(aDownload); michael@0: this._downloadCount++; michael@0: this._downloadsInProgress++; michael@0: if (!this._progressNotificationInfo.get(aDownload.guid)) { michael@0: this._progressNotificationInfo.set(aDownload.guid, {}); michael@0: } michael@0: if (!this._progressAlert) { michael@0: this._progressAlert = new AlertDownloadProgressListener(); michael@0: this.manager.addListener(this._progressAlert); michael@0: } michael@0: }, michael@0: michael@0: observe: function (aSubject, aTopic, aData) { michael@0: let message = ""; michael@0: let msgTitle = ""; michael@0: michael@0: switch (aTopic) { michael@0: case "dl-run": michael@0: let file = aSubject.QueryInterface(Ci.nsIFile); michael@0: this._runDownloadBooleanMap.set(file.path, (aData == 'true')); michael@0: break; michael@0: case "dl-start": michael@0: let download = aSubject.QueryInterface(Ci.nsIDownload); michael@0: this.watchDownload(download); michael@0: this.updateInfobar(); michael@0: break; michael@0: case "dl-done": michael@0: this._downloadsInProgress--; michael@0: download = aSubject.QueryInterface(Ci.nsIDownload); michael@0: this._lastDownload = download; michael@0: let runAfterDownload = this._runDownloadBooleanMap.get(download.targetFile.path); michael@0: if (runAfterDownload) { michael@0: this.openDownload(download); michael@0: } michael@0: michael@0: this._runDownloadBooleanMap.delete(download.targetFile.path); michael@0: if (this._downloadsInProgress == 0) { michael@0: if (this._downloadCount > 1 || !runAfterDownload) { michael@0: this._showDownloadCompleteToast(); michael@0: this._showDownloadCompleteNotification(); michael@0: } michael@0: let notn = this._progressNotification; michael@0: if (notn) michael@0: this._notificationBox.removeNotification(notn); michael@0: michael@0: ContextUI.displayNavbar(); michael@0: } michael@0: michael@0: this._downloadProgressIndicator.notify(); michael@0: break; michael@0: case "dl-failed": michael@0: download = aSubject.QueryInterface(Ci.nsIDownload); michael@0: this._showDownloadFailedNotification(download); michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: handleEvent: function(aEvent) { michael@0: switch (aEvent.type) { michael@0: case 'TabClose': { michael@0: let browser = aEvent.originalTarget.linkedBrowser; michael@0: let tab = Browser.getTabForBrowser(browser); michael@0: let notificationBox = Browser.getNotificationBox(browser); michael@0: michael@0: // move any download-related notification before the tab and its notificationBox goes away michael@0: // The 3 possible values should be mutually exclusive michael@0: for(let name of ["download-progress", michael@0: "save-download", michael@0: "download-complete"]) { michael@0: let notn = notificationBox.getNotificationWithValue(name); michael@0: if (!notn) { michael@0: continue; michael@0: } michael@0: michael@0: let nextTab = Browser.getNextTab(tab); michael@0: let nextBox = nextTab && Browser.getNotificationBox(nextTab.browser); michael@0: if (nextBox) { michael@0: // move notification to the next tab michael@0: nextBox.adoptNotification(notn); michael@0: } else { michael@0: // Alas, no browser to move the notifications to. michael@0: } michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: }, michael@0: michael@0: QueryInterface: function (aIID) { michael@0: if (!aIID.equals(Ci.nsIObserver) && michael@0: !aIID.equals(Ci.nsISupportsWeakReference) && michael@0: !aIID.equals(Ci.nsISupports)) michael@0: throw Components.results.NS_ERROR_NO_INTERFACE; michael@0: return this; michael@0: } michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Notifies Downloads object about updates in the state of various downloads. michael@0: * michael@0: * @param aDownloads An instance of Downloads. michael@0: */ michael@0: function DownloadProgressListener(aDownloads) { michael@0: this._downloads = aDownloads; michael@0: } michael@0: michael@0: DownloadProgressListener.prototype = { michael@0: _downloads: null, michael@0: michael@0: ////////////////////////////////////////////////////////////////////////////// michael@0: //// nsIDownloadProgressListener michael@0: onDownloadStateChange: function dPL_onDownloadStateChange(aState, aDownload) { michael@0: // TODO: Use DownloadProgressListener instead of observers in the Downloads object. michael@0: this._downloads.updateDownload(aDownload); michael@0: }, michael@0: michael@0: onProgressChange: function dPL_onProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress, aDownload) { michael@0: // TODO : Add more detailed progress information. michael@0: this._downloads.updateDownload(aDownload); michael@0: }, michael@0: michael@0: onStateChange: function(aWebProgress, aRequest, aState, aStatus, aDownload) { }, michael@0: onSecurityChange: function(aWebProgress, aRequest, aState, aDownload) { }, michael@0: michael@0: ////////////////////////////////////////////////////////////////////////////// michael@0: //// nsISupports michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadProgressListener]) michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Tracks download progress so that additional information can be displayed michael@0: * about its download in alert popups. michael@0: */ michael@0: function AlertDownloadProgressListener() { } michael@0: michael@0: AlertDownloadProgressListener.prototype = { michael@0: ////////////////////////////////////////////////////////////////////////////// michael@0: //// nsIDownloadProgressListener michael@0: onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress, aDownload) { michael@0: let strings = Strings.browser; michael@0: let availableSpace = -1; michael@0: michael@0: try { michael@0: // diskSpaceAvailable is not implemented on all systems michael@0: let availableSpace = aDownload.targetFile.diskSpaceAvailable; michael@0: } catch(ex) { } michael@0: michael@0: let contentLength = aDownload.size; michael@0: if (availableSpace > 0 && contentLength > 0 && contentLength > availableSpace) { michael@0: MetroDownloadsView.showAlert(aDownload.target.spec.replace("file:", "download:"), michael@0: strings.GetStringFromName("alertDownloadsNoSpace"), michael@0: strings.GetStringFromName("alertDownloadsSize")); michael@0: MetroDownloadsView.cancelDownload(aDownload); michael@0: } michael@0: }, michael@0: michael@0: onDownloadStateChange: function(aState, aDownload) { }, michael@0: onStateChange: function(aWebProgress, aRequest, aState, aStatus, aDownload) { }, michael@0: onSecurityChange: function(aWebProgress, aRequest, aState, aDownload) { }, michael@0: michael@0: ////////////////////////////////////////////////////////////////////////////// michael@0: //// nsISupports michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadProgressListener]) michael@0: };