X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=common%2Fmodules%2Fdownloads.jsm;h=fdf5925b846d5d01853db1de0debec0aad957919;hb=8b6fcae7eaa413bc62d645d2d0c99835c47265e6;hp=faee6e22a7a1ce5a28bcda6019c2e99dc9c05a68;hpb=70740024f9c028c1fd63e1a1850ab062ff956054;p=dactyl.git diff --git a/common/modules/downloads.jsm b/common/modules/downloads.jsm index faee6e2..fdf5925 100644 --- a/common/modules/downloads.jsm +++ b/common/modules/downloads.jsm @@ -1,17 +1,20 @@ -// Copyright (c) 2011 by Kris Maglione +// Copyright (c) 2011-2012 Kris Maglione // // This work is licensed for reuse under an MIT license. Details are // given in the LICENSE.txt file included with this file. "use strict"; -Components.utils.import("resource://dactyl/bootstrap.jsm"); defineModule("downloads", { exports: ["Download", "Downloads", "downloads"], - use: ["io", "messages", "prefs", "services", "util"] -}, this); + require: ["util"] +}); + +lazyRequire("overlay", ["overlay"]); Cu.import("resource://gre/modules/DownloadUtils.jsm", this); +var MAX_LOAD_TIME = 10 * 1000; + let prefix = "DOWNLOAD_"; var states = iter([v, k.slice(prefix.length).toLowerCase()] for ([k, v] in Iterator(Ci.nsIDownloadManager)) @@ -20,41 +23,39 @@ var states = iter([v, k.slice(prefix.length).toLowerCase()] var Download = Class("Download", { init: function init(id, list) { - let self = XPCSafeJSObjectWrapper(services.downloadManager.getDownload(id)); - self.__proto__ = this; - this.instance = this; + let self = this; + this.download = services.downloadManager.getDownload(id); this.list = list; this.nodes = { commandTarget: self }; - util.xmlToDom( - - - - {self.displayName} - {self.targetFile.path} - - - - - {_("download.action.Pause")} - {_("download.action.Remove")} - {_("download.action.Resume")} - {_("download.action.Retry")} - {_("download.action.Cancel")} - {_("download.action.Delete")} - - - / - - - - - {self.source.spec} - , + DOM.fromJSON( + ["tr", { highlight: "Download", key: "row" }, + ["td", { highlight: "DownloadTitle" }, + ["span", { highlight: "Link" }, + ["a", { key: "launch", href: self.target.spec, path: self.targetFile.path }, + self.displayName], + ["span", { highlight: "LinkInfo" }, + self.targetFile.path]]], + ["td", { highlight: "DownloadState", key: "state" }], + ["td", { highlight: "DownloadButtons Buttons" }, + ["a", { highlight: "Button", href: "javascript:0", key: "pause" }, _("download.action.Pause")], + ["a", { highlight: "Button", href: "javascript:0", key: "remove" }, _("download.action.Remove")], + ["a", { highlight: "Button", href: "javascript:0", key: "resume" }, _("download.action.Resume")], + ["a", { highlight: "Button", href: "javascript:0", key: "retry" }, _("download.action.Retry")], + ["a", { highlight: "Button", href: "javascript:0", key: "cancel" }, _("download.action.Cancel")], + ["a", { highlight: "Button", href: "javascript:0", key: "delete" }, _("download.action.Delete")]], + ["td", { highlight: "DownloadProgress", key: "progress" }, + ["span", { highlight: "DownloadProgressHave", key: "progressHave" }], + "/", + ["span", { highlight: "DownloadProgressTotal", key: "progressTotal" }]],, + ["td", { highlight: "DownloadPercent", key: "percent" }], + ["td", { highlight: "DownloadSpeed", key: "speed" }], + ["td", { highlight: "DownloadTime", key: "time" }], + ["td", {}, + ["a", { highlight: "DownloadSource", key: "source", href: self.source.spec }, + self.source.spec]]], this.list.document, this.nodes); this.nodes.launch.addEventListener("click", function (event) { @@ -74,7 +75,7 @@ var Download = Class("Download", { get alive() this.inState(["downloading", "notstarted", "paused", "queued", "scanning"]), - allowedCommands: Class.memoize(function () let (self = this) ({ + allowedCommands: Class.Memoize(function () let (self = this) ({ get cancel() self.cancelable && self.inState(["downloading", "paused", "starting"]), get delete() !this.cancel && self.targetFile.exists(), get launch() self.targetFile.exists() && self.inState(["finished"]), @@ -106,7 +107,7 @@ var Download = Class("Download", { function action() { try { if (this.MIMEInfo && this.MIMEInfo.preferredAction == this.MIMEInfo.useHelperApp) - this.MIMEInfo.launchWithFile(file); + this.MIMEInfo.launchWithFile(file.file); else file.launch(); } @@ -172,7 +173,8 @@ var Download = Class("Download", { } } - let total = this.nodes.progressTotal.textContent = this.size ? util.formatBytes(this.size, 1, true) : _("download.unknown"); + let total = this.nodes.progressTotal.textContent = this.size || !this.nActive ? util.formatBytes(this.size, 1, true) + : _("download.unknown"); let suffix = RegExp(/( [a-z]+)?$/i.exec(total)[0] + "$"); this.nodes.progressHave.textContent = util.formatBytes(this.amountTransferred, 1, true).replace(suffix, ""); @@ -193,6 +195,14 @@ var Download = Class("Download", { this.updateProgress(); } }); +Object.keys(XPCOMShim([Ci.nsIDownload])).forEach(function (key) { + if (!(key in Download.prototype)) + Object.defineProperty(Download.prototype, key, { + get: function get() this.download[key], + set: function set(val) this.download[key] = val, + configurable: true + }); +}); var DownloadList = Class("DownloadList", XPCOM([Ci.nsIDownloadProgressListener, @@ -213,40 +223,52 @@ var DownloadList = Class("DownloadList", services.downloadManager.removeListener(this); }, - message: Class.memoize(function () { - - util.xmlToDom( - - {_("title.Title")} - {_("title.Status")} - - {_("title.Progress")} - - {_("title.Speed")} - {_("title.Time remaining")} - {_("title.Source")} - -
- - - - - -
{_("title.Totals")}:  - - {_("download.action.Clear")} - - / - - - - -
, this.document, this.nodes); - + message: Class.Memoize(function () { + + DOM.fromJSON(["table", { highlight: "Downloads", key: "list" }, + ["tr", { highlight: "DownloadHead", key: "head" }, + ["span", {}, _("title.Title")], + ["span", {}, _("title.Status")], + ["span"], + ["span", {}, _("title.Progress")], + ["span"], + ["span", {}, _("title.Speed")], + ["span", {}, _("title.Time remaining")], + ["span", {}, _("title.Source")]], + ["tr", { highlight: "Download" }, + ["span", {}, + ["div", { style: "min-height: 1ex; /* FIXME */" }]]], + ["tr", { highlight: "Download", key: "totals", active: "true" }, + ["td", {}, + ["span", { highlight: "Title" }, + _("title.Totals") + ":"], + " ", + ["span", { key: "total" }]], + ["td"], + ["td", { highlight: "DownloadButtons" }, + ["a", { highlight: "Button", href: "javascript:0", key: "clear" }, _("download.action.Clear")]], + ["td", { highlight: "DownloadProgress", key: "progress" }, + ["span", { highlight: "DownloadProgressHave", key: "progressHave" }], + "/", + ["span", { highlight: "DownloadProgressTotal", key: "progressTotal" }]], + ["td", { highlight: "DownloadPercent", key: "percent" }], + ["td", { highlight: "DownloadSpeed", key: "speed" }], + ["td", { highlight: "DownloadTime", key: "time" }], + ["td"]]], + this.document, this.nodes); + + this.index = Array.indexOf(this.nodes.list.childNodes, + this.nodes.head); + + let start = Date.now(); for (let row in iter(services.downloadManager.DBConnection - .createStatement("SELECT id FROM moz_downloads"))) + .createStatement("SELECT id FROM moz_downloads"))) { + if (Date.now() - start > MAX_LOAD_TIME) { + util.dactyl.warn(_("download.givingUpAfter", (Date.now() - start) / 1000)); + break; + } this.addDownload(row.id); + } this.update(); util.addObserver(this); @@ -265,7 +287,7 @@ var DownloadList = Class("DownloadList", .indexOf(download); this.nodes.list.insertBefore(download.nodes.row, - this.nodes.list.childNodes[index + 1]); + this.nodes.list.childNodes[index + this.index + 1]); } }, removeDownload: function removeDownload(id) { @@ -280,7 +302,7 @@ var DownloadList = Class("DownloadList", this.cleanup(); }, - allowedCommands: Class.memoize(function () let (self = this) ({ + allowedCommands: Class.Memoize(function () let (self = this) ({ get clear() values(self.downloads).some(function (dl) dl.allowedCommands.remove) })), @@ -316,16 +338,17 @@ var DownloadList = Class("DownloadList", updateProgress: function updateProgress() { let downloads = values(this.downloads).toArray(); + let active = downloads.filter(function (d) d.alive); let self = Object.create(this); for (let prop in values(["amountTransferred", "size", "speed", "timeRemaining"])) - this[prop] = downloads.reduce(function (acc, dl) dl[prop] + acc, 0); + this[prop] = active.reduce(function (acc, dl) dl[prop] + acc, 0); Download.prototype.updateProgress.call(self); - let active = downloads.filter(function (dl) dl.alive).length; - if (active) - this.nodes.total.textContent = _("download.nActive", active); + this.nActive = active.length; + if (active.length) + this.nodes.total.textContent = _("download.nActive", active.length); else for (let key in values(["total", "percent", "speed", "time"])) this.nodes[key].textContent = ""; @@ -380,7 +403,30 @@ var DownloadList = Class("DownloadList", } }); -var Downloads = Module("downloads", { +var Downloads = Module("downloads", XPCOM(Ci.nsIDownloadProgressListener), { + init: function () { + services.downloadManager.addListener(this); + }, + + cleanup: function destroy() { + services.downloadManager.removeListener(this); + }, + + onDownloadStateChange: function (state, download) { + if (download.state == services.downloadManager.DOWNLOAD_FINISHED) { + let url = download.source.spec; + let title = download.displayName; + let file = download.targetFile.path; + let size = download.size; + + + overlay.modules.forEach(function (modules) { + modules.dactyl.echomsg({ domains: [util.getHost(url)], message: _("io.downloadFinished", title, file) }, + 1, modules.commandline.ACTIVE_WINDOW); + modules.autocommands.trigger("DownloadPost", { url: url, title: title, file: file, size: size }); + }); + } + } }, { }, { commands: function initCommands(dactyl, modules, window) {