Bug 192728 - Add possibility to drag URL/file to/from SeaMonkey's Download Manager (copy/move to desktop/folder). r/rs=Neil
authorJens Hatlak <jh@junetz.de>
Wed, 26 May 2010 17:30:55 +0200
changeset 5738 6ca437a04a938d0b2dffd3f874b8c9e3a04d677d
parent 5737 7249cc641f4bb189a8f947c80bc49ecf562fdbe0
child 5739 c3b77a8373b549aa81d5f07752381525fb0af446
push id4446
push userjh@junetz.de
push dateWed, 26 May 2010 15:32:08 +0000
treeherdercomm-central@6ca437a04a93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs192728
Bug 192728 - Add possibility to drag URL/file to/from SeaMonkey's Download Manager (copy/move to desktop/folder). r/rs=Neil
suite/common/downloads/downloadmanager.js
suite/common/downloads/downloadmanager.xul
suite/common/downloads/tests/Makefile.in
suite/common/downloads/tests/chrome/test_drag.xul
--- a/suite/common/downloads/downloadmanager.js
+++ b/suite/common/downloads/downloadmanager.js
@@ -694,8 +694,54 @@ var dlTreeController = {
     var cmds = ["cmd_play", "cmd_pause", "cmd_resume", "cmd_retry",
                 "cmd_cancel", "cmd_remove", "cmd_stop", "cmd_open", "cmd_show",
                 "cmd_openReferrer", "cmd_copyLocation", "cmd_properties",
                 "cmd_selectAll", "cmd_clearList"];
     for (let command in cmds)
       goUpdateCommand(cmds[command]);
   }
 };
+
+var gDownloadDNDObserver = {
+  onDragStart: function (aEvent)
+  {
+    if (!gDownloadTreeView ||
+        !gDownloadTreeView.selection ||
+        !gDownloadTreeView.selection.count)
+      return;
+
+    var selItemData = gDownloadTreeView.getRowData(gDownloadTree.currentIndex);
+    var file = getLocalFileFromNativePathOrUrl(selItemData.file);
+
+    if (!file.exists())
+      return;
+
+    var url = Services.io.newFileURI(file).spec;
+    var dt = aEvent.dataTransfer;
+    dt.mozSetDataAt("application/x-moz-file", file, 0);
+    dt.setData("text/uri-list", url + "\r\n");
+    dt.setData("text/plain", url + "\n");
+    dt.effectAllowed = "copyMove";
+  },
+
+  onDragOver: function (aEvent)
+  {
+    var types = aEvent.dataTransfer.types;
+    if (types.contains("text/uri-list") ||
+        types.contains("text/x-moz-url") ||
+        types.contains("text/plain"))
+      aEvent.preventDefault();
+    aEvent.stopPropagation();
+  },
+
+  onDrop: function(aEvent)
+  {
+    var dt = aEvent.dataTransfer;
+    var url = dt.getData("URL");
+    var name;
+    if (!url) {
+      url = dt.getData("text/x-moz-url") || dt.getData("text/plain");
+      [url, name] = url.split("\n");
+    }
+    if (url)
+      saveURL(url, name, null, true, true);
+  }
+}
--- a/suite/common/downloads/downloadmanager.xul
+++ b/suite/common/downloads/downloadmanager.xul
@@ -62,16 +62,18 @@
         windowtype="Download:Manager">
 
   <script type="application/javascript"
           src="chrome://communicator/content/downloads/downloadmanager.js"/>
   <script type="application/javascript"
           src="chrome://communicator/content/downloads/DownloadProgressListener.js"/>
   <script type="application/javascript"
           src="chrome://communicator/content/downloads/treeView.js"/>
+  <script type="application/javascript"
+          src="chrome://global/content/contentAreaUtils.js"/>
 
   <stringbundleset id="stringbundleset">
     <stringbundle id="dmBundle"
                   src="chrome://communicator/locale/downloads/downloadmanager.properties"/>
   </stringbundleset>
 
   <commandset id="dlWinCommands">
     <commandset id="tasksCommands">
