Bug 945707 - Pausing a download fails when done after a retry. r=paolo
authorMarco Bonardo <mbonardo@mozilla.com>
Wed, 29 Jan 2014 17:00:17 -0500
changeset 181867 87a0f1a43d39ca1a3200afc8d65f6cd79500bf4f
parent 181866 65159415c2ed2844fd590540074f4e01eec2c118
child 181868 6d1ac6ea785458de8053b2727267ec3ab15cc1cc
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspaolo
bugs945707
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 945707 - Pausing a download fails when done after a retry. r=paolo
browser/components/downloads/content/allDownloadsViewOverlay.js
browser/components/downloads/content/downloads.js
toolkit/content/contentAreaUtils.js
--- a/browser/components/downloads/content/allDownloadsViewOverlay.js
+++ b/browser/components/downloads/content/allDownloadsViewOverlay.js
@@ -36,32 +36,16 @@ const DOWNLOAD_VIEW_SUPPORTED_COMMANDS =
  ["cmd_delete", "cmd_copy", "cmd_paste", "cmd_selectAll",
   "downloadsCmd_pauseResume", "downloadsCmd_cancel",
   "downloadsCmd_open", "downloadsCmd_show", "downloadsCmd_retry",
   "downloadsCmd_openReferrer", "downloadsCmd_clearDownloads"];
 
 const NOT_AVAILABLE = Number.MAX_VALUE;
 
 /**
- * Download a URL.
- *
- * @param aURL
- *        the url to download (nsIURI object)
- * @param [optional] aFileName
- *        the destination file name
- */
-function DownloadURL(aURL, aFileName) {
-  // For private browsing, try to get document out of the most recent browser
-  // window, or provide our own if there's no browser window.
-  let browserWin = RecentWindow.getMostRecentBrowserWindow();
-  let initiatingDoc = browserWin ? browserWin.document : document;
-  saveURL(aURL, aFileName, null, true, true, undefined, initiatingDoc);
-}
-
-/**
  * A download element shell is responsible for handling the commands and the
  * displayed data for a single download view element. The download element
  * could represent either a past download (for which we get data from places)  or
  * a "session" download (using a data-item object. See DownloadsCommon.jsm), or both.
  *
  * Once initialized with either a data item or a places node, the created richlistitem
  * can be accessed through the |element| getter, and can then be inserted/removed from
  * a richlistbox.
@@ -640,17 +624,20 @@ DownloadElementShell.prototype = {
     }
     return false;
   },
 
   _retryAsHistoryDownload: function DES__retryAsHistoryDownload() {
     // In future we may try to download into the same original target uri, when
     // we have it.  Though that requires verifying the path is still valid and
     // may surprise the user if he wants to be requested every time.
-    DownloadURL(this.downloadURI, this.getDownloadMetaData().fileName);
+    let browserWin = RecentWindow.getMostRecentBrowserWindow();
+    let initiatingDoc = browserWin ? browserWin.document : document;
+    DownloadURL(this.downloadURI, this.getDownloadMetaData().fileName,
+                initiatingDoc);
   },
 
   /* nsIController */
   doCommand: function DES_doCommand(aCommand) {
     switch (aCommand) {
       case "downloadsCmd_open": {
         let file = this._dataItem ?
           this.dataItem.localFile :
@@ -1428,17 +1415,19 @@ DownloadsPlacesView.prototype = {
 
   _canDownloadClipboardURL: function DPV__canDownloadClipboardURL() {
     let [url, name] = this._getURLFromClipboardData();
     return url != "";
   },
 
   _downloadURLFromClipboard: function DPV__downloadURLFromClipboard() {
     let [url, name] = this._getURLFromClipboardData();
-    DownloadURL(url, name);
+    let browserWin = RecentWindow.getMostRecentBrowserWindow();
+    let initiatingDoc = browserWin ? browserWin.document : document;
+    DownloadURL(url, name, initiatingDoc);
   },
 
   doCommand: function DPV_doCommand(aCommand) {
     switch (aCommand) {
       case "cmd_copy":
         this._copySelectedDownloadsToClipboard();
         break;
       case "cmd_selectAll":
@@ -1482,16 +1471,21 @@ DownloadsPlacesView.prototype = {
     // Set the state attribute so that only the appropriate items are displayed.
     let contextMenu = document.getElementById("downloadsContextMenu");
     let state = element._shell.getDownloadMetaData().state;
     if (state !== undefined)
       contextMenu.setAttribute("state", state);
     else
       contextMenu.removeAttribute("state");
 
+    if (state == nsIDM.DOWNLOAD_DOWNLOADING) {
+      // The resumable property of a download may change at any time, so
+      // ensure we update the related command now.
+      goUpdateCommand("downloadsCmd_pauseResume");
+    }
     return true;
   },
 
   onKeyPress: function DPV_onKeyPress(aEvent) {
     let selectedElements = this._richlistbox.selectedItems;
     if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN) {
       // In the content tree, opening bookmarks by pressing return is only
       // supported when a single item is selected. To be consistent, do the
@@ -1574,18 +1568,21 @@ DownloadsPlacesView.prototype = {
     let dt = aEvent.dataTransfer;
     // If dragged item is from our source, do not try to
     // redownload already downloaded file.
     if (dt.mozGetDataAt("application/x-moz-file", 0))
       return;
 
     let name = { };
     let url = Services.droppedLinkHandler.dropLink(aEvent, name);
-    if (url)
-      DownloadURL(url, name.value);
+    if (url) {
+      let browserWin = RecentWindow.getMostRecentBrowserWindow();
+      let initiatingDoc = browserWin ? browserWin.document : document;
+      DownloadURL(url, name.value, initiatingDoc);
+    }
   }
 };
 
 for (let methodName of ["load", "applyFilter", "selectNode", "selectItems"]) {
   DownloadsPlacesView.prototype[methodName] = function() {
     throw new Error("|" + methodName + "| is not implemented by the downloads view.");
   }
 }
--- a/browser/components/downloads/content/downloads.js
+++ b/browser/components/downloads/content/downloads.js
@@ -500,18 +500,17 @@ const DownloadsPanel = {
                             .data
                             .split("\n");
       if (!url) {
         return;
       }
 
       let uri = NetUtil.newURI(url);
       DownloadsCommon.log("Pasted URL seems valid. Starting download.");
-      saveURL(uri.spec, name || uri.spec, null, true, true,
-              undefined, document);
+      DownloadURL(uri.spec, name, document);
     } catch (ex) {}
   },
 
   /**
    * Move focus to the main element in the downloads panel, unless another
    * element in the panel is already focused.
    */
   _focusPanel: function DP_focusPanel()
--- a/toolkit/content/contentAreaUtils.js
+++ b/toolkit/content/contentAreaUtils.js
@@ -674,16 +674,64 @@ function uniqueFile(aLocalFile)
     else {
       // replace the last (n) in the filename with (n+1)
       aLocalFile.leafName = aLocalFile.leafName.replace(/^(.*\()\d+\)/, "$1" + (collisionCount + 1) + ")");
     }
   }
   return aLocalFile;
 }
 
+#ifdef MOZ_JSDOWNLOADS
+/**
+ * Download a URL using the new jsdownloads API.
+ *
+ * @param aURL
+ *        the url to download
+ * @param [optional] aFileName
+ *        the destination file name, if omitted will be obtained from the url.
+ * @param aInitiatingDocument
+ *        The document from which the download was initiated.
+ */
+function DownloadURL(aURL, aFileName, aInitiatingDocument) {
+  // For private browsing, try to get document out of the most recent browser
+  // window, or provide our own if there's no browser window.
+  let isPrivate = aInitiatingDocument.defaultView
+                                     .QueryInterface(Ci.nsIInterfaceRequestor)
+                                     .getInterface(Ci.nsIWebNavigation)
+                                     .QueryInterface(Ci.nsILoadContext)
+                                     .usePrivateBrowsing;
+
+  let fileInfo = new FileInfo(aFileName);
+  initFileInfo(fileInfo, aURL, null, null, null, null);
+
+  let filepickerParams = {
+    fileInfo: fileInfo,
+    saveMode: SAVEMODE_FILEONLY
+  };
+
+  Task.spawn(function* () {
+    let accepted = yield promiseTargetFile(filepickerParams, true, fileInfo.uri);
+    if (!accepted)
+      return;
+
+    let file = filepickerParams.file;
+    let download = yield Downloads.createDownload({
+      source: { url: aURL, isPrivate: isPrivate },
+      target: { path: file.path, partFilePath: file.path + ".part" }
+    });
+    download.tryToKeepPartialData = true;
+    download.start();
+
+    // Add the download to the list, allowing it to be managed.
+    let list = yield Downloads.getList(Downloads.ALL);
+    list.add(download);
+  }).then(null, Components.utils.reportError);
+}
+#endif
+
 // We have no DOM, and can only save the URL as is.
 const SAVEMODE_FILEONLY      = 0x00;
 // We have a DOM and can save as complete.
 const SAVEMODE_COMPLETE_DOM  = 0x01;
 // We have a DOM which we can serialize as text.
 const SAVEMODE_COMPLETE_TEXT = 0x02;
 
 // If we are able to save a complete DOM, the 'save as complete' filter