browser/metro/base/content/downloads.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 const URI_GENERIC_ICON_DOWNLOAD = "chrome://browser/skin/images/alert-downloads-30.png";
michael@0 7
michael@0 8 var MetroDownloadsView = {
michael@0 9 /**
michael@0 10 * _downloadCount keeps track of the number of downloads that a single
michael@0 11 * notification bar groups together. A download is grouped with other
michael@0 12 * downloads if it starts before other downloads have completed.
michael@0 13 */
michael@0 14 _downloadCount: 0,
michael@0 15 _downloadsInProgress: 0,
michael@0 16 _lastDownload: null,
michael@0 17 _inited: false,
michael@0 18 _progressAlert: null,
michael@0 19 _lastSec: Infinity,
michael@0 20
michael@0 21 _progressNotificationInfo: new Map(),
michael@0 22 _runDownloadBooleanMap: new Map(),
michael@0 23
michael@0 24 get manager() {
michael@0 25 return Cc["@mozilla.org/download-manager;1"]
michael@0 26 .getService(Ci.nsIDownloadManager);
michael@0 27 },
michael@0 28
michael@0 29 _getReferrerOrSource: function dh__getReferrerOrSource(aDownload) {
michael@0 30 return aDownload.referrer.spec || aDownload.source.spec;
michael@0 31 },
michael@0 32
michael@0 33 _getLocalFile: function dh__getLocalFile(aFileURI) {
michael@0 34 // XXX it's possible that using a null char-set here is bad
michael@0 35 let spec = ('string' == typeof aFileURI) ? aFileURI : aFileURI.spec;
michael@0 36 let fileUrl;
michael@0 37 try {
michael@0 38 fileUrl = Services.io.newURI(spec, null, null).QueryInterface(Ci.nsIFileURL);
michael@0 39 } catch (ex) {
michael@0 40 Util.dumpLn("_getLocalFile: Caught exception creating newURI from file spec: "+aFileURI.spec+": " + ex.message);
michael@0 41 return;
michael@0 42 }
michael@0 43 return fileUrl.file.clone().QueryInterface(Ci.nsILocalFile);
michael@0 44 },
michael@0 45
michael@0 46 init: function dh_init() {
michael@0 47 if (this._inited)
michael@0 48 return;
michael@0 49
michael@0 50 this._inited = true;
michael@0 51
michael@0 52 Services.obs.addObserver(this, "dl-start", true);
michael@0 53 Services.obs.addObserver(this, "dl-done", true);
michael@0 54 Services.obs.addObserver(this, "dl-run", true);
michael@0 55 Services.obs.addObserver(this, "dl-failed", true);
michael@0 56
michael@0 57
michael@0 58 this._progress = new DownloadProgressListener(this);
michael@0 59 this.manager.addListener(this._progress);
michael@0 60
michael@0 61 Elements.tabList.addEventListener("TabClose", this, false);
michael@0 62
michael@0 63 this._downloadProgressIndicator = document.getElementById("download-progress");
michael@0 64
michael@0 65 if (this.manager.activeDownloadCount) {
michael@0 66 setTimeout (this._restartWithActiveDownloads.bind(this), 0);
michael@0 67 }
michael@0 68 },
michael@0 69
michael@0 70 uninit: function dh_uninit() {
michael@0 71 if (this._inited) {
michael@0 72 Services.obs.removeObserver(this, "dl-start");
michael@0 73 Services.obs.removeObserver(this, "dl-done");
michael@0 74 Services.obs.removeObserver(this, "dl-run");
michael@0 75 Services.obs.removeObserver(this, "dl-failed");
michael@0 76 if (Elements && Elements.tabList)
michael@0 77 Elements.tabList.removeEventListener("TabClose", this);
michael@0 78 }
michael@0 79 },
michael@0 80
michael@0 81 get _notificationBox() {
michael@0 82 return Browser.getNotificationBox(Browser.selectedBrowser);
michael@0 83 },
michael@0 84
michael@0 85 get _notificationBoxes() {
michael@0 86 let currentBox = this._notificationBox;
michael@0 87 let boxes = [
michael@0 88 currentBox
michael@0 89 ];
michael@0 90 for (let { linkedBrowser } of Elements.tabList.children) {
michael@0 91 if (linkedBrowser !== Browser.selectedBrowser) {
michael@0 92 let notificationBox = Browser.getNotificationBox(linkedBrowser);
michael@0 93 if (notificationBox)
michael@0 94 boxes.push(notificationBox);
michael@0 95 }
michael@0 96 }
michael@0 97 return boxes;
michael@0 98 },
michael@0 99
michael@0 100 get _progressNotification() {
michael@0 101 let notn = this._getNotificationWithValue("download-progress");
michael@0 102 let currentBox = this._notificationBox;
michael@0 103 // move the progress notification if attached to a different browser
michael@0 104 if (notn && notn.parentNode !== currentBox) {
michael@0 105 notn.parentNode.removeNotification(notn);
michael@0 106 currentBox.insertBefore(notn, currentBox.firstChild);
michael@0 107 }
michael@0 108 return notn;
michael@0 109 },
michael@0 110
michael@0 111 _getNotificationWithValue: function(aValue) {
michael@0 112 let notn;
michael@0 113 let allNotificationBoxes = this._notificationBoxes;
michael@0 114 for(let box of allNotificationBoxes) {
michael@0 115 notn = box.getNotificationWithValue(aValue);
michael@0 116 if (notn) {
michael@0 117 break;
michael@0 118 }
michael@0 119 }
michael@0 120 return notn;
michael@0 121 },
michael@0 122
michael@0 123 _restartWithActiveDownloads: function() {
michael@0 124 let activeDownloads = this.manager.activeDownloads;
michael@0 125
michael@0 126 while (activeDownloads.hasMoreElements()) {
michael@0 127 let dl = activeDownloads.getNext();
michael@0 128 switch (dl.state) {
michael@0 129 case 0: // Downloading
michael@0 130 case 5: // Queued
michael@0 131 this.watchDownload(dl);
michael@0 132 this.updateInfobar();
michael@0 133 break;
michael@0 134 }
michael@0 135 }
michael@0 136 if (this.manager.activeDownloadCount) {
michael@0 137 ContextUI.displayNavbar();
michael@0 138 }
michael@0 139 },
michael@0 140
michael@0 141 openDownload: function dh_openDownload(aDownload) {
michael@0 142 let fileURI = aDownload.target
michael@0 143
michael@0 144 if (!(fileURI && fileURI.spec)) {
michael@0 145 Util.dumpLn("Cant open download "+id+", fileURI is invalid");
michael@0 146 return;
michael@0 147 }
michael@0 148
michael@0 149 let file = this._getLocalFile(fileURI);
michael@0 150 try {
michael@0 151 file && Services.metro.launchInDesktop(aDownload.target.spec, "");
michael@0 152 } catch (ex) {
michael@0 153 Util.dumpLn("Failed to open download, with id: "+id+", download target URI spec: " + fileURI.spec);
michael@0 154 Util.dumpLn("Failed download source:"+(aDownload.source && aDownload.source.spec));
michael@0 155 }
michael@0 156 },
michael@0 157
michael@0 158 removeDownload: function dh_removeDownload(aDownload) {
michael@0 159 // aDownload is the XUL element here,
michael@0 160 // and .target currently returns the target attribute (string value)
michael@0 161 let id = aDownload.getAttribute("downloadId");
michael@0 162 let download = this.manager.getDownload(id);
michael@0 163
michael@0 164 if (download) {
michael@0 165 this.manager.removeDownload(id);
michael@0 166 }
michael@0 167 },
michael@0 168
michael@0 169 cancelDownload: function dh_cancelDownload(aDownload) {
michael@0 170 let fileURI = aDownload.target;
michael@0 171 if (!(fileURI && fileURI.spec)) {
michael@0 172 Util.dumpLn("Cant remove download file for: "+aDownload.id+", fileURI is invalid");
michael@0 173 }
michael@0 174
michael@0 175 try {
michael@0 176 let file = this._getLocalFile(fileURI);
michael@0 177 if (file && file.exists())
michael@0 178 file.remove(false);
michael@0 179 this.manager.cancelDownload(aDownload.id);
michael@0 180
michael@0 181 // If cancelling was successful, stop tracking the download.
michael@0 182 this._progressNotificationInfo.delete(aDownload.guid);
michael@0 183 this._runDownloadBooleanMap.delete(aDownload.targetFile.path);
michael@0 184 this._downloadCount--;
michael@0 185 this._downloadsInProgress--;
michael@0 186 let notn = this._progressNotification;
michael@0 187 if (notn && this._downloadsInProgress <= 0) {
michael@0 188 this._notificationBox.removeNotification(notn);
michael@0 189 }
michael@0 190 } catch (ex) {
michael@0 191 Util.dumpLn("Failed to cancel download, with id: "+aDownload.id+", download target URI spec: " + fileURI.spec);
michael@0 192 Util.dumpLn("Failed download source:"+(aDownload.source && aDownload.source.spec));
michael@0 193 }
michael@0 194 },
michael@0 195
michael@0 196 // Cancels all downloads.
michael@0 197 cancelDownloads: function dh_cancelDownloads() {
michael@0 198 for (let [guid, info] of this._progressNotificationInfo) {
michael@0 199 this.cancelDownload(info.download);
michael@0 200 }
michael@0 201 this._downloadCount = 0;
michael@0 202 this._progressNotificationInfo.clear();
michael@0 203 this._runDownloadBooleanMap.clear();
michael@0 204 },
michael@0 205
michael@0 206 pauseDownload: function dh_pauseDownload(aDownload) {
michael@0 207 let id = aDownload.getAttribute("downloadId");
michael@0 208 this.manager.pauseDownload(id);
michael@0 209 },
michael@0 210
michael@0 211 resumeDownload: function dh_resumeDownload(aDownload) {
michael@0 212 let id = aDownload.getAttribute("downloadId");
michael@0 213 this.manager.resumeDownload(id);
michael@0 214 },
michael@0 215
michael@0 216 showPage: function dh_showPage(aDownload) {
michael@0 217 let id = aDownload.getAttribute("downloadId");
michael@0 218 let download = this.manager.getDownload(id);
michael@0 219 let uri = this._getReferrerOrSource(download);
michael@0 220 if (uri)
michael@0 221 BrowserUI.addAndShowTab(uri, Browser.selectedTab);
michael@0 222 },
michael@0 223
michael@0 224 showAlert: function dh_showAlert(aName, aMessage, aTitle, aObserver) {
michael@0 225 var notifier = Cc["@mozilla.org/alerts-service;1"]
michael@0 226 .getService(Ci.nsIAlertsService);
michael@0 227
michael@0 228 if (!aTitle)
michael@0 229 aTitle = Strings.browser.GetStringFromName("alertDownloads");
michael@0 230
michael@0 231 notifier.showAlertNotification("", aTitle, aMessage, true, "", aObserver, aName);
michael@0 232 },
michael@0 233
michael@0 234 showNotification: function dh_showNotification(title, msg, buttons, priority) {
michael@0 235 let notification = this._notificationBox.appendNotification(msg,
michael@0 236 title,
michael@0 237 URI_GENERIC_ICON_DOWNLOAD,
michael@0 238 priority,
michael@0 239 buttons);
michael@0 240 return notification;
michael@0 241 },
michael@0 242
michael@0 243 _showDownloadFailedNotification: function (aDownload) {
michael@0 244 let tryAgainButtonText =
michael@0 245 Strings.browser.GetStringFromName("downloadTryAgain");
michael@0 246 let cancelButtonText =
michael@0 247 Strings.browser.GetStringFromName("downloadCancel");
michael@0 248
michael@0 249 let message = Strings.browser.formatStringFromName("alertDownloadFailed",
michael@0 250 [aDownload.displayName], 1);
michael@0 251
michael@0 252 let buttons = [
michael@0 253 {
michael@0 254 isDefault: true,
michael@0 255 label: tryAgainButtonText,
michael@0 256 accessKey: "",
michael@0 257 callback: function() {
michael@0 258 MetroDownloadsView.manager.retryDownload(aDownload.id);
michael@0 259 }
michael@0 260 },
michael@0 261 {
michael@0 262 label: cancelButtonText,
michael@0 263 accessKey: "",
michael@0 264 callback: function() {
michael@0 265 MetroDownloadsView.cancelDownload(aDownload);
michael@0 266 MetroDownloadsView._downloadProgressIndicator.reset();
michael@0 267 }
michael@0 268 }
michael@0 269 ];
michael@0 270 this.showNotification("download-failed", message, buttons,
michael@0 271 this._notificationBox.PRIORITY_WARNING_HIGH);
michael@0 272 },
michael@0 273
michael@0 274 _showDownloadCompleteNotification: function () {
michael@0 275 let message = "";
michael@0 276 let showInFilesButtonText = Strings.browser.GetStringFromName("downloadShowInFiles");
michael@0 277
michael@0 278 let buttons = [
michael@0 279 {
michael@0 280 label: showInFilesButtonText,
michael@0 281 accessKey: "",
michael@0 282 callback: function() {
michael@0 283 let fileURI = MetroDownloadsView._lastDownload.target;
michael@0 284 let file = MetroDownloadsView._getLocalFile(fileURI);
michael@0 285 file.reveal();
michael@0 286 MetroDownloadsView._resetCompletedDownloads();
michael@0 287 }
michael@0 288 }
michael@0 289 ];
michael@0 290
michael@0 291 if (this._downloadCount > 1) {
michael@0 292 message = PluralForm.get(this._downloadCount,
michael@0 293 Strings.browser.GetStringFromName("alertMultipleDownloadsComplete"))
michael@0 294 .replace("#1", this._downloadCount)
michael@0 295 } else {
michael@0 296 let runButtonText =
michael@0 297 Strings.browser.GetStringFromName("downloadOpen");
michael@0 298 message = Strings.browser.formatStringFromName("alertDownloadsDone2",
michael@0 299 [this._lastDownload.displayName], 1);
michael@0 300
michael@0 301 buttons.unshift({
michael@0 302 isDefault: true,
michael@0 303 label: runButtonText,
michael@0 304 accessKey: "",
michael@0 305 callback: function() {
michael@0 306 MetroDownloadsView.openDownload(MetroDownloadsView._lastDownload);
michael@0 307 MetroDownloadsView._resetCompletedDownloads();
michael@0 308 }
michael@0 309 });
michael@0 310 }
michael@0 311 this._removeNotification("download-complete");
michael@0 312 this.showNotification("download-complete", message, buttons,
michael@0 313 this._notificationBox.PRIORITY_WARNING_MEDIUM);
michael@0 314 },
michael@0 315
michael@0 316 _showDownloadCompleteToast: function () {
michael@0 317 let name = "DownloadComplete";
michael@0 318 let msg = "";
michael@0 319 let title = "";
michael@0 320 let observer = null;
michael@0 321 if (this._downloadCount > 1) {
michael@0 322 title = PluralForm.get(this._downloadCount,
michael@0 323 Strings.browser.GetStringFromName("alertMultipleDownloadsComplete"))
michael@0 324 .replace("#1", this._downloadCount)
michael@0 325 msg = PluralForm.get(2, Strings.browser.GetStringFromName("downloadShowInFiles"));
michael@0 326
michael@0 327 observer = {
michael@0 328 observe: function (aSubject, aTopic, aData) {
michael@0 329 switch (aTopic) {
michael@0 330 case "alertclickcallback":
michael@0 331 let fileURI = MetroDownloadsView._lastDownload.target;
michael@0 332 let file = MetroDownloadsView._getLocalFile(fileURI);
michael@0 333 file.reveal();
michael@0 334 MetroDownloadsView._resetCompletedDownloads();
michael@0 335 break;
michael@0 336 }
michael@0 337 }
michael@0 338 }
michael@0 339 } else {
michael@0 340 title = Strings.browser.formatStringFromName("alertDownloadsDone",
michael@0 341 [this._lastDownload.displayName], 1);
michael@0 342 msg = Strings.browser.GetStringFromName("downloadOpenNow");
michael@0 343 observer = {
michael@0 344 observe: function (aSubject, aTopic, aData) {
michael@0 345 switch (aTopic) {
michael@0 346 case "alertclickcallback":
michael@0 347 MetroDownloadsView.openDownload(MetroDownloadsView._lastDownload);
michael@0 348 MetroDownloadsView._resetCompletedDownloads();
michael@0 349 break;
michael@0 350 }
michael@0 351 }
michael@0 352 }
michael@0 353 }
michael@0 354 this.showAlert(name, msg, title, observer);
michael@0 355 },
michael@0 356
michael@0 357 _resetCompletedDownloads: function () {
michael@0 358 this._progressNotificationInfo.clear();
michael@0 359 this._downloadCount = 0;
michael@0 360 this._lastDownload = null;
michael@0 361 this._downloadProgressIndicator.reset();
michael@0 362 this._removeNotification("download-complete");
michael@0 363 },
michael@0 364
michael@0 365 _updateCircularProgressMeter: function dv_updateCircularProgressMeter() {
michael@0 366 if (!this._progressNotificationInfo) {
michael@0 367 return;
michael@0 368 }
michael@0 369
michael@0 370 let totPercent = 0;
michael@0 371 for (let [guid, info] of this._progressNotificationInfo) {
michael@0 372 // info.download => nsIDownload
michael@0 373 totPercent += info.download.percentComplete;
michael@0 374 }
michael@0 375
michael@0 376 let percentComplete = totPercent / this._progressNotificationInfo.size;
michael@0 377 this._downloadProgressIndicator.updateProgress(percentComplete);
michael@0 378 },
michael@0 379
michael@0 380 _computeDownloadProgressString: function dv_computeDownloadProgressString() {
michael@0 381 let totTransferred = 0, totSize = 0, totSecondsLeft = 0;
michael@0 382 let guid, info;
michael@0 383 for ([guid, info] of this._progressNotificationInfo) {
michael@0 384 let size = info.download.size;
michael@0 385 let amountTransferred = info.download.amountTransferred;
michael@0 386 let speed = info.download.speed;
michael@0 387
michael@0 388 totTransferred += amountTransferred;
michael@0 389 totSize += size;
michael@0 390 totSecondsLeft += ((size - amountTransferred) / speed);
michael@0 391 }
michael@0 392
michael@0 393 // Compute progress in bytes.
michael@0 394 let amountTransferred = Util.getDownloadSize(totTransferred);
michael@0 395 let size = Util.getDownloadSize(totSize);
michael@0 396 let progress = amountTransferred + "/" + size;
michael@0 397
michael@0 398 // Compute progress in time.;
michael@0 399 let [timeLeft, newLast] = DownloadUtils.getTimeLeft(totSecondsLeft, this._lastSec);
michael@0 400 this._lastSec = newLast;
michael@0 401
michael@0 402 if (this._downloadCount == 1) {
michael@0 403 return Strings.browser.GetStringFromName("alertDownloadsStart2")
michael@0 404 .replace("#1", info.download.displayName)
michael@0 405 .replace("#2", progress)
michael@0 406 .replace("#3", timeLeft)
michael@0 407 }
michael@0 408
michael@0 409 let numDownloads = this._downloadCount;
michael@0 410 return PluralForm.get(numDownloads,
michael@0 411 Strings.browser.GetStringFromName("alertDownloadMultiple"))
michael@0 412 .replace("#1", numDownloads)
michael@0 413 .replace("#2", progress)
michael@0 414 .replace("#3", timeLeft);
michael@0 415 },
michael@0 416
michael@0 417 _saveDownloadData: function dv_saveDownloadData(aDownload) {
michael@0 418 if (!this._progressNotificationInfo.get(aDownload.guid)) {
michael@0 419 this._progressNotificationInfo.set(aDownload.guid, {});
michael@0 420 }
michael@0 421 let infoObj = this._progressNotificationInfo.get(aDownload.guid);
michael@0 422 infoObj.download = aDownload;
michael@0 423 this._progressNotificationInfo.set(aDownload.guid, infoObj);
michael@0 424 },
michael@0 425
michael@0 426 onDownloadButton: function dv_onDownloadButton() {
michael@0 427 let progressNotification = this._getNotificationWithValue("download-progress");
michael@0 428 let wasProgressVisible = (progressNotification &&
michael@0 429 progressNotification.parentNode == this._notificationBox);
michael@0 430 let completeNotification = this._getNotificationWithValue("download-complete");
michael@0 431 let wasCompleteVisible = (completeNotification &&
michael@0 432 completeNotification.parentNode == this._notificationBox);
michael@0 433
michael@0 434 this._removeNotification("download-complete");
michael@0 435 this._removeNotification("download-progress");
michael@0 436
michael@0 437 if (this._downloadsInProgress && !wasProgressVisible) {
michael@0 438 this.updateInfobar();
michael@0 439 } else if (this._downloadCount && !wasCompleteVisible) {
michael@0 440 this._showDownloadCompleteNotification();
michael@0 441 }
michael@0 442 },
michael@0 443
michael@0 444 _removeNotification: function (aValue) {
michael@0 445 let notification = this._getNotificationWithValue(aValue);
michael@0 446 return notification &&
michael@0 447 notification.parentNode.removeNotification(notification);
michael@0 448 },
michael@0 449
michael@0 450 updateInfobar: function dv_updateInfobar() {
michael@0 451 let message = this._computeDownloadProgressString();
michael@0 452 this._updateCircularProgressMeter();
michael@0 453
michael@0 454 let notn = this._progressNotification;
michael@0 455 if (!notn) {
michael@0 456 let cancelButtonText =
michael@0 457 Strings.browser.GetStringFromName("downloadCancel");
michael@0 458
michael@0 459 let buttons = [
michael@0 460 {
michael@0 461 isDefault: false,
michael@0 462 label: cancelButtonText,
michael@0 463 accessKey: "",
michael@0 464 callback: function() {
michael@0 465 MetroDownloadsView.cancelDownloads();
michael@0 466 MetroDownloadsView._downloadProgressIndicator.reset();
michael@0 467 }
michael@0 468 }
michael@0 469 ];
michael@0 470
michael@0 471 notn = this.showNotification("download-progress", message, buttons,
michael@0 472 this._notificationBox.PRIORITY_WARNING_LOW);
michael@0 473
michael@0 474 ContextUI.displayNavbar();
michael@0 475 } else {
michael@0 476 notn.label = message;
michael@0 477 }
michael@0 478 },
michael@0 479
michael@0 480 updateDownload: function dv_updateDownload(aDownload) {
michael@0 481 this._saveDownloadData(aDownload);
michael@0 482 let notn = this._progressNotification;
michael@0 483 if (notn) {
michael@0 484 notn.label =
michael@0 485 this._computeDownloadProgressString(aDownload);
michael@0 486 }
michael@0 487 this._updateCircularProgressMeter();
michael@0 488 },
michael@0 489
michael@0 490 watchDownload: function dv_watchDownload(aDownload) {
michael@0 491 this._saveDownloadData(aDownload);
michael@0 492 this._downloadCount++;
michael@0 493 this._downloadsInProgress++;
michael@0 494 if (!this._progressNotificationInfo.get(aDownload.guid)) {
michael@0 495 this._progressNotificationInfo.set(aDownload.guid, {});
michael@0 496 }
michael@0 497 if (!this._progressAlert) {
michael@0 498 this._progressAlert = new AlertDownloadProgressListener();
michael@0 499 this.manager.addListener(this._progressAlert);
michael@0 500 }
michael@0 501 },
michael@0 502
michael@0 503 observe: function (aSubject, aTopic, aData) {
michael@0 504 let message = "";
michael@0 505 let msgTitle = "";
michael@0 506
michael@0 507 switch (aTopic) {
michael@0 508 case "dl-run":
michael@0 509 let file = aSubject.QueryInterface(Ci.nsIFile);
michael@0 510 this._runDownloadBooleanMap.set(file.path, (aData == 'true'));
michael@0 511 break;
michael@0 512 case "dl-start":
michael@0 513 let download = aSubject.QueryInterface(Ci.nsIDownload);
michael@0 514 this.watchDownload(download);
michael@0 515 this.updateInfobar();
michael@0 516 break;
michael@0 517 case "dl-done":
michael@0 518 this._downloadsInProgress--;
michael@0 519 download = aSubject.QueryInterface(Ci.nsIDownload);
michael@0 520 this._lastDownload = download;
michael@0 521 let runAfterDownload = this._runDownloadBooleanMap.get(download.targetFile.path);
michael@0 522 if (runAfterDownload) {
michael@0 523 this.openDownload(download);
michael@0 524 }
michael@0 525
michael@0 526 this._runDownloadBooleanMap.delete(download.targetFile.path);
michael@0 527 if (this._downloadsInProgress == 0) {
michael@0 528 if (this._downloadCount > 1 || !runAfterDownload) {
michael@0 529 this._showDownloadCompleteToast();
michael@0 530 this._showDownloadCompleteNotification();
michael@0 531 }
michael@0 532 let notn = this._progressNotification;
michael@0 533 if (notn)
michael@0 534 this._notificationBox.removeNotification(notn);
michael@0 535
michael@0 536 ContextUI.displayNavbar();
michael@0 537 }
michael@0 538
michael@0 539 this._downloadProgressIndicator.notify();
michael@0 540 break;
michael@0 541 case "dl-failed":
michael@0 542 download = aSubject.QueryInterface(Ci.nsIDownload);
michael@0 543 this._showDownloadFailedNotification(download);
michael@0 544 break;
michael@0 545 }
michael@0 546 },
michael@0 547
michael@0 548 handleEvent: function(aEvent) {
michael@0 549 switch (aEvent.type) {
michael@0 550 case 'TabClose': {
michael@0 551 let browser = aEvent.originalTarget.linkedBrowser;
michael@0 552 let tab = Browser.getTabForBrowser(browser);
michael@0 553 let notificationBox = Browser.getNotificationBox(browser);
michael@0 554
michael@0 555 // move any download-related notification before the tab and its notificationBox goes away
michael@0 556 // The 3 possible values should be mutually exclusive
michael@0 557 for(let name of ["download-progress",
michael@0 558 "save-download",
michael@0 559 "download-complete"]) {
michael@0 560 let notn = notificationBox.getNotificationWithValue(name);
michael@0 561 if (!notn) {
michael@0 562 continue;
michael@0 563 }
michael@0 564
michael@0 565 let nextTab = Browser.getNextTab(tab);
michael@0 566 let nextBox = nextTab && Browser.getNotificationBox(nextTab.browser);
michael@0 567 if (nextBox) {
michael@0 568 // move notification to the next tab
michael@0 569 nextBox.adoptNotification(notn);
michael@0 570 } else {
michael@0 571 // Alas, no browser to move the notifications to.
michael@0 572 }
michael@0 573 }
michael@0 574 break;
michael@0 575 }
michael@0 576 }
michael@0 577 },
michael@0 578
michael@0 579 QueryInterface: function (aIID) {
michael@0 580 if (!aIID.equals(Ci.nsIObserver) &&
michael@0 581 !aIID.equals(Ci.nsISupportsWeakReference) &&
michael@0 582 !aIID.equals(Ci.nsISupports))
michael@0 583 throw Components.results.NS_ERROR_NO_INTERFACE;
michael@0 584 return this;
michael@0 585 }
michael@0 586 };
michael@0 587
michael@0 588
michael@0 589 /**
michael@0 590 * Notifies Downloads object about updates in the state of various downloads.
michael@0 591 *
michael@0 592 * @param aDownloads An instance of Downloads.
michael@0 593 */
michael@0 594 function DownloadProgressListener(aDownloads) {
michael@0 595 this._downloads = aDownloads;
michael@0 596 }
michael@0 597
michael@0 598 DownloadProgressListener.prototype = {
michael@0 599 _downloads: null,
michael@0 600
michael@0 601 //////////////////////////////////////////////////////////////////////////////
michael@0 602 //// nsIDownloadProgressListener
michael@0 603 onDownloadStateChange: function dPL_onDownloadStateChange(aState, aDownload) {
michael@0 604 // TODO: Use DownloadProgressListener instead of observers in the Downloads object.
michael@0 605 this._downloads.updateDownload(aDownload);
michael@0 606 },
michael@0 607
michael@0 608 onProgressChange: function dPL_onProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress, aDownload) {
michael@0 609 // TODO <jwilde>: Add more detailed progress information.
michael@0 610 this._downloads.updateDownload(aDownload);
michael@0 611 },
michael@0 612
michael@0 613 onStateChange: function(aWebProgress, aRequest, aState, aStatus, aDownload) { },
michael@0 614 onSecurityChange: function(aWebProgress, aRequest, aState, aDownload) { },
michael@0 615
michael@0 616 //////////////////////////////////////////////////////////////////////////////
michael@0 617 //// nsISupports
michael@0 618 QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadProgressListener])
michael@0 619 };
michael@0 620
michael@0 621
michael@0 622 /**
michael@0 623 * Tracks download progress so that additional information can be displayed
michael@0 624 * about its download in alert popups.
michael@0 625 */
michael@0 626 function AlertDownloadProgressListener() { }
michael@0 627
michael@0 628 AlertDownloadProgressListener.prototype = {
michael@0 629 //////////////////////////////////////////////////////////////////////////////
michael@0 630 //// nsIDownloadProgressListener
michael@0 631 onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress, aDownload) {
michael@0 632 let strings = Strings.browser;
michael@0 633 let availableSpace = -1;
michael@0 634
michael@0 635 try {
michael@0 636 // diskSpaceAvailable is not implemented on all systems
michael@0 637 let availableSpace = aDownload.targetFile.diskSpaceAvailable;
michael@0 638 } catch(ex) { }
michael@0 639
michael@0 640 let contentLength = aDownload.size;
michael@0 641 if (availableSpace > 0 && contentLength > 0 && contentLength > availableSpace) {
michael@0 642 MetroDownloadsView.showAlert(aDownload.target.spec.replace("file:", "download:"),
michael@0 643 strings.GetStringFromName("alertDownloadsNoSpace"),
michael@0 644 strings.GetStringFromName("alertDownloadsSize"));
michael@0 645 MetroDownloadsView.cancelDownload(aDownload);
michael@0 646 }
michael@0 647 },
michael@0 648
michael@0 649 onDownloadStateChange: function(aState, aDownload) { },
michael@0 650 onStateChange: function(aWebProgress, aRequest, aState, aStatus, aDownload) { },
michael@0 651 onSecurityChange: function(aWebProgress, aRequest, aState, aDownload) { },
michael@0 652
michael@0 653 //////////////////////////////////////////////////////////////////////////////
michael@0 654 //// nsISupports
michael@0 655 QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadProgressListener])
michael@0 656 };

mercurial