2009-04-22 07:59:52 -07:00
|
|
|
|
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
|
2012-05-21 04:12:37 -07:00
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2009-04-22 07:59:52 -07:00
|
|
|
|
|
2013-05-03 17:01:52 -07:00
|
|
|
|
"use strict";
|
|
|
|
|
|
2013-11-01 12:06:07 -07:00
|
|
|
|
let Cu = Components.utils;
|
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
|
|
2013-03-15 11:07:04 -07:00
|
|
|
|
function dump(a) {
|
|
|
|
|
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(a);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-01 12:06:07 -07:00
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "Notifications",
|
|
|
|
|
"resource://gre/modules/Notifications.jsm");
|
|
|
|
|
|
2012-05-24 20:41:57 -07:00
|
|
|
|
const URI_GENERIC_ICON_DOWNLOAD = "drawable://alert_download";
|
2013-09-24 13:53:55 -07:00
|
|
|
|
const URI_PAUSE_ICON = "drawable://pause";
|
|
|
|
|
const URI_CANCEL_ICON = "drawable://close";
|
|
|
|
|
const URI_RESUME_ICON = "drawable://play";
|
|
|
|
|
|
2009-04-22 07:59:52 -07:00
|
|
|
|
|
2013-08-27 05:50:22 -07:00
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
|
|
|
|
|
|
2011-10-19 11:17:00 -07:00
|
|
|
|
var Downloads = {
|
2009-06-16 13:15:46 -07:00
|
|
|
|
_initialized: false,
|
2009-04-22 07:59:52 -07:00
|
|
|
|
_dlmgr: null,
|
2010-10-06 11:17:34 -07:00
|
|
|
|
_progressAlert: null,
|
2013-03-15 11:07:04 -07:00
|
|
|
|
_privateDownloads: [],
|
2013-09-24 13:53:55 -07:00
|
|
|
|
_showingPrompt: false,
|
2013-11-01 12:06:07 -07:00
|
|
|
|
_downloadsIdMap: {},
|
2009-04-22 07:59:52 -07:00
|
|
|
|
|
2011-10-19 11:17:00 -07:00
|
|
|
|
_getLocalFile: function dl__getLocalFile(aFileURI) {
|
2009-04-22 07:59:52 -07:00
|
|
|
|
// if this is a URL, get the file from that
|
|
|
|
|
// XXX it's possible that using a null char-set here is bad
|
2010-07-13 07:36:09 -07:00
|
|
|
|
const fileUrl = Services.io.newURI(aFileURI, null, null).QueryInterface(Ci.nsIFileURL);
|
2009-04-22 07:59:52 -07:00
|
|
|
|
return fileUrl.file.clone().QueryInterface(Ci.nsILocalFile);
|
|
|
|
|
},
|
|
|
|
|
|
2011-10-19 11:17:00 -07:00
|
|
|
|
init: function dl_init() {
|
2009-06-16 13:15:46 -07:00
|
|
|
|
if (this._initialized)
|
2009-04-22 07:59:52 -07:00
|
|
|
|
return;
|
2009-06-16 13:15:46 -07:00
|
|
|
|
this._initialized = true;
|
2009-04-22 07:59:52 -07:00
|
|
|
|
|
2009-06-16 13:15:46 -07:00
|
|
|
|
// Monitor downloads and display alerts
|
2012-12-13 16:47:30 -08:00
|
|
|
|
this._dlmgr = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
|
|
|
|
|
this._progressAlert = new AlertDownloadProgressListener();
|
|
|
|
|
this._dlmgr.addPrivacyAwareListener(this._progressAlert);
|
2013-03-15 11:07:04 -07:00
|
|
|
|
Services.obs.addObserver(this, "last-pb-context-exited", true);
|
2009-04-22 07:59:52 -07:00
|
|
|
|
},
|
|
|
|
|
|
2013-05-28 16:31:27 -07:00
|
|
|
|
openDownload: function dl_openDownload(aDownload) {
|
|
|
|
|
let fileUri = aDownload.target.spec;
|
|
|
|
|
let guid = aDownload.guid;
|
|
|
|
|
let f = this._getLocalFile(fileUri);
|
2009-04-22 07:59:52 -07:00
|
|
|
|
try {
|
|
|
|
|
f.launch();
|
2013-08-02 11:04:49 -07:00
|
|
|
|
} catch (ex) {
|
2013-05-28 16:31:27 -07:00
|
|
|
|
// in case we are not able to open the file (i.e. there is no app able to handle it)
|
|
|
|
|
// we just open the browser tab showing it
|
|
|
|
|
BrowserApp.addTab("about:downloads?id=" + guid);
|
|
|
|
|
}
|
2009-04-22 07:59:52 -07:00
|
|
|
|
},
|
|
|
|
|
|
2011-10-19 11:17:00 -07:00
|
|
|
|
cancelDownload: function dl_cancelDownload(aDownload) {
|
2012-12-13 16:47:30 -08:00
|
|
|
|
aDownload.cancel();
|
2011-10-19 11:17:00 -07:00
|
|
|
|
let fileURI = aDownload.target.spec;
|
|
|
|
|
let f = this._getLocalFile(fileURI);
|
2013-08-27 05:50:22 -07:00
|
|
|
|
|
|
|
|
|
OS.File.remove(f.path);
|
2009-04-22 07:59:52 -07:00
|
|
|
|
},
|
|
|
|
|
|
2013-09-24 13:53:55 -07:00
|
|
|
|
showCancelConfirmPrompt: function dl_showCancelConfirmPrompt(aDownload) {
|
|
|
|
|
if (this._showingPrompt)
|
|
|
|
|
return;
|
|
|
|
|
this._showingPrompt = true;
|
|
|
|
|
// Open a prompt that offers a choice to cancel the download
|
|
|
|
|
let title = Strings.browser.GetStringFromName("downloadCancelPromptTitle");
|
|
|
|
|
let message = Strings.browser.GetStringFromName("downloadCancelPromptMessage");
|
|
|
|
|
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_YES +
|
|
|
|
|
Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_NO;
|
|
|
|
|
let choice = Services.prompt.confirmEx(null, title, message, flags,
|
|
|
|
|
null, null, null, null, {});
|
|
|
|
|
if (choice == 0)
|
|
|
|
|
this.cancelDownload(aDownload);
|
|
|
|
|
this._showingPrompt = false;
|
|
|
|
|
},
|
2013-03-15 11:07:04 -07:00
|
|
|
|
|
2013-09-24 13:53:55 -07:00
|
|
|
|
handleClickEvent: function dl_handleClickEvent(aDownload) {
|
|
|
|
|
// Only open the downloaded file if the download is complete
|
|
|
|
|
if (aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_FINISHED)
|
|
|
|
|
this.openDownload(aDownload);
|
|
|
|
|
else if (aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING ||
|
|
|
|
|
aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_PAUSED)
|
|
|
|
|
this.showCancelConfirmPrompt(aDownload);
|
|
|
|
|
},
|
|
|
|
|
|
2013-11-01 12:06:07 -07:00
|
|
|
|
clickCallback: function dl_clickCallback(aDownloadId) {
|
|
|
|
|
this._dlmgr.getDownloadByGUID(aDownloadId, (function(status, download) {
|
|
|
|
|
if (Components.isSuccessCode(status))
|
|
|
|
|
this.handleClickEvent(download);
|
|
|
|
|
}).bind(this));
|
2011-10-19 11:17:00 -07:00
|
|
|
|
},
|
|
|
|
|
|
2013-11-01 12:06:07 -07:00
|
|
|
|
pauseClickCallback: function dl_buttonPauseCallback(aDownloadId) {
|
|
|
|
|
this._dlmgr.getDownloadByGUID(aDownloadId, (function(status, download) {
|
2013-09-24 13:53:55 -07:00
|
|
|
|
if (Components.isSuccessCode(status))
|
2013-11-01 12:06:07 -07:00
|
|
|
|
download.pause();
|
2013-09-24 13:53:55 -07:00
|
|
|
|
}).bind(this));
|
2013-11-01 12:06:07 -07:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
resumeClickCallback: function dl_buttonPauseCallback(aDownloadId) {
|
|
|
|
|
this._dlmgr.getDownloadByGUID(aDownloadId, (function(status, download) {
|
|
|
|
|
if (Components.isSuccessCode(status))
|
|
|
|
|
download.resume();
|
|
|
|
|
}).bind(this));
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
cancelClickCallback: function dl_buttonPauseCallback(aDownloadId) {
|
|
|
|
|
this._dlmgr.getDownloadByGUID(aDownloadId, (function(status, download) {
|
|
|
|
|
if (Components.isSuccessCode(status))
|
|
|
|
|
this.cancelDownload(download);
|
|
|
|
|
}).bind(this));
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
notificationCanceledCallback: function dl_notifCancelCallback(aId, aDownloadId) {
|
|
|
|
|
let notificationId = this._downloadsIdMap[aDownloadId];
|
|
|
|
|
if (notificationId && notificationId == aId)
|
|
|
|
|
delete this._downloadsIdMap[aDownloadId];
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
createNotification: function dl_createNotif(aDownload, aOptions) {
|
|
|
|
|
let notificationId = Notifications.create(aOptions);
|
|
|
|
|
this._downloadsIdMap[aDownload.guid]Â = notificationId;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateNotification: function dl_updateNotif(aDownload, aOptions) {
|
|
|
|
|
let notificationId = this._downloadsIdMap[aDownload.guid];
|
|
|
|
|
if (notificationId)
|
|
|
|
|
Notifications.update(notificationId, aOptions);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
cancelNotification: function dl_cleanNotif(aDownload) {
|
|
|
|
|
Notifications.cancel(this._downloadsIdMap[aDownload.guid]);
|
|
|
|
|
delete this._downloadsIdMap[aDownload.guid];
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// observer for last-pb-context-exited
|
|
|
|
|
observe: function dl_observe(aSubject, aTopic, aData) {
|
|
|
|
|
let download;
|
|
|
|
|
while ((download = this._privateDownloads.pop())) {
|
|
|
|
|
try {
|
|
|
|
|
let notificationId = aDownload.guid;
|
|
|
|
|
Notifications.clear(notificationId);
|
|
|
|
|
Downloads.removeNotification(download);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
dump("Error removing private download: " + e);
|
2013-03-15 11:07:04 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-04-22 07:59:52 -07:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
QueryInterface: function (aIID) {
|
2012-12-13 16:47:30 -08:00
|
|
|
|
if (!aIID.equals(Ci.nsISupports) &&
|
|
|
|
|
!aIID.equals(Ci.nsIObserver) &&
|
|
|
|
|
!aIID.equals(Ci.nsISupportsWeakReference))
|
2009-04-22 07:59:52 -07:00
|
|
|
|
throw Components.results.NS_ERROR_NO_INTERFACE;
|
|
|
|
|
return this;
|
2013-11-01 12:06:07 -07:00
|
|
|
|
}
|
|
|
|
|
};
|
2013-09-24 13:53:55 -07:00
|
|
|
|
|
2013-11-01 12:06:07 -07:00
|
|
|
|
const PAUSE_BUTTON = {
|
|
|
|
|
buttonId: "pause",
|
|
|
|
|
title : Strings.browser.GetStringFromName("alertDownloadsPause"),
|
|
|
|
|
icon : URI_PAUSE_ICON,
|
|
|
|
|
onClicked: function (aId, aCookie) {
|
|
|
|
|
Downloads.pauseClickCallback(aCookie);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const CANCEL_BUTTON = {
|
|
|
|
|
buttonId: "cancel",
|
|
|
|
|
title : Strings.browser.GetStringFromName("alertDownloadsCancel"),
|
|
|
|
|
icon : URI_CANCEL_ICON,
|
|
|
|
|
onClicked: function (aId, aCookie) {
|
|
|
|
|
Downloads.cancelClickCallback(aCookie);
|
|
|
|
|
}
|
|
|
|
|
};
|
2013-09-24 13:53:55 -07:00
|
|
|
|
|
2013-11-01 12:06:07 -07:00
|
|
|
|
const RESUME_BUTTON = {
|
|
|
|
|
buttonId: "resume",
|
|
|
|
|
title : Strings.browser.GetStringFromName("alertDownloadsResume"),
|
|
|
|
|
icon: URI_RESUME_ICON,
|
|
|
|
|
onClicked: function (aId, aCookie) {
|
|
|
|
|
Downloads.resumeClickCallback(aCookie);
|
2009-04-22 07:59:52 -07:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2013-11-01 12:06:07 -07:00
|
|
|
|
function DownloadNotifOptions (aDownload, aTitle, aMessage) {
|
|
|
|
|
this.icon = URI_GENERIC_ICON_DOWNLOAD;
|
|
|
|
|
this.onCancel = function (aId, aCookie) {
|
|
|
|
|
Downloads.notificationCanceledCallback(aId, aCookie);
|
|
|
|
|
}
|
|
|
|
|
this.onClick = function (aId, aCookie) {
|
|
|
|
|
Downloads.clickCallback(aCookie);
|
|
|
|
|
}
|
|
|
|
|
this.title = aTitle;
|
|
|
|
|
this.message = aMessage;
|
|
|
|
|
this.buttons = null;
|
|
|
|
|
this.cookie = aDownload.guid;
|
2013-11-05 22:08:15 -08:00
|
|
|
|
this.persistent = true;
|
2013-11-01 12:06:07 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function DownloadProgressNotifOptions (aDownload, aButtons) {
|
|
|
|
|
DownloadNotifOptions.apply(this, [aDownload, aDownload.displayName, aDownload.percentComplete + "%"]);
|
|
|
|
|
this.ongoing = true;
|
|
|
|
|
this.progress = aDownload.percentComplete;
|
|
|
|
|
this.buttons = aButtons;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-06 11:17:34 -07:00
|
|
|
|
// AlertDownloadProgressListener is used to display progress in the alert notifications.
|
|
|
|
|
function AlertDownloadProgressListener() { }
|
|
|
|
|
|
|
|
|
|
AlertDownloadProgressListener.prototype = {
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//// nsIDownloadProgressListener
|
|
|
|
|
onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress, aDownload) {
|
2011-01-03 12:07:41 -08:00
|
|
|
|
let strings = Strings.browser;
|
2010-11-11 10:48:00 -08:00
|
|
|
|
let availableSpace = -1;
|
|
|
|
|
try {
|
|
|
|
|
// diskSpaceAvailable is not implemented on all systems
|
|
|
|
|
let availableSpace = aDownload.targetFile.diskSpaceAvailable;
|
|
|
|
|
} catch(ex) { }
|
|
|
|
|
let contentLength = aDownload.size;
|
|
|
|
|
if (availableSpace > 0 && contentLength > 0 && contentLength > availableSpace) {
|
2013-11-01 12:06:07 -07:00
|
|
|
|
Downloads.updateNotification(aDownload, new DownloadNotifOptions(aDownload,
|
|
|
|
|
strings.GetStringFromName("alertDownloadsNoSpace"),
|
|
|
|
|
strings.GetStringFromName("alertDownloadsSize")));
|
2012-12-13 16:47:30 -08:00
|
|
|
|
aDownload.cancel();
|
2010-11-11 10:48:00 -08:00
|
|
|
|
}
|
|
|
|
|
|
2010-10-06 11:17:34 -07:00
|
|
|
|
if (aDownload.percentComplete == -1) {
|
|
|
|
|
// Undetermined progress is not supported yet
|
|
|
|
|
return;
|
|
|
|
|
}
|
2013-09-24 13:53:55 -07:00
|
|
|
|
|
2013-11-01 12:06:07 -07:00
|
|
|
|
Downloads.updateNotification(aDownload, new DownloadProgressNotifOptions(aDownload, [PAUSE_BUTTON, CANCEL_BUTTON]));
|
2010-10-06 11:17:34 -07:00
|
|
|
|
},
|
|
|
|
|
|
2010-10-19 12:34:58 -07:00
|
|
|
|
onDownloadStateChange: function(aState, aDownload) {
|
|
|
|
|
let state = aDownload.state;
|
|
|
|
|
switch (state) {
|
2013-11-01 12:06:07 -07:00
|
|
|
|
case Ci.nsIDownloadManager.DOWNLOAD_QUEUED: {
|
2012-12-13 16:47:30 -08:00
|
|
|
|
NativeWindow.toast.show(Strings.browser.GetStringFromName("alertDownloadsToast"), "long");
|
2013-11-01 12:06:07 -07:00
|
|
|
|
Downloads.createNotification(aDownload, new DownloadNotifOptions(aDownload,
|
|
|
|
|
Strings.browser.GetStringFromName("alertDownloadsStart2"),
|
|
|
|
|
aDownload.displayName));
|
2012-12-13 16:47:30 -08:00
|
|
|
|
break;
|
2013-11-01 12:06:07 -07:00
|
|
|
|
}
|
|
|
|
|
case Ci.nsIDownloadManager.DOWNLOAD_PAUSED: {
|
|
|
|
|
Downloads.updateNotification(aDownload, new DownloadProgressNotifOptions(aDownload, [RESUME_BUTTON, CANCEL_BUTTON]));
|
2013-09-24 13:53:55 -07:00
|
|
|
|
break;
|
2013-11-01 12:06:07 -07:00
|
|
|
|
}
|
2010-10-19 12:34:58 -07:00
|
|
|
|
case Ci.nsIDownloadManager.DOWNLOAD_FAILED:
|
|
|
|
|
case Ci.nsIDownloadManager.DOWNLOAD_CANCELED:
|
|
|
|
|
case Ci.nsIDownloadManager.DOWNLOAD_BLOCKED_PARENTAL:
|
|
|
|
|
case Ci.nsIDownloadManager.DOWNLOAD_DIRTY:
|
|
|
|
|
case Ci.nsIDownloadManager.DOWNLOAD_FINISHED: {
|
2013-11-01 12:06:07 -07:00
|
|
|
|
Downloads.cancelNotification(aDownload);
|
2013-03-15 11:07:04 -07:00
|
|
|
|
if (aDownload.isPrivate) {
|
2013-10-17 15:18:35 -07:00
|
|
|
|
let index = Downloads._privateDownloads.indexOf(aDownload);
|
2013-03-15 11:07:04 -07:00
|
|
|
|
if (index != -1) {
|
2013-10-17 15:18:35 -07:00
|
|
|
|
Downloads._privateDownloads.splice(index, 1);
|
2013-03-15 11:07:04 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-07-18 12:12:38 -07:00
|
|
|
|
|
|
|
|
|
if (state == Ci.nsIDownloadManager.DOWNLOAD_FINISHED) {
|
2013-11-01 12:06:07 -07:00
|
|
|
|
Downloads.createNotification(aDownload, new DownloadNotifOptions(aDownload,
|
|
|
|
|
Strings.browser.GetStringFromName("alertDownloadsDone2"),
|
|
|
|
|
aDownload.displayName));
|
2012-12-13 16:47:30 -08:00
|
|
|
|
}
|
2010-10-19 12:34:58 -07:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2010-10-06 11:17:34 -07:00
|
|
|
|
onStateChange: function(aWebProgress, aRequest, aState, aStatus, aDownload) { },
|
|
|
|
|
onSecurityChange: function(aWebProgress, aRequest, aState, aDownload) { },
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//// nsISupports
|
|
|
|
|
QueryInterface: function (aIID) {
|
|
|
|
|
if (!aIID.equals(Ci.nsIDownloadProgressListener) &&
|
|
|
|
|
!aIID.equals(Ci.nsISupports))
|
|
|
|
|
throw Components.results.NS_ERROR_NO_INTERFACE;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
};
|