@@ -386,16 +388,19 @@
   </toolbox>
 
   <tree id="downloadTree"
         flex="1" type="downloads"
         class="plain"
         context="downloadContext"
         enableColumnDrag="true"
         ondblclick="goDoCommand('cmd_open');"
+        ondragstart="gDownloadDNDObserver.onDragStart(event);"
+        ondragover="gDownloadDNDObserver.onDragOver(event);"
+        ondrop="gDownloadDNDObserver.onDrop(event);"
         onselect="onTreeSelect(event);">
     <treecols context="" onclick="sortDownloads(event.target)">
       <treecol id="Name"
                label="&col.name.label;"
                tooltiptext="&col.name.tooltip;"
                class="sortDirectionIndicator" flex="3"
                persist="width hidden ordinal sortActive sortDirection"/>
       <splitter class="tree-splitter"/>
--- a/suite/common/downloads/tests/Makefile.in
+++ b/suite/common/downloads/tests/Makefile.in
@@ -46,16 +46,17 @@ include $(topsrcdir)/config/rules.mk
 _CHROME_FILES = \
     test_action_keys_respect_focus.xul \
     test_basic_functionality.xul \
     test_cleanup_search.xul \
     test_clear_button_disabled.xul \
     test_close_download_manager.xul \
     test_delete_key_cancels.xul \
     test_delete_key_removes.xul \
+    test_drag.xul \
     test_enter_dblclick_opens.xul \
     test_multi_select.xul \
     test_multiword_search.xul \
     test_open_properties.xul \
     test_removeDownload_updates_ui.xul \
     test_search_clearlist.xul \
     test_search_keys.xul \
     test_select_all.xul \
