Bug 906314 - Allow using the JavaScript API instead of nsIDownloadManager when removing finished downloads. r=enn
authorPaolo Amadini <paolo.mozmail@amadzone.org>
Mon, 19 Aug 2013 17:18:25 +0200
changeset 143066 0cec459440080e6433ce9d07971ebd81fbef8139
parent 143065 3bcc3e774eee69e2325a98c2cc07f880dc81d498
child 143067 5f42d98b068ba28cc517dece7424631e73ae4ff7
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersenn
bugs906314
milestone26.0a1
Bug 906314 - Allow using the JavaScript API instead of nsIDownloadManager when removing finished downloads. r=enn
browser/components/downloads/content/allDownloadsViewOverlay.js
browser/components/downloads/content/downloads.js
browser/components/downloads/src/DownloadsCommon.jsm
--- a/browser/components/downloads/content/allDownloadsViewOverlay.js
+++ b/browser/components/downloads/content/allDownloadsViewOverlay.js
@@ -783,27 +783,27 @@ function DownloadsPlacesView(aRichListBo
 
   this._searchTerm = "";
 
   this._active = aActive;
 
   // Register as a downloads view. The places data will be initialized by
   // the places setter.
   this._initiallySelectedElement = null;
-  let downloadsData = DownloadsCommon.getData(window.opener || window);
-  downloadsData.addView(this);
+  this._downloadsData = DownloadsCommon.getData(window.opener || window);
+  this._downloadsData.addView(this);
 
   // Get the Download button out of the attention state since we're about to
   // view all downloads.
   DownloadsCommon.getIndicatorData(window).attention = false;
 
   // Make sure to unregister the view if the window is closed.
   window.addEventListener("unload", function() {
     window.controllers.removeController(this);
-    downloadsData.removeView(this);
+    this._downloadsData.removeView(this);
     this.result = null;
   }.bind(this), true);
   // Resizing the window may change items visibility.
   window.addEventListener("resize", function() {
     this._ensureVisibleElementsAreActive();
   }.bind(this), true);
 }
 
