gecko/toolkit/mozapps/downloads/content/downloads.js

854 lines
30 KiB
JavaScript

# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# ***** 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
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 2001
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Blake Ross <blakeross@telocity.com> (Original Author)
# Ben Goodger <ben@bengoodger.com> (v2.0)
# Dan Mosedale <dmose@mozilla.org>
# Fredrik Holmqvist <thesuckiestemail@yahoo.se>
# Josh Aas <josh@mozilla.com>
#
# 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 *****
///////////////////////////////////////////////////////////////////////////////
// Globals
const kObserverServiceProgID = "@mozilla.org/observer-service;1";
const kDlmgrContractID = "@mozilla.org/download-manager;1";
const nsIDownloadManager = Components.interfaces.nsIDownloadManager;
const PREF_BDM_CLOSEWHENDONE = "browser.download.manager.closeWhenDone";
const PREF_BDM_ALERTONEXEOPEN = "browser.download.manager.alertOnEXEOpen";
const PREF_BDM_RETENTION = "browser.download.manager.retention";
const nsLocalFile = Components.Constructor("@mozilla.org/file/local;1",
"nsILocalFile", "initWithPath");
var Ci = Components.interfaces;
var gDownloadManager = Components.classes[kDlmgrContractID]
.getService(nsIDownloadManager);
var gDownloadListener = null;
var gDownloadsView = null;
var gUserInterfered = false;
var gActiveDownloads = [];
// If the user has interacted with the window in a significant way, we should
// not auto-close the window. Tough UI decisions about what is "significant."
var gUserInteracted = false;
///////////////////////////////////////////////////////////////////////////////
// Utility Functions
function fireEventForElement(aElement, aEventType)
{
var e = document.createEvent("Events");
e.initEvent("download-" + aEventType, true, true);
aElement.dispatchEvent(e);
}
function createDownloadItem(aID, aFile, aImage, aTarget, aURI, aState,
aAnimated, aStatus, aProgress)
{
var dl = document.createElement("download");
dl.setAttribute("id", "dl" + aID);
dl.setAttribute("dlid", aID);
dl.setAttribute("image", aImage);
dl.setAttribute("file", aFile);
dl.setAttribute("target", aTarget);
dl.setAttribute("uri", aURI);
dl.setAttribute("state", aState);
dl.setAttribute("animated", aAnimated);
dl.setAttribute("status", aStatus);
dl.setAttribute("progress", aProgress);
return dl;
}
function getDownload(aID)
{
return document.getElementById("dl" + aID);
}
///////////////////////////////////////////////////////////////////////////////
// Start/Stop Observers
function downloadCompleted(aDownload)
{
// Wrap this in try...catch since this can be called while shutting down...
// it doesn't really matter if it fails then since well.. we're shutting down
// and there's no UI to update!
try {
// getTypeFromFile fails if it can't find a type for this file. Handle this gracefully.
try {
// Refresh the icon, so that executable icons are shown.
var mimeService = Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"].getService(Components.interfaces.nsIMIMEService);
var contentType = mimeService.getTypeFromFile(aDownload.targetFile);
var listItem = getDownload(aDownload.id)
var oldImage = listItem.getAttribute("image");
// I tack on the content-type here as a hack to bypass the cache which seems
// to be interfering despite the fact the image has 'validate="always"' set
// on it.
listItem.setAttribute("image", oldImage + "&contentType=" + contentType);
} catch (e) { }
var insertIndex = gDownloadManager.activeDownloadCount + 1;
// Remove the download from our book-keeping list and if the count
// falls to zero, update the title here, since we won't be getting
// any more progress notifications in which to do it.
for (var i = 0; i < gActiveDownloads.length; ++i) {
if (gActiveDownloads[i] == aDownload) {
gActiveDownloads.splice(i, 1);
break;
}
}
gDownloadViewController.onCommandUpdate();
if (gActiveDownloads.length == 0)
document.title = document.documentElement.getAttribute("statictitle");
}
catch (e) { }
}
function autoRemoveAndClose(aDownload)
{
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
if (aDownload && (pref.getIntPref(PREF_BDM_RETENTION) == 0)) {
// The download manager backend removes this, but we have to update the UI!
var dl = getDownload(aDownload.id);
dl.parentNode.removeChild(dl);
}
if (gDownloadManager.activeDownloadCount == 0) {
// For the moment, just use the simple heuristic that if this window was
// opened by the download process, rather than by the user, it should auto-close
// if the pref is set that way. If the user opened it themselves, it should
// not close until they explicitly close it.
var autoClose = pref.getBoolPref(PREF_BDM_CLOSEWHENDONE);
if (autoClose && (!window.opener ||
window.opener.location.href == window.location.href) &&
!gUserInteracted) {
gCloseDownloadManager();
return true;
}
}
return false;
}
// This function can be overwritten by extensions that wish to place the Download Window in
// another part of the UI, such as in a tab or a sidebar panel.
function gCloseDownloadManager()
{
window.close();
}
var gDownloadObserver = {
observe: function (aSubject, aTopic, aState)
{
switch (aTopic) {
case "dl-done":
gDownloadViewController.onCommandUpdate();
var dl = aSubject.QueryInterface(Components.interfaces.nsIDownload);
downloadCompleted(dl);
autoRemoveAndClose(dl);
break;
case "dl-failed":
case "dl-cancel":
gDownloadViewController.onCommandUpdate();
var dl = aSubject.QueryInterface(Components.interfaces.nsIDownload);
downloadCompleted(dl);
break;
case "dl-start":
// Add this download to the percentage average tally
var dl = aSubject.QueryInterface(Components.interfaces.nsIDownload);
if (getDownload(dl.id))
return;
gActiveDownloads.push(dl);
// Adding to the UI
var uri = Components.classes["@mozilla.org/network/util;1"]
.getService(Components.interfaces.nsIIOService)
.newFileURI(dl.targetFile);
var img = "moz-icon://" + uri.spec + "?size=32";
var itm = createDownloadItem(dl.id, uri.spec, img, dl.displayName,
dl.source.spec, dl.state, "",
dl.percentComplete);
gDownloadsView.insertBefore(itm, gDownloadsView.firstChild);
// switch view to it
gDownloadsView.selectedIndex = 0;
break;
}
}
};
///////////////////////////////////////////////////////////////////////////////
// Download Event Handlers
function onDownloadCancel(aEvent)
{
var selectedIndex = gDownloadsView.selectedIndex;
gDownloadManager.cancelDownload(aEvent.target.getAttribute("dlid"));
// XXXben -
// If we got here because we resumed the download, we weren't using a temp file
// because we used saveURL instead. (this is because the proper download mechanism
// employed by the helper app service isn't fully accessible yet... should be fixed...
// talk to bz...)
// the upshot is we have to delete the file if it exists.
var f = getLocalFileFromNativePathOrUrl(aEvent.target.getAttribute("file"));
if (f.exists())
f.remove(false);
gDownloadViewController.onCommandUpdate();
// now reset the richlistbox
gDownloadsView.clearSelection();
var rowCount = gDownloadsView.getRowCount();
if (selectedIndex >= rowCount)
gDownloadsView.selectedIndex = rowCount - 1;
else
gDownloadsView.selectedIndex = selectedIndex;
}
function onDownloadPause(aEvent)
{
var selectedIndex = gDownloadsView.selectedIndex;
var id = aEvent.target.getAttribute("dlid");
gDownloadManager.pauseDownload(id);
// now reset the richlistbox
gDownloadsView.clearSelection();
var rowCount = gDownloadsView.getRowCount();
if (selectedIndex >= rowCount)
gDownloadsView.selectedIndex = rowCount - 1;
else
gDownloadsView.selectedIndex = selectedIndex;
}
function onDownloadResume(aEvent)
{
var selectedIndex = gDownloadsView.selectedIndex;
gDownloadManager.resumeDownload(aEvent.target.getAttribute("dlid"));
// now reset the richlistbox
gDownloadsView.clearSelection();
var rowCount = gDownloadsView.getRowCount();
if (selectedIndex >= rowCount)
gDownloadsView.selectedIndex = rowCount - 1;
else
gDownloadsView.selectedIndex = selectedIndex;
}
function onDownloadRemove(aEvent)
{
if (aEvent.target.removable) {
var selectedIndex = gDownloadsView.selectedIndex;
gDownloadManager.removeDownload(aEvent.target.getAttribute("dlid"));
aEvent.target.parentNode.removeChild(aEvent.target);
gDownloadViewController.onCommandUpdate();
}
}
function onDownloadShow(aEvent)
{
var f = getLocalFileFromNativePathOrUrl(aEvent.target.getAttribute("file"));
if (f.exists()) {
try {
f.reveal();
} catch (ex) {
// if reveal failed for some reason (eg on unix it's not currently
// implemented), send the file: URL window rooted at the parent to
// the OS handler for that protocol
var parent = f.parent;
if (parent) {
openExternal(parent);
}
}
}
else {
var brandStrings = document.getElementById("brandStrings");
var appName = brandStrings.getString("brandShortName");
var strings = document.getElementById("downloadStrings");
var name = aEvent.target.getAttribute("target");
var message = strings.getFormattedString("fileDoesNotExistError", [name, appName]);
var title = strings.getFormattedString("fileDoesNotExistShowTitle", [name]);
var promptSvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
promptSvc.alert(window, title, message);
}
}
function onDownloadOpen(aEvent)
{
if (aEvent.type == "dblclick" && aEvent.button != 0)
return;
var download = aEvent.target;
if (download.localName == "download") {
if (download.openable) {
var f = getLocalFileFromNativePathOrUrl(aEvent.target.getAttribute("file"));
if (f.exists()) {
if (f.isExecutable()) {
var dontAsk = false;
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
try {
dontAsk = !pref.getBoolPref(PREF_BDM_ALERTONEXEOPEN);
}
catch (e) { }
if (!dontAsk) {
var strings = document.getElementById("downloadStrings");
var name = aEvent.target.getAttribute("target");
var message = strings.getFormattedString("fileExecutableSecurityWarning", [name, name]);
var title = strings.getString("fileExecutableSecurityWarningTitle");
var dontAsk = strings.getString("fileExecutableSecurityWarningDontAsk");
var promptSvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
var checkbox = { value: false };
var open = promptSvc.confirmCheck(window, title, message, dontAsk, checkbox);
if (!open)
return;
else
pref.setBoolPref(PREF_BDM_ALERTONEXEOPEN, !checkbox.value);
}
}
try {
f.launch();
} catch (ex) {
// if launch fails, try sending it through the system's external
// file: URL handler
openExternal(f);
}
}
else {
var brandStrings = document.getElementById("brandStrings");
var appName = brandStrings.getString("brandShortName");
var strings = document.getElementById("downloadStrings");
var name = aEvent.target.getAttribute("target");
var message = strings.getFormattedString("fileDoesNotExistError", [name, appName]);
var title = strings.getFormattedString("fileDoesNotExistOpenTitle", [name]);
var promptSvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
promptSvc.alert(window, title, message);
}
}
else if(download.canceledOrFailed) {
// If the user canceled this download, double clicking tries again.
fireEventForElement(download, "retry")
}
}
}
function onDownloadOpenWith(aEvent)
{
}
function onDownloadProperties(aEvent)
{
gUserInteracted = true;
window.openDialog("chrome://mozapps/content/downloads/downloadProperties.xul",
"_blank", "modal,centerscreen,chrome,resizable=no", aEvent.target.id);
}
function onDownloadAnimated(aEvent)
{
gDownloadViewController.onCommandUpdate();
}
function onDownloadRetry(aEvent)
{
var download = aEvent.target;
if (download.localName == "download")
gDownloadManager.retryDownload(download.getAttribute("dlid"));
gDownloadViewController.onCommandUpdate();
}
// This is called by the progress listener. We don't actually use the event
// system here to minimize time wastage.
var gLastComputedMean = -1;
var gLastActiveDownloads = 0;
function onUpdateProgress()
{
var numActiveDownloads = gActiveDownloads.length;
if (numActiveDownloads == 0) {
document.title = document.documentElement.getAttribute("statictitle");
gLastComputedMean = -1;
return;
}
var mean = 0;
var base = 0;
var dl = null;
for (var i = 0; i < numActiveDownloads; ++i) {
dl = gActiveDownloads[i];
// Update progress
getDownload(dl.id).setAttribute("progress", dl.percentComplete);
// Fire DOM event so that accessible value change events occur
var progressmeter = document.getAnonymousElementByAttribute(getDownload(dl.id), "anonid", "progressmeter");
var event = document.createEvent('Events');
event.initEvent('ValueChange', true, true);
progressmeter.dispatchEvent(event);
// gActiveDownloads is screwed so it's possible
// to have more files than we're really downloading.
// The good news is that those files have size==0.
// Same with files with unknown size. Their size==0.
if (dl.percentComplete < 100 && dl.size > 0) {
mean += dl.amountTransferred;
base += dl.size;
}
}
// we're not downloading anything at the moment,
// but we already downloaded something.
if (base == 0) {
mean = 100;
} else {
mean = Math.floor((mean / base) * 100);
}
if (mean != gLastComputedMean || gLastActiveDownloads != numActiveDownloads) {
gLastComputedMean = mean;
gLastActiveDownloads = numActiveDownloads;
var strings = document.getElementById("downloadStrings");
var title;
if (numActiveDownloads > 1)
title = strings.getFormattedString("downloadsTitleMultiple", [mean, numActiveDownloads]);
else
title = strings.getFormattedString("downloadsTitle", [mean]);
document.title = title;
}
}
///////////////////////////////////////////////////////////////////////////////
// Startup, Shutdown
function Startup()
{
gDownloadsView = document.getElementById("downloadView");
var db = gDownloadManager.DBConnection;
var stmt = db.createStatement("SELECT id, target, iconURL, name, source," +
"state " +
"FROM moz_downloads " +
"ORDER BY startTime DESC");
while (stmt.executeStep()) {
var i = stmt.getString(2) == "" ?
"moz-icon://" + stmt.getString(1) + "?size=32" : stmt.getString(2);
var dl = createDownloadItem(stmt.getInt64(0), stmt.getString(1), i,
stmt.getString(3), stmt.getString(4),
stmt.getInt32(5), "", "", "100");
gDownloadsView.appendChild(dl);
}
// The DownloadProgressListener (DownloadProgressListener.js) handles progress
// notifications.
var downloadStrings = document.getElementById("downloadStrings");
gDownloadListener = new DownloadProgressListener(document, downloadStrings);
gDownloadManager.addListener(gDownloadListener);
// The active downloads list is created by the front end only when the download starts,
// so we need to pre-populate it with any downloads that were already going.
var activeDownloads = gDownloadManager.activeDownloads;
while (activeDownloads.hasMoreElements()) {
var download = activeDownloads.getNext().QueryInterface(Ci.nsIDownload);
gActiveDownloads.push(download);
}
// Handlers for events generated by the UI (downloads, list view)
gDownloadsView.addEventListener("download-cancel", onDownloadCancel, false);
gDownloadsView.addEventListener("download-pause", onDownloadPause, false);
gDownloadsView.addEventListener("download-resume", onDownloadResume, false);
gDownloadsView.addEventListener("download-remove", onDownloadRemove, false);
gDownloadsView.addEventListener("download-show", onDownloadShow, false);
gDownloadsView.addEventListener("download-open", onDownloadOpen, false);
gDownloadsView.addEventListener("download-retry", onDownloadRetry, false);
gDownloadsView.addEventListener("download-animated", onDownloadAnimated, false);
gDownloadsView.addEventListener("download-properties", onDownloadProperties, false);
gDownloadsView.addEventListener("dblclick", onDownloadOpen, false);
// Set up AutoDownload display area
initAutoDownloadDisplay();
var pbi = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch2);
pbi.addObserver("browser.download.", gDownloadPrefObserver, false);
// Handlers for events generated by the Download Manager (download events)
var observerService = Components.classes[kObserverServiceProgID]
.getService(Components.interfaces.nsIObserverService);
observerService.addObserver(gDownloadObserver, "dl-done", false);
observerService.addObserver(gDownloadObserver, "dl-cancel", false);
observerService.addObserver(gDownloadObserver, "dl-failed", false);
observerService.addObserver(gDownloadObserver, "dl-start", false);
// This is for the "Clean Up" button, which requires there to be
// non-active downloads before it can be enabled.
gDownloadsView.controllers.appendController(gDownloadViewController);
// downloads can finish before Startup() does, so check if the window should close
if (!autoRemoveAndClose())
gDownloadsView.focus();
}
function Shutdown()
{
gDownloadManager.removeListener(gDownloadListener);
var pbi = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch2);
pbi.removeObserver("browser.download.", gDownloadPrefObserver);
var observerService = Components.classes[kObserverServiceProgID]
.getService(Components.interfaces.nsIObserverService);
observerService.removeObserver(gDownloadObserver, "dl-done");
observerService.removeObserver(gDownloadObserver, "dl-cancel");
observerService.removeObserver(gDownloadObserver, "dl-failed");
observerService.removeObserver(gDownloadObserver, "dl-start");
}
///////////////////////////////////////////////////////////////////////////////
// View Context Menus
var gContextMenus = [
["menuitem_pause", "menuitem_cancel", "menuseparator_properties", "menuitem_properties"],
["menuitem_open", "menuitem_show", "menuitem_remove", "menuseparator_properties", "menuitem_properties"],
["menuitem_retry", "menuitem_remove", "menuseparator_properties", "menuitem_properties"],
["menuitem_retry", "menuitem_remove", "menuseparator_properties", "menuitem_properties"],
["menuitem_resume", "menuitem_cancel", "menuseparator_properties", "menuitem_properties"]
];
function buildContextMenu(aEvent)
{
if (aEvent.target.id != "downloadContextMenu")
return false;
var popup = document.getElementById("downloadContextMenu");
while (popup.hasChildNodes())
popup.removeChild(popup.firstChild);
if (gDownloadsView.selectedItem) {
var idx = parseInt(gDownloadsView.selectedItem.getAttribute("state"));
if (idx < 0)
idx = 0;
var menus = gContextMenus[idx];
for (var i = 0; i < menus.length; ++i)
popup.appendChild(document.getElementById(menus[i]).cloneNode(true));
return true;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
// Drag and Drop
var gDownloadDNDObserver =
{
onDragOver: function (aEvent, aFlavour, aDragSession)
{
aDragSession.canDrop = true;
},
onDrop: function(aEvent, aXferData, aDragSession)
{
var split = aXferData.data.split("\n");
var url = split[0];
if (url != aXferData.data) { //do nothing, not a valid URL
var name = split[1];
saveURL(url, name, null, true, true);
}
},
_flavourSet: null,
getSupportedFlavours: function ()
{
if (!this._flavourSet) {
this._flavourSet = new FlavourSet();
this._flavourSet.appendFlavour("text/x-moz-url");
this._flavourSet.appendFlavour("text/unicode");
}
return this._flavourSet;
}
}
///////////////////////////////////////////////////////////////////////////////
// Command Updating and Command Handlers
var gDownloadViewController = {
supportsCommand: function (aCommand)
{
var commandNode = document.getElementById(aCommand);
return commandNode && commandNode.parentNode == document.getElementById("downloadsCommands");
},
isCommandEnabled: function (aCommand)
{
if (!window.gDownloadsView)
return false;
switch (aCommand) {
case "cmd_cleanUp":
return gDownloadManager.canCleanUp;
case "cmd_remove":
return gDownloadsView.selectedItem != null;
}
return false;
},
doCommand: function (aCommand)
{
if (this.isCommandEnabled(aCommand))
this.commands[aCommand](gDownloadsView.selectedItem);
},
onCommandUpdate: function ()
{
var downloadsCommands = document.getElementById("downloadsCommands");
for (var i = 0; i < downloadsCommands.childNodes.length; ++i)
this.updateCommand(downloadsCommands.childNodes[i]);
},
updateCommand: function (command)
{
if (this.isCommandEnabled(command.id))
command.removeAttribute("disabled");
else
command.setAttribute("disabled", "true");
},
commands: {
cmd_cleanUp: function() {
gDownloadManager.cleanUp();
// Update UI
for (var i = gDownloadsView.children.length - 1; i >= 0; --i) {
var elm = gDownloadsView.children[i];
var state = elm.getAttribute("state");
if (state != nsIDownloadManager.DOWNLOAD_NOTSTARTED &&
state != nsIDownloadManager.DOWNLOAD_DOWNLOADING &&
state != nsIDownloadManager.DOWNLOAD_PAUSED)
gDownloadsView.removeChild(gDownloadsView.children[i]);
}
gDownloadViewController.onCommandUpdate();
},
cmd_remove: function(aSelectedItem) {
fireEventForElement(aSelectedItem, 'remove');
}
}
};
function onDownloadShowInfo()
{
if (gDownloadsView.selectedItem)
fireEventForElement(gDownloadsView.selectedItem, "properties");
}
function initAutoDownloadDisplay()
{
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var autodownload = pref.getBoolPref("browser.download.useDownloadDir");
if (autodownload) {
var autodownloadInfo = document.getElementById("autodownloadInfo");
autodownloadInfo.hidden = false;
var autodownloadSpring = document.getElementById("autodownloadSpring");
autodownloadSpring.hidden = true;
function getSpecialFolderKey(aFolderType)
{
if (aFolderType == "Desktop")
return "Desk";
if (aFolderType != "Downloads")
throw "ASSERTION FAILED: folder type should be 'Desktop' or 'Downloads'";
#ifdef XP_WIN
return "Pers";
#else
#ifdef XP_MACOSX
return "UsrDocs";
#else
return "Home";
#endif
#endif
}
function getDownloadsFolder(aFolder)
{
var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties);
var dir = fileLocator.get(getSpecialFolderKey(aFolder), Components.interfaces.nsILocalFile);
var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
.getService(Components.interfaces.nsIStringBundleService);
bundle = bundle.createBundle("chrome://mozapps/locale/downloads/unknownContentType.properties");
var description = bundle.GetStringFromName("myDownloads");
if (aFolder != "Desktop")
dir.append(description);
return dir;
}
var displayName = null;
var folder;
switch (pref.getIntPref("browser.download.folderList")) {
case 0:
folder = getDownloadsFolder("Desktop");
displayName = document.getElementById("downloadStrings").getString("displayNameDesktop");
break;
case 1:
folder = getDownloadsFolder("Downloads");
break;
case 2:
folder = pref.getComplexValue("browser.download.dir", Components.interfaces.nsILocalFile);
break;
}
if (folder) {
var ioServ = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var fph = ioServ.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
var mozIconURI = "moz-icon://" + fph.getURLSpecFromFile(folder) + "?size=16";
var folderIcon = document.getElementById("saveToFolder")
folderIcon.image = mozIconURI;
var folderName = document.getElementById("saveToFolder");
folderName.label = displayName || folder.leafName;
folderName.setAttribute("path", folder.path);
}
}
else {
var autodownloadInfo = document.getElementById("autodownloadInfo");
autodownloadInfo.hidden = true;
var autodownloadSpring = document.getElementById("autodownloadSpring");
autodownloadSpring.hidden = false;
}
}
var gDownloadPrefObserver = {
observe: function (aSubject, aTopic, aData)
{
if (aTopic == "nsPref:changed") {
switch(aData) {
case "browser.download.folderList":
case "browser.download.useDownloadDir":
case "browser.download.dir":
initAutoDownloadDisplay();
}
}
}
};
function onDownloadShowFolder()
{
var folderName = document.getElementById("saveToFolder");
var dir = getLocalFileFromNativePathOrUrl(folderName.getAttribute("path"));
if (!dir.exists())
dir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0755);
try {
dir.reveal();
} catch (ex) {
// if nsILocalFile::Reveal failed (eg it currently just returns an
// error on unix), just open the folder in a browser window
openExternal(dir);
}
}
function openExternal(aFile)
{
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newFileURI(aFile);
var protocolSvc =
Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
.getService(Components.interfaces.nsIExternalProtocolService);
protocolSvc.loadUrl(uri);
return;
}
// we should be using real URLs all the time, but until
// bug 239948 is fully fixed, this will do...
function getLocalFileFromNativePathOrUrl(aPathOrUrl)
{
if (aPathOrUrl.substring(0,7) == "file://") {
// if this is a URL, get the file from that
ioSvc = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
// XXX it's possible that using a null char-set here is bad
const fileUrl = ioSvc.newURI(aPathOrUrl, null, null).
QueryInterface(Components.interfaces.nsIFileURL);
return fileUrl.file.clone().
QueryInterface(Components.interfaces.nsILocalFile);
} else {
// if it's a pathname, create the nsILocalFile directly
var f = new nsLocalFile(aPathOrUrl);
return f;
}
}