new file mode 100644
--- /dev/null
+++ b/suite/common/downloads/tests/chrome/test_drag.xul
@@ -0,0 +1,215 @@
+<?xml version="1.0"?>
+<!--
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Phil Lacy <philbaseless-firefox@yahoo.com> (Original Author)
+ *   Jens Hatlak <jh@junetz.de>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * Assure download manager can load valid list item as
+ * "application/moz-x-file", "text/uri-list" and "text/plain"
+ */
+
+based on toolkit/mozapps/downloads/tests/chrome/test_bug_462172.xul
+https://bugzilla.mozilla.org/show_bug.cgi?id=462172
+
+create a file with unique name
+create another file with unique name and delete it
+load into downloads database
+open download manager
+synthesize drag on both files
+missing file should not init drag
+real file should return transferdata with application/x-moz-file,
+  text/uri-list (CRLF-terminated) and text/plain (LF-terminated)
+close window
+-->
+<window title="Download Manager Test"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="test();">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/MochiKit/packed.js"/>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+  <script type="application/javascript">
+  <![CDATA[
+var missingFileElid;
+var realFileElid;
+const kFiller = "notApplicable";
+const kFillerURL = "https://bugzilla.mozilla.org/show_bug.cgi?id=462172"
+var realFile = Components.classes["@mozilla.org/file/directory_service;1"]
+                         .getService(Components.interfaces.nsIProperties)
+                         .get("CurWorkD", Components.interfaces.nsIFile);
+var missingFile = Components.classes["@mozilla.org/file/directory_service;1"]
+                            .getService(Components.interfaces.nsIProperties)
+                            .get("CurWorkD", Components.interfaces.nsIFile);
+
+var ios = Components.classes["@mozilla.org/network/io-service;1"]
+                    .getService(Components.interfaces.nsIIOService);
+
+realFile.append(kFiller);
+realFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666);
+var realFilePath = ios.newFileURI(realFile).spec;
+
+missingFile.append(kFiller);
+missingFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666);
+var missingFilePath = ios.newFileURI(missingFile).spec;
+missingFile.remove(false);
+
+// Dummy data for our files.
+// 'source' field must be in form of a URL.
+const DownloadData = [
+  { name: kFiller,
+    source: kFillerURL,
+    target: realFilePath,
+    state: Components.interfaces.nsIDownloadManager.DOWNLOAD_FINISHED },
+  { name: kFiller,
+    source: kFillerURL,
+    target: missingFilePath,
+    state: Components.interfaces.nsIDownloadManager.DOWNLOAD_FINISHED }
+];
+
+function mouseDragStartOnCell(aTree, aRow, aColumn, aWin, aFile)
+{
+  // get cell coordinates
+  var x = {}, y = {}, width = {}, height = {};
+  if (typeof aTree.columns != "undefined")
+    aColumn = aTree.columns[aColumn];
+  aTree.treeBoxObject.getCoordsForCellItem(aRow, aColumn, "text", x, y, width,
+                                           height);
+  return synthesizeDragStart(aTree.body, aFile, aWin, x.value, y.value);
+}
+
+function compareFunc(actualData, expectedData)
+{
+  return expectedData.equals(actualData);
+}
+
+var dragRealFile = [[
+  { type: "application/x-moz-file",
+    data: realFile,
+    eqTest: compareFunc },
+  { type: "text/uri-list",
+    data: realFilePath + "\r\n" },
+  { type: "text/plain",
+    data: realFilePath + "\n" }
+]];
+var dragMissingFile = [[
+  { type: "application/x-moz-file",
+    data: missingFile,
+    eqTest: compareFunc },
+  { type: "text/uri-list",
+    data: missingFilePath + "\r\n" },
+  { type: "text/plain",
+    data: missingFilePath + "\n" }
+]];
+
+function test()
+{
+  var dm = Components.classes["@mozilla.org/download-manager;1"]
+                     .getService(Components.interfaces.nsIDownloadManager);
+
+  // See if the DM is already open, and if it is, close it!
+  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+                     .getService(Components.interfaces.nsIWindowMediator);
+  var win = wm.getMostRecentWindow("Download:Manager");
+  if (win)
+    win.close();
+
+  var os = Components.classes["@mozilla.org/observer-service;1"]
+                     .getService(Components.interfaces.nsIObserverService);
+  const DLMGR_UI_DONE = "download-manager-ui-done";
+
+  // load files into db
+  var db = dm.DBConnection;
+
+  var stmt = db.createStatement(
+    "INSERT INTO moz_downloads ( name,  source,  target,  state)" +
+    "VALUES                    (:name, :source, :target, :state)");
+  for each (var dl in DownloadData) {
+    for (var prop in dl)
+      stmt.params[prop] = dl[prop];
+    stmt.execute();
+  }
+  stmt.finalize();
+
+  var testObs = {
+    observe: function(aSubject, aTopic, aData) {
+      if (aTopic != DLMGR_UI_DONE)
+        return;
+
+      var win = aSubject;
+      win.focus();
+
+      var downloadTree = win.document.getElementById("downloadTree");
+
+      // Now we can run our tests
+      // Unordered sorting -> DownloadData/insert order: realFile, missingFile
+      // Column 4 is "Progress" (column 1, "Status", is hidden by default)
+      var result = mouseDragStartOnCell(downloadTree, 0, 4, win, dragRealFile);
+      is(result, null, "Checking for Real file match");
+      result = mouseDragStartOnCell(downloadTree, 1, 4, win, dragMissingFile);
+      isnot(result, null, "Drag start did not return item for missing file");
+
+      // Done.
+      win.close();
+      realFile.remove(false);
+      os.removeObserver(testObs, DLMGR_UI_DONE);
+      SimpleTest.finish();
+    }
+  };
+
+  // Register with the observer service
+  os.addObserver(testObs, DLMGR_UI_DONE, false);
+
+  // Show the Download Manager UI
+  Components.classes["@mozilla.org/download-manager-ui;1"]
+            .getService(Components.interfaces.nsISuiteDownloadManagerUI)
+            .showManager();
+
+  SimpleTest.waitForExplicitFinish();
+}
+
+  ]]>
+  </script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <p id="display"></p>
+    <div id="content" style="display:none;"></div>
+    <pre id="test"></pre>
+  </body>
+</window>