browser/metro/components/HelperAppDialog.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 const Cc = Components.classes;
michael@0 6 const Ci = Components.interfaces;
michael@0 7 const Cu = Components.utils;
michael@0 8 const Cr = Components.results;
michael@0 9
michael@0 10 const PREF_BD_USEDOWNLOADDIR = "browser.download.useDownloadDir";
michael@0 11 const URI_GENERIC_ICON_DOWNLOAD = "chrome://browser/skin/images/alert-downloads-30.png";
michael@0 12
michael@0 13 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 14 Cu.import("resource://gre/modules/Services.jsm");
michael@0 15 Cu.import("resource://gre/modules/DownloadUtils.jsm");
michael@0 16
michael@0 17 XPCOMUtils.defineLazyGetter(this, "ContentUtil", function() {
michael@0 18 Cu.import("resource:///modules/ContentUtil.jsm");
michael@0 19 return ContentUtil;
michael@0 20 });
michael@0 21 XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
michael@0 22 "resource://gre/modules/Downloads.jsm");
michael@0 23 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
michael@0 24 "resource://gre/modules/FileUtils.jsm");
michael@0 25 XPCOMUtils.defineLazyModuleGetter(this, "Task",
michael@0 26 "resource://gre/modules/Task.jsm");
michael@0 27
michael@0 28 // -----------------------------------------------------------------------
michael@0 29 // HelperApp Launcher Dialog
michael@0 30 // -----------------------------------------------------------------------
michael@0 31
michael@0 32 function HelperAppLauncherDialog() { }
michael@0 33
michael@0 34 HelperAppLauncherDialog.prototype = {
michael@0 35 classID: Components.ID("{e9d277a0-268a-4ec2-bb8c-10fdf3e44611}"),
michael@0 36 QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
michael@0 37
michael@0 38 show: function hald_show(aLauncher, aContext, aReason) {
michael@0 39 // Check to see if we can open this file or not
michael@0 40 // If the file is an executable then launchWithApplication will fail in
michael@0 41 // /uriloader nsMIMEInfoWin.cpp code. So always download in that case.
michael@0 42 if (aLauncher.MIMEInfo.hasDefaultHandler && !aLauncher.targetFileIsExecutable) {
michael@0 43 aLauncher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.useSystemDefault;
michael@0 44 aLauncher.launchWithApplication(null, false);
michael@0 45 } else {
michael@0 46 let wasClicked = false;
michael@0 47 this._showDownloadInfobar(aLauncher);
michael@0 48 }
michael@0 49 },
michael@0 50
michael@0 51 _getDownloadSize: function dv__getDownloadSize (aSize) {
michael@0 52 let displaySize = DownloadUtils.convertByteUnits(aSize);
michael@0 53 // displaySize[0] is formatted size, displaySize[1] is units
michael@0 54 if (aSize > 0)
michael@0 55 return displaySize.join("");
michael@0 56 else {
michael@0 57 let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
michael@0 58 return browserBundle.GetStringFromName("downloadsUnknownSize");
michael@0 59 }
michael@0 60 },
michael@0 61
michael@0 62 _getChromeWindow: function (aWindow) {
michael@0 63 let chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 64 .getInterface(Ci.nsIWebNavigation)
michael@0 65 .QueryInterface(Ci.nsIDocShellTreeItem)
michael@0 66 .rootTreeItem
michael@0 67 .QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 68 .getInterface(Ci.nsIDOMWindow)
michael@0 69 .QueryInterface(Ci.nsIDOMChromeWindow);
michael@0 70 return chromeWin;
michael@0 71 },
michael@0 72
michael@0 73 _showDownloadInfobar: function do_showDownloadInfobar(aLauncher) {
michael@0 74 let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
michael@0 75
michael@0 76 let runButtonText =
michael@0 77 browserBundle.GetStringFromName("downloadOpen");
michael@0 78 let saveButtonText =
michael@0 79 browserBundle.GetStringFromName("downloadSave");
michael@0 80 let cancelButtonText =
michael@0 81 browserBundle.GetStringFromName("downloadCancel");
michael@0 82
michael@0 83 let buttons = [
michael@0 84 {
michael@0 85 isDefault: true,
michael@0 86 label: runButtonText,
michael@0 87 accessKey: "",
michael@0 88 callback: function() {
michael@0 89 aLauncher.saveToDisk(null, false);
michael@0 90 Services.obs.notifyObservers(aLauncher.targetFile, "dl-run", "true");
michael@0 91 }
michael@0 92 },
michael@0 93 {
michael@0 94 label: saveButtonText,
michael@0 95 accessKey: "",
michael@0 96 callback: function() {
michael@0 97 aLauncher.saveToDisk(null, false);
michael@0 98 Services.obs.notifyObservers(aLauncher.targetFile, "dl-run", "false");
michael@0 99 }
michael@0 100 },
michael@0 101 {
michael@0 102 label: cancelButtonText,
michael@0 103 accessKey: "",
michael@0 104 callback: function() { aLauncher.cancel(Cr.NS_BINDING_ABORTED); }
michael@0 105 }
michael@0 106 ];
michael@0 107
michael@0 108 let window = Services.wm.getMostRecentWindow("navigator:browser");
michael@0 109 let chromeWin = this._getChromeWindow(window).wrappedJSObject;
michael@0 110 let notificationBox = chromeWin.Browser.getNotificationBox();
michael@0 111 let document = notificationBox.ownerDocument;
michael@0 112 let downloadSize = this._getDownloadSize(aLauncher.contentLength);
michael@0 113
michael@0 114 let msg = browserBundle.GetStringFromName("alertDownloadSave2");
michael@0 115
michael@0 116 let fragment = ContentUtil.populateFragmentFromString(
michael@0 117 document.createDocumentFragment(),
michael@0 118 msg,
michael@0 119 {
michael@0 120 text: aLauncher.suggestedFileName,
michael@0 121 className: "download-filename-text"
michael@0 122 },
michael@0 123 {
michael@0 124 text: downloadSize,
michael@0 125 className: "download-size-text"
michael@0 126 },
michael@0 127 {
michael@0 128 text: aLauncher.source.host,
michael@0 129 className: "download-host-text"
michael@0 130 }
michael@0 131 );
michael@0 132 let newBar = notificationBox.appendNotification("",
michael@0 133 "save-download",
michael@0 134 URI_GENERIC_ICON_DOWNLOAD,
michael@0 135 notificationBox.PRIORITY_WARNING_HIGH,
michael@0 136 buttons);
michael@0 137 let messageContainer = document.getAnonymousElementByAttribute(newBar, "anonid", "messageText");
michael@0 138 messageContainer.appendChild(fragment);
michael@0 139 },
michael@0 140
michael@0 141 promptForSaveToFile: function hald_promptForSaveToFile(aLauncher, aContext, aDefaultFile, aSuggestedFileExt, aForcePrompt) {
michael@0 142 throw new Components.Exception("Async version must be used", Cr.NS_ERROR_NOT_AVAILABLE);
michael@0 143 },
michael@0 144
michael@0 145 promptForSaveToFileAsync: function hald_promptForSaveToFileAsync(aLauncher, aContext, aDefaultFile, aSuggestedFileExt, aForcePrompt) {
michael@0 146 let file = null;
michael@0 147 let prefs = Services.prefs;
michael@0 148
michael@0 149 Task.spawn(function() {
michael@0 150 if (!aForcePrompt) {
michael@0 151 // Check to see if the user wishes to auto save to the default download
michael@0 152 // folder without prompting. Note that preference might not be set.
michael@0 153 let autodownload = true;
michael@0 154 try {
michael@0 155 autodownload = prefs.getBoolPref(PREF_BD_USEDOWNLOADDIR);
michael@0 156 } catch (e) { }
michael@0 157
michael@0 158 if (autodownload) {
michael@0 159 // Retrieve the user's preferred download directory
michael@0 160 let preferredDir = yield Downloads.getPreferredDownloadsDirectory();
michael@0 161 let defaultFolder = new FileUtils.File(preferredDir);
michael@0 162
michael@0 163 try {
michael@0 164 file = this.validateLeafName(defaultFolder, aDefaultFile, aSuggestedFileExt);
michael@0 165 }
michael@0 166 catch (e) {
michael@0 167 }
michael@0 168
michael@0 169 // Check to make sure we have a valid directory, otherwise, prompt
michael@0 170 if (file) {
michael@0 171 aLauncher.saveDestinationAvailable(file);
michael@0 172 return;
michael@0 173 }
michael@0 174 }
michael@0 175 }
michael@0 176
michael@0 177 // Use file picker to show dialog.
michael@0 178 let picker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
michael@0 179 let windowTitle = "";
michael@0 180 let parent = aContext.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
michael@0 181 picker.init(parent, windowTitle, Ci.nsIFilePicker.modeSave);
michael@0 182 picker.defaultString = aDefaultFile;
michael@0 183
michael@0 184 if (aSuggestedFileExt) {
michael@0 185 // aSuggestedFileExtension includes the period, so strip it
michael@0 186 picker.defaultExtension = aSuggestedFileExt.substring(1);
michael@0 187 }
michael@0 188 else {
michael@0 189 try {
michael@0 190 picker.defaultExtension = aLauncher.MIMEInfo.primaryExtension;
michael@0 191 }
michael@0 192 catch (e) { }
michael@0 193 }
michael@0 194
michael@0 195 let wildCardExtension = "*";
michael@0 196 if (aSuggestedFileExt) {
michael@0 197 wildCardExtension += aSuggestedFileExt;
michael@0 198 picker.appendFilter(aLauncher.MIMEInfo.description, wildCardExtension);
michael@0 199 }
michael@0 200
michael@0 201 picker.appendFilters(Ci.nsIFilePicker.filterAll);
michael@0 202
michael@0 203 // Default to lastDir if it is valid, otherwise use the user's preferred
michael@0 204 // downloads directory. getPreferredDownloadsDirectory should always
michael@0 205 // return a valid directory string, so we can safely default to it.
michael@0 206 let preferredDir = yield Downloads.getPreferredDownloadsDirectory();
michael@0 207 picker.displayDirectory = new FileUtils.File(preferredDir);
michael@0 208
michael@0 209 // The last directory preference may not exist, which will throw.
michael@0 210 try {
michael@0 211 let lastDir = prefs.getComplexValue("browser.download.lastDir", Ci.nsILocalFile);
michael@0 212 if (isUsableDirectory(lastDir))
michael@0 213 picker.displayDirectory = lastDir;
michael@0 214 }
michael@0 215 catch (e) { }
michael@0 216
michael@0 217 picker.open(function(aResult) {
michael@0 218 if (aResult == Ci.nsIFilePicker.returnCancel) {
michael@0 219 // null result means user cancelled.
michael@0 220 aLauncher.saveDestinationAvailable(null);
michael@0 221 return;
michael@0 222 }
michael@0 223
michael@0 224 // Be sure to save the directory the user chose through the Save As...
michael@0 225 // dialog as the new browser.download.dir since the old one
michael@0 226 // didn't exist.
michael@0 227 file = picker.file;
michael@0 228
michael@0 229 if (file) {
michael@0 230 try {
michael@0 231 // Remove the file so that it's not there when we ensure non-existence later;
michael@0 232 // this is safe because for the file to exist, the user would have had to
michael@0 233 // confirm that he wanted the file overwritten.
michael@0 234 if (file.exists())
michael@0 235 file.remove(false);
michael@0 236 }
michael@0 237 catch (e) { }
michael@0 238 let newDir = file.parent.QueryInterface(Ci.nsILocalFile);
michael@0 239 prefs.setComplexValue("browser.download.lastDir", Ci.nsILocalFile, newDir);
michael@0 240 file = this.validateLeafName(newDir, file.leafName, null);
michael@0 241 }
michael@0 242 aLauncher.saveDestinationAvailable(file);
michael@0 243 }.bind(this));
michael@0 244 }.bind(this));
michael@0 245 },
michael@0 246
michael@0 247 validateLeafName: function hald_validateLeafName(aLocalFile, aLeafName, aFileExt) {
michael@0 248 if (!(aLocalFile && this.isUsableDirectory(aLocalFile)))
michael@0 249 return null;
michael@0 250
michael@0 251 // Remove any leading periods, since we don't want to save hidden files
michael@0 252 // automatically.
michael@0 253 aLeafName = aLeafName.replace(/^\.+/, "");
michael@0 254
michael@0 255 if (aLeafName == "")
michael@0 256 aLeafName = "unnamed" + (aFileExt ? "." + aFileExt : "");
michael@0 257 aLocalFile.append(aLeafName);
michael@0 258
michael@0 259 this.makeFileUnique(aLocalFile);
michael@0 260 return aLocalFile;
michael@0 261 },
michael@0 262
michael@0 263 makeFileUnique: function hald_makeFileUnique(aLocalFile) {
michael@0 264 try {
michael@0 265 // Note - this code is identical to that in
michael@0 266 // toolkit/content/contentAreaUtils.js.
michael@0 267 // If you are updating this code, update that code too! We can't share code
michael@0 268 // here since this is called in a js component.
michael@0 269 var collisionCount = 0;
michael@0 270 while (aLocalFile.exists()) {
michael@0 271 collisionCount++;
michael@0 272 if (collisionCount == 1) {
michael@0 273 // Append "(2)" before the last dot in (or at the end of) the filename
michael@0 274 // special case .ext.gz etc files so we don't wind up with .tar(2).gz
michael@0 275 if (aLocalFile.leafName.match(/\.[^\.]{1,3}\.(gz|bz2|Z)$/i))
michael@0 276 aLocalFile.leafName = aLocalFile.leafName.replace(/\.[^\.]{1,3}\.(gz|bz2|Z)$/i, "(2)$&");
michael@0 277 else
michael@0 278 aLocalFile.leafName = aLocalFile.leafName.replace(/(\.[^\.]*)?$/, "(2)$&");
michael@0 279 }
michael@0 280 else {
michael@0 281 // replace the last (n) in the filename with (n+1)
michael@0 282 aLocalFile.leafName = aLocalFile.leafName.replace(/^(.*\()\d+\)/, "$1" + (collisionCount+1) + ")");
michael@0 283 }
michael@0 284 }
michael@0 285 aLocalFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
michael@0 286 }
michael@0 287 catch (e) {
michael@0 288 dump("*** exception in validateLeafName: " + e + "\n");
michael@0 289
michael@0 290 if (e.result == Cr.NS_ERROR_FILE_ACCESS_DENIED)
michael@0 291 throw e;
michael@0 292
michael@0 293 if (aLocalFile.leafName == "" || aLocalFile.isDirectory()) {
michael@0 294 aLocalFile.append("unnamed");
michael@0 295 if (aLocalFile.exists())
michael@0 296 aLocalFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
michael@0 297 }
michael@0 298 }
michael@0 299 },
michael@0 300
michael@0 301 isUsableDirectory: function hald_isUsableDirectory(aDirectory) {
michael@0 302 return aDirectory.exists() && aDirectory.isDirectory() && aDirectory.isWritable();
michael@0 303 },
michael@0 304 };
michael@0 305
michael@0 306 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([HelperAppLauncherDialog]);

mercurial