!import
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 ***** */
40
41 const NC_NS = "http://home.netscape.com/NC-rdf#";
42
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));
53
54 const dlObserver = {
observe
55 observe: function(subject, topic, state) {
56 if (topic != "download-starting") return;
57 selectDownload(subject.QueryInterface(Components.interfaces.nsIDownload));
58 }
59 };
60
selectDownload
61 function selectDownload(aDownload)
62 {
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);
67 }
68
DLManagerStartup
69 function DLManagerStartup()
70 {
71 if (!window.arguments.length)
72 return;
73
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 }
81
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");
87
88 gDownloadView = document.getElementById("downloadView");
89 setSortVariables(gDownloadView);
90
91 const dlmgrContractID = "@mozilla.org/download-manager;1";
92 const dlmgrIID = Components.interfaces.nsIDownloadManager;
93 gDownloadManager = Components.classes[dlmgrContractID].getService(dlmgrIID);
94
95 const ioSvcContractID = "@mozilla.org/network/io-service;1";
96 const ioSvcIID = Components.interfaces.nsIIOService;
97 var ioService = Components.classes[ioSvcContractID].getService(ioSvcIID);
98
99 const fileHandlerIID = Components.interfaces.nsIFileProtocolHandler;
100 gFileHandler = ioService.getProtocolHandler("file")
101 .QueryInterface(fileHandlerIID);
102
103 var ds = window.arguments[0];
104 gDownloadView.database.AddDataSource(ds);
105 gDownloadView.builder.rebuild();
106 window.setTimeout(onRebuild, 0);
107
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;
118 }
119
onRebuild
120 function onRebuild() {
121 gDownloadView.controllers.appendController(downloadViewController);
122 gDownloadView.focus();
123
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 }
134 }
135
onSelect
136 function onSelect(aEvent) {
137 if (!gStatusBar)
138 gStatusBar = document.getElementById("statusbar-text");
139
140 var selectionCount = gDownloadView.view.selection.count;
141 if (selectionCount == 1)
142 gStatusBar.label = createLocalFile(getSelectedItem().id).path;
143 else
144 gStatusBar.label = "";
145
146 window.updateCommands("tree-select");
147 }
148
onTrigger
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');
156 }
157
158 var downloadViewController = {
dVC_supportsCommand
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 },
174
dVC_isCommandEnabled
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;
180
181 var selectedItem = getSelectedItem();
182 var isDownloading = selectedItem && gDownloadManager.getDownload(selectedItem.id);
183
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 },
213
dVC_doCommand
214 doCommand: function dVC_doCommand (aCommand)
215 {
216 var selectedItem, selectedItems;
217 var file, i;
218
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);
268
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();
299
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();
308
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 },
337
dVC_onEvent
338 onEvent: function dVC_onEvent (aEvent)
339 {
340 switch (aEvent) {
341 case "tree-select":
342 this.onCommandUpdate();
343 }
344 },
345
dVC_onCommandUpdate
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 }
353 };
354
getSelectedItem
355 function getSelectedItem()
356 {
357 if (gDownloadView.currentIndex != -1)
358 return gDownloadView.contentView.getItemAtIndex(gDownloadView.currentIndex);
359 return null;
360 }
361
getSelectedItems
362 function getSelectedItems()
363 {
364 var items = [];
365 var k = 0;
366
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 }
376
377 return items;
378 }
379
createLocalFile
380 function createLocalFile(aFilePath)
381 {
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.
387
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 }
398
399 return file;
400 }
401
DLManagerShutdown
402 function DLManagerShutdown()
403 {
404 try {
405 var observerService = Components.classes[kObserverServiceProgID]
406 .getService(Components.interfaces.nsIObserverService);
407 observerService.removeObserver(dlObserver, "download-starting");
408 }
409 catch (ex) {
410 }
411 }
412
setSortVariables
413 function setSortVariables(tree)
414 {
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 }
425
426 tree.setAttribute("sortActive", "true");
427 tree.setAttribute("sortDirection", node.getAttribute("sortDirection"));
428 tree.setAttribute("sortResource", node.getAttribute("resource"));
429 }
430
doSort
431 function doSort(node)
432 {
433 if (node.localName != "treecol")
434 return;
435
436 var sortResource = node.getAttribute("resource");
437
438 var sortDirection = node.getAttribute("sortDirection");
439 sortDirection = sortDirection == "ascending" ? "descending" : "ascending";
440
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 }
448 }
449
copyToClipboard
450 function copyToClipboard(selectedItems)
451 {
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 }
456
457 var clipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
458 .getService(Components.interfaces.nsIClipboardHelper);
459 clipboardHelper.copyString(urlArray.join("\n"));
460
461 return urlArray.join(" "); // for status text
462 }