]> git.donarmstrong.com Git - dactyl.git/blob - common/tests/functional/shared-modules/downloads.js
Initial import of 1.0~b6
[dactyl.git] / common / tests / functional / shared-modules / downloads.js
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is MozMill Test code.
15  *
16  * The Initial Developer of the Original Code is Mozilla Foundation.
17  * Portions created by the Initial Developer are Copyright (C) 2009
18  * the Initial Developer. All Rights Reserved.
19  *
20  * Contributor(s):
21  *   Henrik Skupin <hskupin@mozilla.com>
22  *   Anthony Hughes <anthony.s.hughes@gmail.com>
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either the GNU General Public License Version 2 or later (the "GPL"), or
26  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the MPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the MPL, the GPL or the LGPL.
35  *
36  * ***** END LICENSE BLOCK ***** */
37
38 /**
39  * @fileoverview
40  * The DownloadsAPI adds support for download related functions. It also gives
41  * access to the Download Manager.
42  *
43  * @version 1.0.1
44  */
45
46 // Include required modules
47 var utils = require("utils");
48
49 const gTimeout = 5000;
50
51 /**
52  * List of available download states
53  */
54 const downloadState = {
55   notStarted      : -1,
56   downloading     : 0,
57   finished        : 1,
58   failed          : 2,
59   canceled        : 3,
60   paused          : 4,
61   queued          : 5,
62   blockedParental : 6,
63   scanning        : 7,
64   dirty           : 8,
65   blockedPolicy   : 9
66 }
67
68 /**
69  * Constructor
70  */
71 function downloadManager() {
72   this._controller = null;
73   this.downloadState = downloadState;
74
75   this._dms = Cc["@mozilla.org/download-manager;1"].
76               getService(Ci.nsIDownloadManager);
77 }
78
79 /**
80  * Download Manager class
81  */
82 downloadManager.prototype = {
83   /**
84    * Returns the controller of the current window
85    *
86    * @returns Mozmill Controller
87    * @type {MozMillController}
88    */
89   get controller() {
90     return this._controller;
91   },
92
93   /**
94    * Returns the number of currently active downloads
95    *
96    * @returns Number of active downloads
97    * @type {number}
98    */
99   get activeDownloadCount() {
100     return this._dms.activeDownloadCount;
101   },
102
103   /**
104    * Cancel all active downloads
105    */
106   cancelActiveDownloads : function downloadManager_cancelActiveDownloads() {
107     // Get a list of all active downloads (nsISimpleEnumerator)
108     var downloads = this._dms.activeDownloads;
109
110     // Iterate through each active download and cancel it
111     while (downloads.hasMoreElements()) {
112       var download = downloads.getNext().QueryInterface(Ci.nsIDownload);
113       this._dms.cancelDownload(download.id);
114     }
115   },
116
117   /**
118    * Remove all downloads from the database
119    */
120   cleanUp : function downloadManager_cleanUp()
121   {
122     this._dms.cleanUp();
123   },
124
125   /**
126    * Cancel any active downloads, remove the files, and clean
127    * up the Download Manager database
128    *
129    * @param {Array of download} downloads
130    *        Downloaded files which should be deleted (optional)
131    */
132   cleanAll : function downloadManager_cleanAll(downloads) {
133     // Cancel any active downloads
134     this.cancelActiveDownloads();
135
136     // If no downloads have been specified retrieve the list from the database
137     if (downloads === undefined || downloads.length == 0)
138       downloads = this.getAllDownloads();
139     else
140       downloads = downloads.concat(this.getAllDownloads());
141
142     // Delete all files referred to in the Download Manager
143     this.deleteDownloadedFiles(downloads);
144
145     // Clean any entries from the Download Manager database
146     this.cleanUp();
147   },
148
149   /**
150    * Close the download manager
151    *
152    * @param {boolean} force
153    *        Force the closing of the DM window
154    */
155   close : function downloadManager_close(force) {
156     var windowCount = mozmill.utils.getWindows().length;
157
158     if (this._controller) {
159       // Check if we should force the closing of the DM window
160       if (force) {
161         this._controller.window.close();
162       } else {
163         var cmdKey = utils.getEntity(this.getDtds(), "cmd.close.commandKey");
164         this._controller.keypress(null, cmdKey, {accelKey: true});
165       }
166
167       this._controller.waitForEval("subject.getWindows().length == " + (windowCount - 1),
168                                    gTimeout, 100, mozmill.utils);
169       this._controller = null;
170     }
171   },
172
173   /**
174    * Delete all downloads from the local drive
175    *
176    * @param {download} downloads
177    *        List of downloaded files
178    */
179   deleteDownloadedFiles : function downloadManager_deleteDownloadedFiles(downloads) {
180     downloads.forEach(function(download) {
181       try {
182         var file = getLocalFileFromNativePathOrUrl(download.target);
183         file.remove(false);
184       } catch (ex) {
185       }
186     });
187   },
188
189   /**
190    * Get the list of all downloaded files in the database
191    *
192    * @returns List of downloads
193    * @type {Array of download}
194    */
195   getAllDownloads : function downloadManager_getAllDownloads() {
196     var dbConn = this._dms.DBConnection;
197     var stmt = null;
198
199     if (dbConn.schemaVersion < 3)
200       return new Array();
201
202     // Run a SQL query and iterate through all results which have been found
203     var downloads = [];
204     stmt = dbConn.createStatement("SELECT * FROM moz_downloads");
205     while (stmt.executeStep()) {
206       downloads.push({
207         id: stmt.row.id, name: stmt.row.name, target: stmt.row.target,
208         tempPath: stmt.row.tempPath, startTime: stmt.row.startTime,
209         endTime: stmt.row.endTime, state: stmt.row.state,
210         referrer: stmt.row.referrer, entityID: stmt.row.entityID,
211         currBytes: stmt.row.currBytes, maxBytes: stmt.row.maxBytes,
212         mimeType : stmt.row.mimeType, autoResume: stmt.row.autoResume,
213         preferredApplication: stmt.row.preferredApplication,
214         preferredAction: stmt.row.preferredAction
215       });
216     };
217     stmt.reset();
218
219     return downloads;
220   },
221
222   /**
223    * Gets the download state of the given download
224    *
225    * @param {ElemBase} download
226    *        Download which state should be checked
227    */
228   getDownloadState : function downloadManager_getDownloadState(download) {
229     return download.getNode().getAttribute('state');
230   },
231
232   /**
233    * Gets all the needed external DTD urls as an array
234    *
235    * @returns Array of external DTD urls
236    * @type [string]
237    */
238   getDtds : function downloadManager_getDtds() {
239     var dtds = ["chrome://browser/locale/browser.dtd",
240                 "chrome://mozapps/locale/downloads/downloads.dtd"];
241     return dtds;
242   },
243
244   /**
245    * Retrieve an UI element based on the given spec
246    *
247    * @param {object} spec
248    *        Information of the UI element which should be retrieved
249    *        type: General type information
250    *        subtype: Specific element or property
251    *        value: Value of the element or property
252    * @returns Element which has been created
253    * @type {ElemBase}
254    */
255   getElement : function downloadManager_getElement(spec) {
256     var elem = null;
257
258     switch(spec.type) {
259       /**
260        * subtype: subtype of property to match
261        * value: value of property to match
262        */
263       case "download":
264         // Use a temporary lookup to get the download item
265         var download = new elementslib.Lookup(this._controller.window.document,
266                                               '/id("downloadManager")/id("downloadView")/' +
267                                               '{"' + spec.subtype + '":"' + spec.value + '"}');
268         this._controller.waitForElement(download, gTimeout);
269
270         // Use its download id to construct the real lookup expression
271         elem = new elementslib.Lookup(this._controller.window.document,
272                                       '/id("downloadManager")/id("downloadView")/' +
273                                       'id("' + download.getNode().getAttribute('id') + '")');
274         break;
275
276       /**
277        * subtype: Identifier of the specified download button (cancel, pause, resume, retry)
278        * value: Entry (download) of the download list
279        */
280       case "download_button":
281         // XXX: Bug 555347 - There are outstanding events to process
282         this._controller.sleep(0);
283
284         elem = new elementslib.Lookup(this._controller.window.document, spec.value.expression +
285                                       '/anon({"flex":"1"})/[1]/[1]/{"cmd":"cmd_' + spec.subtype + '"}');
286         break;
287       default:
288         throw new Error(arguments.callee.name + ": Unknown element type - " + spec.type);
289     }
290
291     return elem;
292   },
293
294   /**
295    * Open the Download Manager
296    *
297    * @param {MozMillController} controller
298    *        MozMillController of the window to operate on
299    * @param {boolean} shortcut
300    *        If true the keyboard shortcut is used
301    */
302   open : function downloadManager_open(controller, shortcut) {
303     if (shortcut) {
304       if (mozmill.isLinux) {
305         var cmdKey = utils.getEntity(this.getDtds(), "downloadsUnix.commandkey");
306         controller.keypress(null, cmdKey, {ctrlKey: true, shiftKey: true});
307       } else {
308         var cmdKey = utils.getEntity(this.getDtds(), "downloads.commandkey");
309         controller.keypress(null, cmdKey, {accelKey: true});
310       }
311     } else {
312       controller.click(new elementslib.Elem(controller.menus["tools-menu"].menu_openDownloads));
313     }
314
315     controller.sleep(500);
316     this.waitForOpened(controller);
317   },
318
319   /**
320    * Wait for the given download state
321    *
322    * @param {MozMillController} controller
323    *        MozMillController of the window to operate on
324    * @param {downloadState} state
325    *        Expected state of the download
326    * @param {number} timeout
327    *        Timeout for waiting for the download state (optional)
328    */
329   waitForDownloadState : function downloadManager_waitForDownloadState(download, state, timeout) {
330     this._controller.waitForEval("subject.manager.getDownloadState(subject.download) == subject.state", timeout, 100,
331                                  {manager: this, download: download, state: state});
332   },
333
334   /**
335    * Wait until the Download Manager has been opened
336    *
337    * @param {MozMillController} controller
338    *        MozMillController of the window to operate on
339    */
340   waitForOpened : function downloadManager_waitForOpened(controller) {
341     this._controller = utils.handleWindow("type", "Download:Manager",
342                                           undefined, false);
343   }
344 };
345
346 /**
347  * Download the file of unkown type from the given location by saving it
348  * automatically to disk
349  *
350  * @param {MozMillController} controller
351  *        MozMillController of the browser window
352  * @param {string} url
353  *        URL of the file which has to be downloaded
354  */
355 var downloadFileOfUnknownType = function(controller, url) {
356   controller.open(url);
357
358   // Wait until the unknown content type dialog has been opened
359   controller.waitForEval("subject.getMostRecentWindow('').document.documentElement.id == 'unknownContentType'",
360                          gTimeout, 100, mozmill.wm);
361
362   utils.handleWindow("type", "", function (controller) {
363     // Select to save the file directly
364     var saveFile = new elementslib.ID(controller.window.document, "save");
365     controller.waitThenClick(saveFile, gTimeout);
366     controller.waitForEval("subject.selected == true", gTimeout, 100,
367                            saveFile.getNode());
368
369     // Wait until the OK button has been enabled and click on it
370     var button = new elementslib.Lookup(controller.window.document,
371                                         '/id("unknownContentType")/anon({"anonid":"buttons"})/{"dlgtype":"accept"}');
372     controller.waitForElement(button, gTimeout);
373     controller.waitForEval("subject.okButton.hasAttribute('disabled') == false", gTimeout, 100,
374                            {okButton: button.getNode()});
375     controller.click(button);
376   });
377 }
378
379 /**
380  * Get a local file from a native path or URL
381  *
382  * @param {string} aPathOrUrl
383  *        Native path or URL of the file
384  * @see http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/downloads/content/downloads.js#1309
385  */
386 function getLocalFileFromNativePathOrUrl(aPathOrUrl) {
387   if (aPathOrUrl.substring(0,7) == "file://") {
388     // if this is a URL, get the file from that
389     let ioSvc = Cc["@mozilla.org/network/io-service;1"]
390                    .getService(Ci.nsIIOService);
391
392     // XXX it's possible that using a null char-set here is bad
393     const fileUrl = ioSvc.newURI(aPathOrUrl, null, null)
394                          .QueryInterface(Ci.nsIFileURL);
395     return fileUrl.file.clone().QueryInterface(Ci.nsILocalFile);
396   } else {
397     // if it's a pathname, create the nsILocalFile directly
398     var f = new nsLocalFile(aPathOrUrl);
399     return f;
400   }
401 }
402
403 // Export of variables
404 exports.downloadState = downloadState;
405
406 // Export of functions
407 exports.downloadFileOfUnknownType = downloadFileOfUnknownType;
408 exports.getLocalFileFromNativePathOrUrl = getLocalFileFromNativePathOrUrl;
409
410 // Export of classes
411 exports.downloadManager = downloadManager;