Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / xpfe / components / download-manager / resources / downloadmanager.js
blobbb60ab94340668d4205d67b55da4e47b51fbabff
1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is mozilla.org code.
16  *
17  * The Initial Developer of the Original Code is
18  * Netscape Communications Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 1998
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *   Ben Goodger <ben@netscape.com> (Original Author)
24  *   Blake Ross <blakeross@telocity.com>
25  *   Jan Varga <varga@ku.sk>
26  *
27  * Alternatively, the contents of this file may be used under the terms of
28  * either of the GNU General Public License Version 2 or later (the "GPL"),
29  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30  * in which case the provisions of the GPL or the LGPL are applicable instead
31  * of those above. If you wish to allow use of your version of this file only
32  * under the terms of either the GPL or the LGPL, and not to allow others to
33  * use your version of this file under the terms of the MPL, indicate your
34  * decision by deleting the provisions above and replace them with the notice
35  * and other provisions required by the GPL or the LGPL. If you do not delete
36  * the provisions above, a recipient may use your version of this file under
37  * the terms of any one of the MPL, the GPL or the LGPL.
38  *
39  * ***** END LICENSE BLOCK ***** */
41 const NC_NS = "http://home.netscape.com/NC-rdf#";
43 var gDownloadView = null;
44 var gDownloadManager = null;
45 var gRDFService = null;
46 var gNC_File = null;
47 var gFileHandler = null;
48 var gStatusBar = null;
49 var gCannotLaunch = ((navigator.platform.indexOf("Win") == -1) &&
50                      (navigator.platform.indexOf("OS/2") == -1) &&
51                      (navigator.platform.indexOf("Mac") == -1) &&
52                      (navigator.platform.indexOf("BeOS") == -1));
54 const dlObserver = {
55   observe: function(subject, topic, state) {
56     if (topic != "download-starting") return;
57     selectDownload(subject.QueryInterface(Components.interfaces.nsIDownload));
58   }
61 function selectDownload(aDownload)
63   var dlElt = document.getElementById(aDownload.targetFile.path);
64   var dlIndex = gDownloadView.contentView.getIndexOfItem(dlElt);
65   gDownloadView.view.selection.select(dlIndex);
66   gDownloadView.treeBoxObject.ensureRowIsVisible(dlIndex);
69 function DLManagerStartup()
70 {  
71   if (!window.arguments.length)
72     return;
74   try {
75     var observerService = Components.classes[kObserverServiceProgID]
76                                     .getService(Components.interfaces.nsIObserverService);
77     observerService.addObserver(dlObserver, "download-starting", false);
78   }
79   catch (ex) {
80   }
82   const rdfSvcContractID = "@mozilla.org/rdf/rdf-service;1";
83   const rdfSvcIID = Components.interfaces.nsIRDFService;
84   gRDFService = Components.classes[rdfSvcContractID].getService(rdfSvcIID);
85   
86   gNC_File = gRDFService.GetResource(NC_NS + "File");
88   gDownloadView = document.getElementById("downloadView");
89   setSortVariables(gDownloadView);
91   const dlmgrContractID = "@mozilla.org/download-manager;1";
92   const dlmgrIID = Components.interfaces.nsIDownloadManager;
93   gDownloadManager = Components.classes[dlmgrContractID].getService(dlmgrIID);
95   const ioSvcContractID = "@mozilla.org/network/io-service;1";
96   const ioSvcIID = Components.interfaces.nsIIOService;
97   var ioService = Components.classes[ioSvcContractID].getService(ioSvcIID);
99   const fileHandlerIID = Components.interfaces.nsIFileProtocolHandler;
100   gFileHandler = ioService.getProtocolHandler("file")
101                           .QueryInterface(fileHandlerIID);
103   var ds = window.arguments[0];
104   gDownloadView.database.AddDataSource(ds);
105   gDownloadView.builder.rebuild();
106   window.setTimeout(onRebuild, 0);
108   // correct keybinding command attributes which don't do our business yet
109   var key = document.getElementById("key_delete");
110   if (key.getAttribute("command"))
111     key.setAttribute("command", "cmd_remove");
112   key = document.getElementById("key_delete2");
113   if (key.getAttribute("command"))
114     key.setAttribute("command", "cmd_remove");
115   
116   document.getElementById("btn_openfile").hidden = gCannotLaunch;
117   document.getElementById("downloadPaneContext-openfile").hidden = gCannotLaunch;
120 function onRebuild() {
121   gDownloadView.controllers.appendController(downloadViewController);
122   gDownloadView.focus();
124   // If the window was opened automatically because
125   // a download started, select the new download
126   if (window.arguments.length > 1 && window.arguments[1]) {
127     var dl = window.arguments[1];
128     selectDownload(dl.QueryInterface(Components.interfaces.nsIDownload));
129   }
130   else if (gDownloadView.view && gDownloadView.view.rowCount > 0) {
131     // Select the first item in the view, if any.
132     gDownloadView.view.selection.select(0);
133   }
136 function onSelect(aEvent) {
137   if (!gStatusBar)
138     gStatusBar = document.getElementById("statusbar-text");
140   var selectionCount = gDownloadView.view.selection.count;
141   if (selectionCount == 1)
142     gStatusBar.label = createLocalFile(getSelectedItem().id).path;
143   else
144     gStatusBar.label = "";
146   window.updateCommands("tree-select");
149 function onTrigger() {
150   if (downloadViewController.isCommandEnabled('cmd_properties'))
151     goDoCommand('cmd_properties');
152   else if (downloadViewController.isCommandEnabled('cmd_openfile'))
153     goDoCommand('cmd_openfile');
154   else if (downloadViewController.isCommandEnabled('cmd_showinshell'))
155     goDoCommand('cmd_showinshell');
158 var downloadViewController = {
159   supportsCommand: function dVC_supportsCommand (aCommand)
160   {
161     switch (aCommand) {
162     case "cmd_properties":
163     case "cmd_pause":
164     case "cmd_cancel":
165     case "cmd_remove":
166     case "cmd_copyurl":
167     case "cmd_openfile":
168     case "cmd_showinshell":
169     case "cmd_selectAll":
170       return true;
171     }
172     return false;
173   },
175   isCommandEnabled: function dVC_isCommandEnabled (aCommand)
176   {
177     if (!gDownloadView.view || !gDownloadView.view.selection) return false;
178     var selectionCount = gDownloadView.view.selection.count;
179     if (!selectionCount) return false;
181     var selectedItem = getSelectedItem();
182     var isDownloading = selectedItem && gDownloadManager.getDownload(selectedItem.id);
184     switch (aCommand) {
185     case "cmd_openfile":
186       if (gCannotLaunch)
187         return false;
188     case "cmd_showinshell":
189       // we can't reveal until the download is complete, because we have not given
190       // the file its final name until them.
191       return selectionCount == 1 && !isDownloading && selectedItem &&
192              createLocalFile(selectedItem.id).exists();
193     case "cmd_properties":
194       return selectionCount == 1 && isDownloading;
195     case "cmd_pause":
196       return false;
197     case "cmd_cancel":
198       // XXX check if selection is still in progress
199       //     how to handle multiple selection?
200       return isDownloading;
201     case "cmd_remove":
202       // XXX ensure selection isn't still in progress
203       //     and how to handle multiple selection?
204       return selectionCount > 0 && !isDownloading;
205     case "cmd_copyurl":
206       return selectionCount > 0;
207     case "cmd_selectAll":
208       return gDownloadView.view.rowCount != selectionCount;
209     default:
210       return false;
211     }
212   },
214   doCommand: function dVC_doCommand (aCommand)
215   {
216     var selectedItem, selectedItems;
217     var file, i;
219     switch (aCommand) {
220     case "cmd_properties":
221       selectedItem = getSelectedItem();
222       var dl;
223       if (selectedItem)
224         dl = gDownloadManager.getDownload(selectedItem.id);
225       if (dl)
226         gDownloadManager.openProgressDialogFor(dl, window, false);
227       break;
228     case "cmd_openfile":
229       selectedItem = getSelectedItem();
230       if (selectedItem) {
231         file = createLocalFile(selectedItem.id);
232         const kDontAskAgainPref  = "browser.download.progressDnlgDialog.dontAskForLaunch";
233         try {
234           var pref = Components.classes["@mozilla.org/preferences-service;1"]
235                               .getService(Components.interfaces.nsIPrefBranch);
236           var dontAskAgain = pref.getBoolPref(kDontAskAgainPref);
237         } catch (e) {
238           // dontAskAgain not set - then we need to ask user
239           dontAskAgain = false;
240         }
241         if (!dontAskAgain && file.isExecutable()) {
242           try {
243             var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
244                                       .getService(Components.interfaces.nsIPromptService);
245           } catch (ex) {
246             break;
247           }
248           var strBundle = document.getElementById("dlProgressDlgBundle");
249           var title = strBundle.getFormattedString("openingAlertTitle", [file.leafName]);
250           var msg = strBundle.getFormattedString("securityAlertMsg", [file.leafName]);
251           var dontaskmsg = strBundle.getString("dontAskAgain");
252           var checkbox = {value:0};
253           var okToProceed = promptService.confirmCheck(window, title, msg, dontaskmsg, checkbox);
254           try {
255             if (checkbox.value != dontAskAgain)
256               pref.setBoolPref(kDontAskAgainPref, checkbox.value);
257           } catch (ex) {}
258           if (!okToProceed)
259             return;
260         }
261         file.launch();
262       }
263       break;
264     case "cmd_showinshell":
265       selectedItem = getSelectedItem();
266       if (selectedItem) {
267         file = createLocalFile(selectedItem.id);
269         // on unix, open a browser window rooted at the parent
270         if ((navigator.platform.indexOf("Win") == -1) &&
271             (navigator.platform.indexOf("Mac") == -1) &&
272             (navigator.platform.indexOf("OS/2") == -1) &&
273             (navigator.platform.indexOf("BeOS") == -1)) {
274           var parent = file.parent;
275           if (parent) {
276             const browserURL = "chrome://navigator/content/navigator.xul";
277             window.openDialog(browserURL, "_blank", "chrome,all,dialog=no", parent.path);
278           }
279         }
280         else {
281           file.reveal();
282         }
283       }
284       break;
285     case "cmd_pause":
286       break;
287     case "cmd_cancel":
288       // XXX we should probably prompt the user
289       selectedItems = getSelectedItems();
290       for (i = 0; i < selectedItems.length; i++)
291         gDownloadManager.cancelDownload(selectedItems[i].id);
292       window.updateCommands("tree-select");
293       break;
294     case "cmd_remove":
295       selectedItems = getSelectedItems();
296       // Figure out where to place the selection after deletion
297       var newSelectionPos = gDownloadView.contentView.getIndexOfItem(selectedItems[0]);
298       gDownloadManager.startBatchUpdate();
300       // Notify the datasource that we're about to begin a batch operation
301       var ds = window.arguments[0]
302                      .QueryInterface(Components.interfaces.nsIRDFDataSource);
303       ds.beginUpdateBatch();
304       for (i = 0; i <= selectedItems.length - 1; ++i) {
305         gDownloadManager.removeDownload(selectedItems[i].id);
306       }
307       ds.endUpdateBatch();
309       gDownloadManager.endBatchUpdate();
310       // If there's nothing on the panel now, skip setting the selection
311       if (gDownloadView.treeBoxObject.view && gDownloadView.treeBoxObject.view.rowCount > 0) {
312         // Select the item that replaced the first deleted one
313         if (newSelectionPos >= gDownloadView.treeBoxObject.view.rowCount)
314           newSelectionPos = gDownloadView.treeBoxObject.view.rowCount - 1;
315         gDownloadView.view.selection.select(newSelectionPos);
316         gDownloadView.treeBoxObject.ensureRowIsVisible(newSelectionPos);
317         gStatusBar.label = createLocalFile(getSelectedItem().id).path;
318       }
319       else {
320         // Nothing on the panel, so clear the Status Bar
321         gStatusBar.label = "";
322       }
323       window.updateCommands("tree-select");
324       break;
325     case "cmd_selectAll":
326       gDownloadView.view.selection.selectAll();
327       break;
328     case "cmd_copyurl":
329       selectedItems = getSelectedItems();
330       if (selectedItems.length > 0) {
331         gStatusBar.label = copyToClipboard(selectedItems);
332       }
333       break;
334     default:
335     }
336   },  
338   onEvent: function dVC_onEvent (aEvent)
339   {
340     switch (aEvent) {
341     case "tree-select":
342       this.onCommandUpdate();
343     }
344   },
346   onCommandUpdate: function dVC_onCommandUpdate ()
347   {
348     var cmds = ["cmd_properties", "cmd_pause", "cmd_cancel", "cmd_remove",
349                 "cmd_copyurl", "cmd_openfile", "cmd_showinshell"];
350     for (var command in cmds)
351       goUpdateCommand(cmds[command]);
352   }
355 function getSelectedItem()
357   if (gDownloadView.currentIndex != -1)
358     return gDownloadView.contentView.getItemAtIndex(gDownloadView.currentIndex);
359   return null;
362 function getSelectedItems()
364   var items = [];
365   var k = 0;
367   var selection = gDownloadView.view.selection;
368   var rangeCount = selection.getRangeCount();
369   for (var i = 0; i < rangeCount; i++) {
370     var startIndex = {};
371     var endIndex = {};
372     selection.getRangeAt(i, startIndex, endIndex);
373     for (var j = startIndex.value; j <= endIndex.value; j++)
374       items[k++] = gDownloadView.contentView.getItemAtIndex(j);
375   }
377   return items;
380 function createLocalFile(aFilePath) 
382   const lfIID = Components.interfaces.nsILocalFile;
383   // XXXvarga We should fix the download manager to be consistent, that is,
384   // use urls instead of local paths when adding new items to the list.
385   // Once it's fixed, the code below can be removed.
386   // See bug 208113 for more details.
388   var file;
389   if (aFilePath.substring(0,5) == 'file:') {
390     file = gFileHandler.getFileFromURLSpec(aFilePath)
391                        .QueryInterface(lfIID);
392   }
393   else {
394     const lfContractID = "@mozilla.org/file/local;1";
395     file = Components.classes[lfContractID].createInstance(lfIID);
396     file.initWithPath(aFilePath);
397   }
399   return file;
402 function DLManagerShutdown()
404   try {
405     var observerService = Components.classes[kObserverServiceProgID]
406                      .getService(Components.interfaces.nsIObserverService);
407     observerService.removeObserver(dlObserver, "download-starting");
408   }
409   catch (ex) {
410   }
413 function setSortVariables(tree)
415   var node;
416   for (node = document.getElementById("Name"); node; node = node.nextSibling) {
417     if (node.getAttribute("sortActive") == "true")
418       break;
419   }
420   if (!node) {
421     node = document.getElementById("Progress");
422     node.setAttribute("sortActive", "true");
423     node.setAttribute("sortDirection", "descending");
424   }
426   tree.setAttribute("sortActive", "true");
427   tree.setAttribute("sortDirection", node.getAttribute("sortDirection"));
428   tree.setAttribute("sortResource", node.getAttribute("resource"));
431 function doSort(node)
433   if (node.localName != "treecol")
434     return;
436   var sortResource = node.getAttribute("resource");
438   var sortDirection = node.getAttribute("sortDirection");
439   sortDirection = sortDirection == "ascending" ? "descending" : "ascending";
441   try {
442     var sortService = Components.classes["@mozilla.org/xul/xul-sort-service;1"]
443                       .getService(Components.interfaces.nsIXULSortService);
444     sortService.sort(node, sortResource, sortDirection);
445   }
446   catch(ex) {
447   }
450 function copyToClipboard(selectedItems)
452   var urlArray = new Array(selectedItems.length);
453   for (var i = 0; i < selectedItems.length; ++i) {
454     urlArray[i] = selectedItems[i].firstChild.lastChild.getAttribute("label");
455   }
457   var clipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
458                                   .getService(Components.interfaces.nsIClipboardHelper);
459   clipboardHelper.copyString(urlArray.join("\n"));
461   return urlArray.join(" "); // for status text