@@ -1443,21 +1443,17 @@ DownloadsPlacesView.prototype = {
         break;
       case "cmd_selectAll":
         this._richlistbox.selectAll();
         break;
       case "cmd_paste":
         this._downloadURLFromClipboard();
         break;
       case "downloadsCmd_clearDownloads":
-        if (PrivateBrowsingUtils.isWindowPrivate(window)) {
-          Services.downloads.cleanUpPrivate();
-        } else {
-          Services.downloads.cleanUp();
-        }
+        this._downloadsData.removeFinished();
         if (this.result) {
           Cc["@mozilla.org/browser/download-history;1"]
             .getService(Ci.nsIDownloadHistory)
             .removeAllDownloads();
         }
         // There may be no selection or focus change as a result
         // of these change, and we want the command updated immediately.
         goUpdateCommand("downloadsCmd_clearDownloads");
--- a/browser/components/downloads/content/downloads.js
+++ b/browser/components/downloads/content/downloads.js
@@ -132,17 +132,21 @@ const DownloadsPanel = {
     }
     this._state = this.kStateHidden;
 
     window.addEventListener("unload", this.onWindowUnload, false);
 
     // Ensure that the Download Manager service is running.  This resumes
     // active downloads if required.  If there are downloads to be shown in the
     // panel, starting the service will make us load their data asynchronously.
-    Services.downloads;
+    if (DownloadsCommon.useJSTransfer) {
+      DownloadsCommon.initializeAllDataLinks();
+    } else {
+      Services.downloads;
+    }
 
     // Now that data loading has eventually started, load the required XUL
     // elements and initialize our views.
     DownloadsCommon.log("Ensuring DownloadsPanel overlay loaded.");
     DownloadsOverlayLoader.ensureOverlayLoaded(this.kDownloadsOverlay,
                                                function DP_I_callback() {
       DownloadsViewController.initialize();
       DownloadsCommon.log("Attaching DownloadsView...");
@@ -1339,21 +1343,17 @@ const DownloadsViewController = {
     // ancestors of the focused element.
     return !!element;
   },
 
   isCommandEnabled: function DVC_isCommandEnabled(aCommand)
   {
     // Handle commands that are not selection-specific.
     if (aCommand == "downloadsCmd_clearList") {
-      if (PrivateBrowsingUtils.isWindowPrivate(window)) {
-        return Services.downloads.canCleanUpPrivate;
-      } else {
-        return Services.downloads.canCleanUp;
-      }
+      return DownloadsCommon.getData(window).canRemoveFinished;
     }
 
     // Other commands are selection-specific.
     let element = DownloadsView.richListBox.selectedItem;
     return element &&
            new DownloadsViewItemController(element).isCommandEnabled(aCommand);
   },
 
@@ -1390,21 +1390,17 @@ const DownloadsViewController = {
 
   /**
    * This object contains one key for each command that operates regardless of
    * the currently selected item in the list.
    */
   commands: {
     downloadsCmd_clearList: function DVC_downloadsCmd_clearList()
     {
-      if (PrivateBrowsingUtils.isWindowPrivate(window)) {
-        Services.downloads.cleanUpPrivate();
-      } else {
-        Services.downloads.cleanUp();
-      }
+      DownloadsCommon.getData(window).removeFinished();
     }
   }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsViewItemController
 
 /**
--- a/browser/components/downloads/src/DownloadsCommon.jsm
+++ b/browser/components/downloads/src/DownloadsCommon.jsm
@@ -632,25 +632,29 @@ DownloadsDataCtor.prototype = {
    *        this because getService isn't available for us when this method is
    *        called, and we must ensure to register our listeners before the
    *        getService call for the Download Manager returns.
    */
   initializeDataLink: function DD_initializeDataLink(aDownloadManagerService)
   {
     // Start receiving real-time events.
     if (DownloadsCommon.useJSTransfer) {
-      let promiseList = this._isPrivate ? Downloads.getPrivateDownloadList()
-                                        : Downloads.getPublicDownloadList();
-      promiseList.then(list => list.addView(this)).then(null, Cu.reportError);
+      if (!this._dataLinkInitialized) {
+        let promiseList = this._isPrivate ? Downloads.getPrivateDownloadList()
+                                          : Downloads.getPublicDownloadList();
+        promiseList.then(list => list.addView(this)).then(null, Cu.reportError);
+        this._dataLinkInitialized = true;
+      }
     } else {
       aDownloadManagerService.addPrivacyAwareListener(this);
       Services.obs.addObserver(this, "download-manager-remove-download-guid",
                                false);
     }
   },
+  _dataLinkInitialized: false,
 
   /**
    * Stops receiving events for current downloads and cancels any pending read.
    */
   terminateDataLink: function DD_terminateDataLink()
   {
     if (DownloadsCommon.useJSTransfer) {
       Cu.reportError("terminateDataLink not applicable with useJSTransfer");
@@ -659,16 +663,56 @@ DownloadsDataCtor.prototype = {
 
     this._terminateDataAccess();
 
     // Stop receiving real-time events.
     Services.obs.removeObserver(this, "download-manager-remove-download-guid");
     Services.downloads.removeListener(this);
   },
 
+  /**
+   * True if there are finished downloads that can be removed from the list.
+   */
+  get canRemoveFinished()
+  {
+    if (DownloadsCommon.useJSTransfer) {
+      for (let [, dataItem] of Iterator(this.dataItems)) {
+        if (dataItem && !dataItem.inProgress) {
+          return true;
+        }
+      }
+      return false;
+    } else {
+      if (this._isPrivate) {
+        return Services.downloads.canCleanUpPrivate;
+      } else {
+        return Services.downloads.canCleanUp;
+      }
+    }
+  },
+
+  /**
+   * Asks the back-end to remove finished downloads from the list.
+   */
+  removeFinished: function DD_removeFinished()
+  {
+    if (DownloadsCommon.useJSTransfer) {
+      let promiseList = this._isPrivate ? Downloads.getPrivateDownloadList()
+                                        : Downloads.getPublicDownloadList();
+      promiseList.then(list => list.removeFinished())
+                 .then(null, Cu.reportError);
+    } else {
+      if (this._isPrivate) {
+        Services.downloads.cleanUpPrivate();
+      } else {
+        Services.downloads.cleanUp();
+      }
+    }
+  },
+
   //////////////////////////////////////////////////////////////////////////////
   //// Integration with the asynchronous Downloads back-end
 
   onDownloadAdded: function (aDownload)
   {
     let dataItem = new DownloadsDataItem(aDownload);
     this._downloadToDataItemMap.set(aDownload, dataItem);
     this.dataItems[dataItem.downloadGuid] = dataItem;