Bug 559833 - "Should fix incorrect indentation of nsHelperAppDlg.js" [r=paolo]
authorChiaki Ishikawa <ishikawa@yk.rim.or.jp>
Tue, 25 May 2010 09:01:00 -0400
changeset 43115 ceeb7737c4bb
parent 43114 01f8d7c7654d
child 43116 0388c837c986
push id13625
push userCallek@gmail.com
push dateSat, 05 Jun 2010 02:02:21 +0000
treeherdermozilla-central@63b89b311461 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspaolo
bugs559833
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 559833 - "Should fix incorrect indentation of nsHelperAppDlg.js" [r=paolo]
toolkit/mozapps/downloads/nsHelperAppDlg.js
--- a/toolkit/mozapps/downloads/nsHelperAppDlg.js
+++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js
@@ -1,10 +1,11 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
 /*
-# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 # ***** 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/
 #
@@ -78,1103 +79,1105 @@ const PREF_BD_USEDOWNLOADDIR = "browser.
 const nsITimer = Components.interfaces.nsITimer;
 
 Components.utils.import("resource://gre/modules/DownloadLastDir.jsm");
 Components.utils.import("resource://gre/modules/DownloadPaths.jsm");
 
 /* ctor
  */
 function nsUnknownContentTypeDialog() {
-    // Initialize data properties.
-    this.mLauncher = null;
-    this.mContext  = null;
-    this.mSourcePath = null;
-    this.chosenApp = null;
-    this.givenDefaultApp = false;
-    this.updateSelf = true;
-    this.mTitle    = "";
+  // Initialize data properties.
+  this.mLauncher = null;
+  this.mContext  = null;
+  this.mSourcePath = null;
+  this.chosenApp = null;
+  this.givenDefaultApp = false;
+  this.updateSelf = true;
+  this.mTitle    = "";
 }
 
 nsUnknownContentTypeDialog.prototype = {
-    nsIMIMEInfo  : Components.interfaces.nsIMIMEInfo,
+  nsIMIMEInfo  : Components.interfaces.nsIMIMEInfo,
+
+  QueryInterface: function (iid) {
+    if (!iid.equals(Components.interfaces.nsIHelperAppLauncherDialog) &&
+        !iid.equals(Components.interfaces.nsITimerCallback) &&
+        !iid.equals(Components.interfaces.nsISupports)) {
+      throw Components.results.NS_ERROR_NO_INTERFACE;
+    }
+    return this;
+  },
+
+  // ---------- nsIHelperAppLauncherDialog methods ----------
+
+  // show: Open XUL dialog using window watcher.  Since the dialog is not
+  //       modal, it needs to be a top level window and the way to open
+  //       one of those is via that route).
+  show: function(aLauncher, aContext, aReason)  {
+    this.mLauncher = aLauncher;
+    this.mContext  = aContext;
+
+    const nsITimer = Components.interfaces.nsITimer;
+    this._showTimer = Components.classes["@mozilla.org/timer;1"]
+                                .createInstance(nsITimer);
+    this._showTimer.initWithCallback(this, 0, nsITimer.TYPE_ONE_SHOT);
+  },
 
-    QueryInterface: function (iid) {
-        if (!iid.equals(Components.interfaces.nsIHelperAppLauncherDialog) &&
-            !iid.equals(Components.interfaces.nsITimerCallback) &&
-            !iid.equals(Components.interfaces.nsISupports)) {
-            throw Components.results.NS_ERROR_NO_INTERFACE;
-        }
-        return this;
-    },
+  // When opening from new tab, if tab closes while dialog is opening,
+  // (which is a race condition on the XUL file being cached and the timer
+  // in nsExternalHelperAppService), the dialog gets a blur and doesn't
+  // activate the OK button.  So we wait a bit before doing opening it.
+  reallyShow: function() {
+    try {
+      var ir = this.mContext.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
+      var dwi = ir.getInterface(Components.interfaces.nsIDOMWindowInternal);
+      var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
+                         .getService(Components.interfaces.nsIWindowWatcher);
+      this.mDialog = ww.openWindow(dwi,
+                                   "chrome://mozapps/content/downloads/unknownContentType.xul",
+                                   null,
+                                   "chrome,centerscreen,titlebar,dialog=yes,dependent",
+                                   null);
+    } catch (ex) {
+      // The containing window may have gone away.  Break reference
+      // cycles and stop doing the download.
+      const NS_BINDING_ABORTED = 0x804b0002;
+      this.mLauncher.cancel(NS_BINDING_ABORTED);
+      return;
+    }
 
-    // ---------- nsIHelperAppLauncherDialog methods ----------
+    // Hook this object to the dialog.
+    this.mDialog.dialog = this;
 
-    // show: Open XUL dialog using window watcher.  Since the dialog is not
-    //       modal, it needs to be a top level window and the way to open
-    //       one of those is via that route).
-    show: function(aLauncher, aContext, aReason)  {
-      this.mLauncher = aLauncher;
-      this.mContext  = aContext;
+    // Hook up utility functions.
+    this.getSpecialFolderKey = this.mDialog.getSpecialFolderKey;
 
-      const nsITimer = Components.interfaces.nsITimer;
-      this._showTimer = Components.classes["@mozilla.org/timer;1"]
-                                  .createInstance(nsITimer);
-      this._showTimer.initWithCallback(this, 0, nsITimer.TYPE_ONE_SHOT);
-    },
+    // Watch for error notifications.
+    this.progressListener.helperAppDlg = this;
+    this.mLauncher.setWebProgressListener(this.progressListener);
+  },
+
+  // promptForSaveToFile:  Display file picker dialog and return selected file.
+  //                       This is called by the External Helper App Service
+  //                       after the ucth dialog calls |saveToDisk| with a null
+  //                       target filename (no target, therefore user must pick).
+  //
+  //                       Alternatively, if the user has selected to have all
+  //                       files download to a specific location, return that
+  //                       location and don't ask via the dialog.
+  //
+  // Note - this function is called without a dialog, so it cannot access any part
+  // of the dialog XUL as other functions on this object do.
+  promptForSaveToFile: function(aLauncher, aContext, aDefaultFile, aSuggestedFileExtension, aForcePrompt) {
+    var result = null;
+
+    this.mLauncher = aLauncher;
 
-    // When opening from new tab, if tab closes while dialog is opening,
-    // (which is a race condition on the XUL file being cached and the timer
-    // in nsExternalHelperAppService), the dialog gets a blur and doesn't
-    // activate the OK button.  So we wait a bit before doing opening it.
-    reallyShow: function() {
+    let prefs = Components.classes["@mozilla.org/preferences-service;1"]
+                          .getService(Components.interfaces.nsIPrefBranch);
+    let bundle = Components.classes["@mozilla.org/intl/stringbundle;1"].
+                            getService(Components.interfaces.nsIStringBundleService).
+                            createBundle("chrome://mozapps/locale/downloads/unknownContentType.properties");
+
+    if (!aForcePrompt) {
+      // Check to see if the user wishes to auto save to the default download
+      // folder without prompting. Note that preference might not be set.
+      let autodownload = false;
+      try {
+        autodownload = prefs.getBoolPref(PREF_BD_USEDOWNLOADDIR);
+      } catch (e) { }
+
+      if (autodownload) {
+        // Retrieve the user's default download directory
+        let dnldMgr = Components.classes["@mozilla.org/download-manager;1"]
+                                .getService(Components.interfaces.nsIDownloadManager);
+        let defaultFolder = dnldMgr.userDownloadsDirectory;
+
         try {
-          var ir = this.mContext.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
-          var dwi = ir.getInterface(Components.interfaces.nsIDOMWindowInternal);
-          var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
-                             .getService(Components.interfaces.nsIWindowWatcher);
-          this.mDialog = ww.openWindow(dwi,
-                                       "chrome://mozapps/content/downloads/unknownContentType.xul",
-                                       null,
-                                       "chrome,centerscreen,titlebar,dialog=yes,dependent",
-                                       null);
-        } catch (ex) {
-          // The containing window may have gone away.  Break reference
-          // cycles and stop doing the download.
-          const NS_BINDING_ABORTED = 0x804b0002;
-          this.mLauncher.cancel(NS_BINDING_ABORTED);
-          return;
+          result = this.validateLeafName(defaultFolder, aDefaultFile, aSuggestedFileExtension);
+        }
+        catch (ex) {
+          if (ex.result == Components.results.NS_ERROR_FILE_ACCESS_DENIED) {
+            let prompter = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
+                                      getService(Components.interfaces.nsIPromptService);
+
+            // Display error alert (using text supplied by back-end)
+            prompter.alert(this.dialog,
+                           bundle.GetStringFromName("badPermissions.title"),
+                           bundle.GetStringFromName("badPermissions"));
+
+            return;
+          }
         }
 
-        // Hook this object to the dialog.
-        this.mDialog.dialog = this;
-
-        // Hook up utility functions.
-        this.getSpecialFolderKey = this.mDialog.getSpecialFolderKey;
-
-        // Watch for error notifications.
-        this.progressListener.helperAppDlg = this;
-        this.mLauncher.setWebProgressListener(this.progressListener);
-    },
+        // Check to make sure we have a valid directory, otherwise, prompt
+        if (result)
+          return result;
+      }
+    }
 
-    // promptForSaveToFile:  Display file picker dialog and return selected file.
-    //                       This is called by the External Helper App Service
-    //                       after the ucth dialog calls |saveToDisk| with a null
-    //                       target filename (no target, therefore user must pick).
-    //
-    //                       Alternatively, if the user has selected to have all
-    //                       files download to a specific location, return that
-    //                       location and don't ask via the dialog. 
-    //
-    // Note - this function is called without a dialog, so it cannot access any part
-    // of the dialog XUL as other functions on this object do. 
-    promptForSaveToFile: function(aLauncher, aContext, aDefaultFile, aSuggestedFileExtension, aForcePrompt) {
-      var result = null;
-      
-      this.mLauncher = aLauncher;
+    // Use file picker to show dialog.
+    var nsIFilePicker = Components.interfaces.nsIFilePicker;
+    var picker = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
+    var windowTitle = bundle.GetStringFromName("saveDialogTitle");
+    var parent = aContext.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowInternal);
+    picker.init(parent, windowTitle, nsIFilePicker.modeSave);
+    picker.defaultString = aDefaultFile;
 
-      let prefs = Components.classes["@mozilla.org/preferences-service;1"]
-                            .getService(Components.interfaces.nsIPrefBranch);
-      let bundle = Components.classes["@mozilla.org/intl/stringbundle;1"].
-        getService(Components.interfaces.nsIStringBundleService).
-        createBundle("chrome://mozapps/locale/downloads/unknownContentType.properties");
+    if (aSuggestedFileExtension) {
+      // aSuggestedFileExtension includes the period, so strip it
+      picker.defaultExtension = aSuggestedFileExtension.substring(1);
+    }
+    else {
+      try {
+        picker.defaultExtension = this.mLauncher.MIMEInfo.primaryExtension;
+      }
+      catch (ex) { }
+    }
 
-      if (!aForcePrompt) {
-        // Check to see if the user wishes to auto save to the default download
-        // folder without prompting. Note that preference might not be set.
-        let autodownload = false;
-        try {
-          autodownload = prefs.getBoolPref(PREF_BD_USEDOWNLOADDIR);
-        } catch (e) { }
-      
-        if (autodownload) {
-          // Retrieve the user's default download directory
-          let dnldMgr = Components.classes["@mozilla.org/download-manager;1"]
-                                  .getService(Components.interfaces.nsIDownloadManager);
-          let defaultFolder = dnldMgr.userDownloadsDirectory;
+    var wildCardExtension = "*";
+    if (aSuggestedFileExtension) {
+      wildCardExtension += aSuggestedFileExtension;
+      picker.appendFilter(this.mLauncher.MIMEInfo.description, wildCardExtension);
+    }
 
-          try {
-            result = this.validateLeafName(defaultFolder, aDefaultFile, aSuggestedFileExtension);
-          }
-          catch (ex) {
-            if (ex.result == Components.results.NS_ERROR_FILE_ACCESS_DENIED) {
-              let prompter = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
-                getService(Components.interfaces.nsIPromptService);
+    picker.appendFilters( nsIFilePicker.filterAll );
 
-              // Display error alert (using text supplied by back-end)
-              prompter.alert(this.dialog,
-                             bundle.GetStringFromName("badPermissions.title"),
-                             bundle.GetStringFromName("badPermissions"));
-
-              return;
-            }
-          }
+    // Default to lastDir if it is valid, otherwise use the user's default
+    // downloads directory.  userDownloadsDirectory should always return a
+    // valid directory, so we can safely default to it.
+    var dnldMgr = Components.classes["@mozilla.org/download-manager;1"]
+                            .getService(Components.interfaces.nsIDownloadManager);
+    picker.displayDirectory = dnldMgr.userDownloadsDirectory;
 
-          // Check to make sure we have a valid directory, otherwise, prompt
-          if (result)
-            return result;
-        }
-      }
-      
-      // Use file picker to show dialog.
-      var nsIFilePicker = Components.interfaces.nsIFilePicker;
-      var picker = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
-      var windowTitle = bundle.GetStringFromName("saveDialogTitle");
-      var parent = aContext.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowInternal);
-      picker.init(parent, windowTitle, nsIFilePicker.modeSave);
-      picker.defaultString = aDefaultFile;
+    // The last directory preference may not exist, which will throw.
+    try {
+      var lastDir = gDownloadLastDir.file;
+      if (isUsableDirectory(lastDir))
+        picker.displayDirectory = lastDir;
+    }
+    catch (ex) {
+    }
+
+    if (picker.show() == nsIFilePicker.returnCancel) {
+      // null result means user cancelled.
+      return null;
+    }
 
-      if (aSuggestedFileExtension) {
-        // aSuggestedFileExtension includes the period, so strip it
-        picker.defaultExtension = aSuggestedFileExtension.substring(1);
-      } 
-      else {
-        try {
-          picker.defaultExtension = this.mLauncher.MIMEInfo.primaryExtension;
-        } 
-        catch (ex) { }
-      }
-
-      var wildCardExtension = "*";
-      if (aSuggestedFileExtension) {
-        wildCardExtension += aSuggestedFileExtension;
-        picker.appendFilter(this.mLauncher.MIMEInfo.description, wildCardExtension);
-      }
-
-      picker.appendFilters( nsIFilePicker.filterAll );
+    // Be sure to save the directory the user chose through the Save As...
+    // dialog  as the new browser.download.dir since the old one
+    // didn't exist.
+    result = picker.file;
 
-      // Default to lastDir if it is valid, otherwise use the user's default
-      // downloads directory.  userDownloadsDirectory should always return a
-      // valid directory, so we can safely default to it.
-      var dnldMgr = Components.classes["@mozilla.org/download-manager;1"]
-                              .getService(Components.interfaces.nsIDownloadManager);
-      picker.displayDirectory = dnldMgr.userDownloadsDirectory;
-
-      // The last directory preference may not exist, which will throw.
+    if (result) {
       try {
-        var lastDir = gDownloadLastDir.file;
-        if (isUsableDirectory(lastDir))
-          picker.displayDirectory = lastDir;
+        // Remove the file so that it's not there when we ensure non-existence later;
+        // this is safe because for the file to exist, the user would have had to
+        // confirm that he wanted the file overwritten.
+        if (result.exists())
+          result.remove(false);
       }
-      catch (ex) {
-      }
+      catch (e) { }
+      var newDir = result.parent.QueryInterface(Components.interfaces.nsILocalFile);
 
-      if (picker.show() == nsIFilePicker.returnCancel) {
-        // null result means user cancelled.
-        return null;
-      }
+      // Do not store the last save directory as a pref inside the private browsing mode
+      gDownloadLastDir.file = newDir;
 
-      // Be sure to save the directory the user chose through the Save As... 
-      // dialog  as the new browser.download.dir since the old one
-      // didn't exist.
-      result = picker.file;
+      result = this.validateLeafName(newDir, result.leafName, null);
+    }
+    return result;
+  },
 
-      if (result) {
-        try {
-          // Remove the file so that it's not there when we ensure non-existence later;
-          // this is safe because for the file to exist, the user would have had to
-          // confirm that he wanted the file overwritten.
-          if (result.exists())
-            result.remove(false);
-        }
-        catch (e) { }
-        var newDir = result.parent.QueryInterface(Components.interfaces.nsILocalFile);
-
-        // Do not store the last save directory as a pref inside the private browsing mode
-        gDownloadLastDir.file = newDir;
-
-        result = this.validateLeafName(newDir, result.leafName, null);
-      }
-      return result;
-    },
+  /**
+   * Ensures that a local folder/file combination does not already exist in
+   * the file system (or finds such a combination with a reasonably similar
+   * leaf name), creates the corresponding file, and returns it.
+   *
+   * @param   aLocalFile
+   *          the folder where the file resides
+   * @param   aLeafName
+   *          the string name of the file (may be empty if no name is known,
+   *          in which case a name will be chosen)
+   * @param   aFileExt
+   *          the extension of the file, if one is known; this will be ignored
+   *          if aLeafName is non-empty
+   * @returns nsILocalFile
+   *          the created file
+   */
+  validateLeafName: function (aLocalFile, aLeafName, aFileExt)
+  {
+    if (!(aLocalFile && isUsableDirectory(aLocalFile)))
+      return null;
 
-    /**
-     * Ensures that a local folder/file combination does not already exist in
-     * the file system (or finds such a combination with a reasonably similar
-     * leaf name), creates the corresponding file, and returns it.
-     *
-     * @param   aLocalFile
-     *          the folder where the file resides
-     * @param   aLeafName
-     *          the string name of the file (may be empty if no name is known,
-     *          in which case a name will be chosen)
-     * @param   aFileExt
-     *          the extension of the file, if one is known; this will be ignored
-     *          if aLeafName is non-empty
-     * @returns nsILocalFile
-     *          the created file
-     */
-    validateLeafName: function (aLocalFile, aLeafName, aFileExt)
-    {
-      if (!(aLocalFile && isUsableDirectory(aLocalFile)))
-        return null;
+    // Remove any leading periods, since we don't want to save hidden files
+    // automatically.
+    aLeafName = aLeafName.replace(/^\.+/, "");
 
-      // Remove any leading periods, since we don't want to save hidden files
-      // automatically.
-      aLeafName = aLeafName.replace(/^\.+/, "");
+    if (aLeafName == "")
+      aLeafName = "unnamed" + (aFileExt ? "." + aFileExt : "");
+    aLocalFile.append(aLeafName);
 
-      if (aLeafName == "")
-        aLeafName = "unnamed" + (aFileExt ? "." + aFileExt : "");
-      aLocalFile.append(aLeafName);
-
-      var createdFile = DownloadPaths.createNiceUniqueFile(aLocalFile);
+    var createdFile = DownloadPaths.createNiceUniqueFile(aLocalFile);
 
 #ifdef XP_WIN
-      let ext;
-      try {
-        // We can fail here if there's no primary extension set
-        ext = "." + this.mLauncher.MIMEInfo.primaryExtension;
-      } catch (e) { }
+    let ext;
+    try {
+      // We can fail here if there's no primary extension set
+      ext = "." + this.mLauncher.MIMEInfo.primaryExtension;
+    } catch (e) { }
 
-      // Append a file extension if it's an executable that doesn't have one
-      // but make sure we actually have an extension to add
-      let leaf = createdFile.leafName;
-      if (ext && leaf.slice(-ext.length) != ext && createdFile.isExecutable()) {
-        createdFile.remove(false);
-        aLocalFile.leafName = leaf + ext;
-        createdFile = DownloadPaths.createNiceUniqueFile(aLocalFile);
-      }
+    // Append a file extension if it's an executable that doesn't have one
+    // but make sure we actually have an extension to add
+    let leaf = createdFile.leafName;
+    if (ext && leaf.slice(-ext.length) != ext && createdFile.isExecutable()) {
+      createdFile.remove(false);
+      aLocalFile.leafName = leaf + ext;
+      createdFile = DownloadPaths.createNiceUniqueFile(aLocalFile);
+    }
 #endif
 
-      return createdFile;
-    },
-
-    // ---------- implementation methods ----------
-
-    // Web progress listener so we can detect errors while mLauncher is
-    // streaming the data to a temporary file.
-    progressListener: {
-        // Implementation properties.
-        helperAppDlg: null,
-
-        // nsIWebProgressListener methods.
-        // Look for error notifications and display alert to user.
-        onStatusChange: function( aWebProgress, aRequest, aStatus, aMessage ) {
-            if ( aStatus != Components.results.NS_OK ) {
-                // Get prompt service.
-                var prompter = Components.classes[ "@mozilla.org/embedcomp/prompt-service;1" ]
-                                   .getService( Components.interfaces.nsIPromptService );
-                // Display error alert (using text supplied by back-end).
-                prompter.alert( this.dialog, this.helperAppDlg.mTitle, aMessage );
+    return createdFile;
+  },
 
-                // Close the dialog.
-                this.helperAppDlg.onCancel();
-                if ( this.helperAppDlg.mDialog ) {
-                    this.helperAppDlg.mDialog.close();
-                }
-            }
-        },
-
-        // Ignore onProgressChange, onProgressChange64, onStateChange, onLocationChange, onSecurityChange, and onRefreshAttempted notifications.
-        onProgressChange: function( aWebProgress,
-                                    aRequest,
-                                    aCurSelfProgress,
-                                    aMaxSelfProgress,
-                                    aCurTotalProgress,
-                                    aMaxTotalProgress ) {
-        },
-
-        onProgressChange64: function( aWebProgress,
-                                      aRequest,
-                                      aCurSelfProgress,
-                                      aMaxSelfProgress,
-                                      aCurTotalProgress,
-                                      aMaxTotalProgress ) {
-        },
-
-
+  // ---------- implementation methods ----------
 
-        onStateChange: function( aWebProgress, aRequest, aStateFlags, aStatus ) {
-        },
-
-        onLocationChange: function( aWebProgress, aRequest, aLocation ) {
-        },
-
-        onSecurityChange: function( aWebProgress, aRequest, state ) {
-        },
-
-        onRefreshAttempted: function( aWebProgress, aURI, aDelay, aSameURI ) {
-          return true;
-        }
-    },
-
-    // initDialog:  Fill various dialog fields with initial content.
-    initDialog : function() {
-      // Put file name in window title.
-      var suggestedFileName = this.mLauncher.suggestedFileName;
-
-      // Some URIs do not implement nsIURL, so we can't just QI.
-      var url   = this.mLauncher.source;
-      var fname = "";
-      var iconPath = "goat";
-      this.mSourcePath = url.prePath;
-      if (url instanceof Components.interfaces.nsIURL) {
-          // A url, use file name from it.
-          fname = iconPath = url.fileName;
-          this.mSourcePath += url.directory;
-      } else {
-          // A generic uri, use path.
-          fname = url.path;
-          this.mSourcePath += url.path;
-      }
-
-      if (suggestedFileName)
-        fname = iconPath = suggestedFileName;
-
-      var displayName = fname.replace(/ +/g, " ");
-
-      this.mTitle = this.dialogElement("strings").getFormattedString("title", [displayName]);
-      this.mDialog.document.title = this.mTitle;
-
-      // Put content type, filename and location into intro.
-      this.initIntro(url, fname, displayName);
-
-      var iconString = "moz-icon://" + iconPath + "?size=16&contentType=" + this.mLauncher.MIMEInfo.MIMEType;
-      this.dialogElement("contentTypeImage").setAttribute("src", iconString);
+  // Web progress listener so we can detect errors while mLauncher is
+  // streaming the data to a temporary file.
+  progressListener: {
+    // Implementation properties.
+    helperAppDlg: null,
 
-      // if always-save and is-executable and no-handler
-      // then set up simple ui
-      var mimeType = this.mLauncher.MIMEInfo.MIMEType;
-      var shouldntRememberChoice = (mimeType == "application/octet-stream" || 
-                                    mimeType == "application/x-msdownload" ||
-                                    this.mLauncher.targetFileIsExecutable);
-      if (shouldntRememberChoice && !this.openWithDefaultOK()) {
-        // hide featured choice 
-        this.dialogElement("normalBox").collapsed = true;
-        // show basic choice 
-        this.dialogElement("basicBox").collapsed = false;
-        // change button labels and icons; use "save" icon for the accept
-        // button since it's the only action possible
-        let acceptButton = this.mDialog.document.documentElement
-                               .getButton("accept");
-        acceptButton.label = this.dialogElement("strings")
-                                 .getString("unknownAccept.label");
-        acceptButton.setAttribute("icon", "save");
-        this.mDialog.document.documentElement.getButton("cancel").label = this.dialogElement("strings").getString("unknownCancel.label");
-        // hide other handler
-        this.dialogElement("openHandler").collapsed = true;
-        // set save as the selected option
-        this.dialogElement("mode").selectedItem = this.dialogElement("save");
-      }
-      else {
-        this.initAppAndSaveToDiskValues();
-
-        // Initialize "always ask me" box. This should always be disabled
-        // and set to true for the ambiguous type application/octet-stream.
-        // We don't also check for application/x-msdownload here since we
-        // want users to be able to autodownload .exe files. 
-        var rememberChoice = this.dialogElement("rememberChoice");
+    // nsIWebProgressListener methods.
+    // Look for error notifications and display alert to user.
+    onStatusChange: function( aWebProgress, aRequest, aStatus, aMessage ) {
+      if ( aStatus != Components.results.NS_OK ) {
+        // Get prompt service.
+        var prompter = Components.classes[ "@mozilla.org/embedcomp/prompt-service;1" ]
+                                 .getService( Components.interfaces.nsIPromptService );
+        // Display error alert (using text supplied by back-end).
+        prompter.alert( this.dialog, this.helperAppDlg.mTitle, aMessage );
 
-#if 0
-        // Just because we have a content-type of application/octet-stream 
-        // here doesn't actually mean that the content is of that type. Many 
-        // servers default to sending text/plain for file types they don't know
-        // about. To account for this, the uriloader does some checking to see 
-        // if a file sent as text/plain contains binary characters, and if so (*)
-        // it morphs the content-type into application/octet-stream so that
-        // the file can be properly handled. Since this is not generic binary
-        // data, rather, a data format that the system probably knows about, 
-        // we don't want to use the content-type provided by this dialog's 
-        // opener, as that's the generic application/octet-stream that the 
-        // uriloader has passed, rather we want to ask the MIME Service.
-        // This is so we don't needlessly disable the "autohandle" checkbox.
-        var mimeService = Components.classes["@mozilla.org/mime;1"].getService(Components.interfaces.nsIMIMEService);
-        var type = mimeService.getTypeFromURI(this.mLauncher.source);
-        this.realMIMEInfo = mimeService.getFromTypeAndExtension(type, "");
-
-        if (type == "application/octet-stream") {
-#endif
-        if (shouldntRememberChoice) {
-          rememberChoice.checked = false;
-          rememberChoice.disabled = true;
-        }
-        else {
-          rememberChoice.checked = !this.mLauncher.MIMEInfo.alwaysAskBeforeHandling;
+        // Close the dialog.
+        this.helperAppDlg.onCancel();
+        if ( this.helperAppDlg.mDialog ) {
+          this.helperAppDlg.mDialog.close();
         }
-        this.toggleRememberChoice(rememberChoice);
-
-        // XXXben - menulist won't init properly, hack. 
-        var openHandler = this.dialogElement("openHandler");
-        openHandler.parentNode.removeChild(openHandler);
-        var openHandlerBox = this.dialogElement("openHandlerBox");
-        openHandlerBox.appendChild(openHandler);
-      }
-
-      this.mDialog.setTimeout("dialog.postShowCallback()", 0);
-      
-      this.mDialog.document.documentElement.getButton("accept").disabled = true;
-      this._showTimer = Components.classes["@mozilla.org/timer;1"]
-                                  .createInstance(nsITimer);
-      this._showTimer.initWithCallback(this, 250, nsITimer.TYPE_ONE_SHOT);
-    },
-
-    notify: function (aTimer) {
-      if (aTimer == this._showTimer) {
-        if (!this.mDialog) {
-          this.reallyShow();
-        } else {
-          // The user may have already canceled the dialog.
-          try {
-            if (!this._blurred) {
-              this.mDialog.document.documentElement.getButton("accept").disabled = false;
-            }
-          } catch (ex) {}
-          this._delayExpired = true;
-        }
-        // The timer won't release us, so we have to release it.
-        this._showTimer = null;
-      }
-      else if (aTimer == this._saveToDiskTimer) {
-        // Since saveToDisk may open a file picker and therefore block this routine,
-        // we should only call it once the dialog is closed.
-        this.mLauncher.saveToDisk(null, false);
-        this._saveToDiskTimer = null;
       }
     },
 
-    postShowCallback: function () {
-      this.mDialog.sizeToContent();
-
-      // Set initial focus
-      this.dialogElement("mode").focus();
-    },
-
-    // initIntro:
-    initIntro: function(url, filename, displayname) {
-        this.dialogElement( "location" ).value = displayname;
-        this.dialogElement( "location" ).setAttribute("realname", filename);
-        this.dialogElement( "location" ).setAttribute("tooltiptext", displayname);
-
-        // if mSourcePath is a local file, then let's use the pretty path name instead of an ugly
-        // url...
-        var pathString = this.mSourcePath;
-        try 
-        {
-          var fileURL = url.QueryInterface(Components.interfaces.nsIFileURL);
-          if (fileURL)
-          {
-            var fileObject = fileURL.file;
-            if (fileObject)
-            {
-              var parentObject = fileObject.parent;
-              if (parentObject)
-              {
-                pathString = parentObject.path;
-              }
-            }
-          }
-        } catch(ex) {}
-
-        if (pathString == this.mSourcePath)
-        {
-          // wasn't a fileURL
-          var tmpurl = url.clone(); // don't want to change the real url
-          try {
-            tmpurl.userPass = "";
-          } catch (ex) {}
-          pathString = tmpurl.prePath;
-        }
-
-        // Set the location text, which is separate from the intro text so it can be cropped
-        var location = this.dialogElement( "source" );
-        location.value = pathString;
-        location.setAttribute("tooltiptext", this.mSourcePath);
-        
-        // Show the type of file. 
-        var type = this.dialogElement("type");
-        var mimeInfo = this.mLauncher.MIMEInfo;
-        
-        // 1. Try to use the pretty description of the type, if one is available.
-        var typeString = mimeInfo.description;
-        
-        if (typeString == "") {
-          // 2. If there is none, use the extension to identify the file, e.g. "ZIP file"
-          var primaryExtension = "";
-          try {
-            primaryExtension = mimeInfo.primaryExtension;
-          }
-          catch (ex) {
-          }
-          if (primaryExtension != "")
-            typeString = this.dialogElement("strings").getFormattedString("fileType", [primaryExtension.toUpperCase()]);
-          // 3. If we can't even do that, just give up and show the MIME type. 
-          else
-            typeString = mimeInfo.MIMEType;
-        }
-        
-        type.value = typeString;
-    },
-    
-    _blurred: false,
-    _delayExpired: false, 
-    onBlur: function(aEvent) {
-      this._blurred = true;
-      this.mDialog.document.documentElement.getButton("accept").disabled = true;
-    },
-    
-    onFocus: function(aEvent) {
-      this._blurred = false;
-      if (this._delayExpired) {
-        var script = "document.documentElement.getButton('accept').disabled = false";
-        this.mDialog.setTimeout(script, 250);
-      }
+    // Ignore onProgressChange, onProgressChange64, onStateChange, onLocationChange, onSecurityChange, and onRefreshAttempted notifications.
+    onProgressChange: function( aWebProgress,
+                                aRequest,
+                                aCurSelfProgress,
+                                aMaxSelfProgress,
+                                aCurTotalProgress,
+                                aMaxTotalProgress ) {
     },
 
-    // Returns true if opening the default application makes sense.
-    openWithDefaultOK: function() {
-        // The checking is different on Windows...
-#ifdef XP_WIN
-        // Windows presents some special cases.
-        // We need to prevent use of "system default" when the file is
-        // executable (so the user doesn't launch nasty programs downloaded
-        // from the web), and, enable use of "system default" if it isn't
-        // executable (because we will prompt the user for the default app
-        // in that case).
-        
-        //  Default is Ok if the file isn't executable (and vice-versa).
-        return !this.mLauncher.targetFileIsExecutable;
-#else
-            // On other platforms, default is Ok if there is a default app.
-            // Note that nsIMIMEInfo providers need to ensure that this holds true
-            // on each platform.
-        return this.mLauncher.MIMEInfo.hasDefaultHandler;
-#endif
-    },
-    
-    // Set "default" application description field.
-    initDefaultApp: function() {
-      // Use description, if we can get one.
-      var desc = this.mLauncher.MIMEInfo.defaultDescription;
-      if (desc) {
-        var defaultApp = this.dialogElement("strings").getFormattedString("defaultApp", [desc]);
-        this.dialogElement("defaultHandler").label = defaultApp;
-      }
-      else {
-        this.dialogElement("modeDeck").setAttribute("selectedIndex", "1");
-        // Hide the default handler item too, in case the user picks a 
-        // custom handler at a later date which triggers the menulist to show.
-        this.dialogElement("defaultHandler").hidden = true;
-      }
-    },
-
-    // getPath:
-    getPath: function (aFile) {
-#ifdef XP_MACOSX
-      return aFile.leafName || aFile.path;
-#else
-      return aFile.path;
-#endif
+    onProgressChange64: function( aWebProgress,
+                                  aRequest,
+                                  aCurSelfProgress,
+                                  aMaxSelfProgress,
+                                  aCurTotalProgress,
+                                  aMaxTotalProgress ) {
     },
 
-    // initAppAndSaveToDiskValues:
-    initAppAndSaveToDiskValues: function() {
-      var modeGroup = this.dialogElement("mode");
+
 
-      // We don't let users open .exe files or random binary data directly 
-      // from the browser at the moment because of security concerns. 
-      var openWithDefaultOK = this.openWithDefaultOK();
-      var mimeType = this.mLauncher.MIMEInfo.MIMEType;
-      if (this.mLauncher.targetFileIsExecutable || (
-          (mimeType == "application/octet-stream" ||
-           mimeType == "application/x-msdownload") && 
-           !openWithDefaultOK)) {
-        this.dialogElement("open").disabled = true;
-        var openHandler = this.dialogElement("openHandler");
-        openHandler.disabled = true;
-        openHandler.selectedItem = null;
-        modeGroup.selectedItem = this.dialogElement("save");
-        return;
-      }
-    
-      // Fill in helper app info, if there is any.
-      try {
-        this.chosenApp =
-          this.mLauncher.MIMEInfo.preferredApplicationHandler
-              .QueryInterface(Components.interfaces.nsILocalHandlerApp);
-      } catch (e) {
-        this.chosenApp = null;
-      }
-      // Initialize "default application" field.
-      this.initDefaultApp();
-
-      var otherHandler = this.dialogElement("otherHandler");
-              
-      // Fill application name textbox.
-      if (this.chosenApp && this.chosenApp.executable && 
-          this.chosenApp.executable.path) {
-        otherHandler.setAttribute("path",
-                                  this.getPath(this.chosenApp.executable));
+    onStateChange: function( aWebProgress, aRequest, aStateFlags, aStatus ) {
+    },
 
-#if XP_MACOSX
-        this.chosenApp.executable.QueryInterface(Components.interfaces.nsILocalFileMac);
-        otherHandler.label = this.chosenApp.executable.bundleDisplayName;
-#else
-        otherHandler.label = this.chosenApp.executable.leafName;
-#endif
-        otherHandler.hidden = false;
-      }
-
-      var useDefault = this.dialogElement("useSystemDefault");
-      var openHandler = this.dialogElement("openHandler");
-      openHandler.selectedIndex = 0;
+    onLocationChange: function( aWebProgress, aRequest, aLocation ) {
+    },
 
-      if (this.mLauncher.MIMEInfo.preferredAction == this.nsIMIMEInfo.useSystemDefault) {
-        // Open (using system default).
-        modeGroup.selectedItem = this.dialogElement("open");
-      } else if (this.mLauncher.MIMEInfo.preferredAction == this.nsIMIMEInfo.useHelperApp) {
-        // Open with given helper app.
-        modeGroup.selectedItem = this.dialogElement("open");
-        openHandler.selectedIndex = 1;
-      } else {
-        // Save to disk.
-        modeGroup.selectedItem = this.dialogElement("save");
-      }
-      
-      // If we don't have a "default app" then disable that choice.
-      if (!openWithDefaultOK) {
-        var useDefault = this.dialogElement("defaultHandler");
-        var isSelected = useDefault.selected;
-        
-        // Disable that choice.
-        useDefault.hidden = true;
-        // If that's the default, then switch to "save to disk."
-        if (isSelected) {
-          openHandler.selectedIndex = 1;
-          modeGroup.selectedItem = this.dialogElement("save");
-        }
-      }
-      
-      otherHandler.nextSibling.hidden = otherHandler.nextSibling.nextSibling.hidden = false;
-      this.updateOKButton();
+    onSecurityChange: function( aWebProgress, aRequest, state ) {
     },
 
-    // Returns the user-selected application
-    helperAppChoice: function() {
-      return this.chosenApp;
-    },
-    
-    get saveToDisk() {
-      return this.dialogElement("save").selected;
-    },
-    
-    get useOtherHandler() {
-      return this.dialogElement("open").selected && this.dialogElement("openHandler").selectedIndex == 1;
-    },
-    
-    get useSystemDefault() {
-      return this.dialogElement("open").selected && this.dialogElement("openHandler").selectedIndex == 0;
-    },
-    
-    toggleRememberChoice: function (aCheckbox) {
-        this.dialogElement("settingsChange").hidden = !aCheckbox.checked;
-        this.mDialog.sizeToContent();
-    },
-    
-    openHandlerCommand: function () {
-      var openHandler = this.dialogElement("openHandler");
-      if (openHandler.selectedItem.id == "choose")
-        this.chooseApp();
-      else
-        openHandler.setAttribute("lastSelectedItemID", openHandler.selectedItem.id);
-    },
+    onRefreshAttempted: function( aWebProgress, aURI, aDelay, aSameURI ) {
+      return true;
+    }
+  },
+
+  // initDialog:  Fill various dialog fields with initial content.
+  initDialog : function() {
+    // Put file name in window title.
+    var suggestedFileName = this.mLauncher.suggestedFileName;
+
+    // Some URIs do not implement nsIURL, so we can't just QI.
+    var url   = this.mLauncher.source;
+    var fname = "";
+    var iconPath = "goat";
+    this.mSourcePath = url.prePath;
+    if (url instanceof Components.interfaces.nsIURL) {
+      // A url, use file name from it.
+      fname = iconPath = url.fileName;
+      this.mSourcePath += url.directory;
+    } else {
+      // A generic uri, use path.
+      fname = url.path;
+      this.mSourcePath += url.path;
+    }
+
+    if (suggestedFileName)
+      fname = iconPath = suggestedFileName;
+
+    var displayName = fname.replace(/ +/g, " ");
+
+    this.mTitle = this.dialogElement("strings").getFormattedString("title", [displayName]);
+    this.mDialog.document.title = this.mTitle;
+
+    // Put content type, filename and location into intro.
+    this.initIntro(url, fname, displayName);
+
+    var iconString = "moz-icon://" + iconPath + "?size=16&contentType=" + this.mLauncher.MIMEInfo.MIMEType;
+    this.dialogElement("contentTypeImage").setAttribute("src", iconString);
+
+    // if always-save and is-executable and no-handler
+    // then set up simple ui
+    var mimeType = this.mLauncher.MIMEInfo.MIMEType;
+    var shouldntRememberChoice = (mimeType == "application/octet-stream" ||
+                                  mimeType == "application/x-msdownload" ||
+                                  this.mLauncher.targetFileIsExecutable);
+    if (shouldntRememberChoice && !this.openWithDefaultOK()) {
+      // hide featured choice
+      this.dialogElement("normalBox").collapsed = true;
+      // show basic choice
+      this.dialogElement("basicBox").collapsed = false;
+      // change button labels and icons; use "save" icon for the accept
+      // button since it's the only action possible
+      let acceptButton = this.mDialog.document.documentElement
+                                              .getButton("accept");
+      acceptButton.label = this.dialogElement("strings")
+                               .getString("unknownAccept.label");
+      acceptButton.setAttribute("icon", "save");
+      this.mDialog.document.documentElement.getButton("cancel").label = this.dialogElement("strings").getString("unknownCancel.label");
+      // hide other handler
+      this.dialogElement("openHandler").collapsed = true;
+      // set save as the selected option
+      this.dialogElement("mode").selectedItem = this.dialogElement("save");
+    }
+    else {
+      this.initAppAndSaveToDiskValues();
+
+      // Initialize "always ask me" box. This should always be disabled
+      // and set to true for the ambiguous type application/octet-stream.
+      // We don't also check for application/x-msdownload here since we
+      // want users to be able to autodownload .exe files.
+      var rememberChoice = this.dialogElement("rememberChoice");
 
-    updateOKButton: function() {
-      var ok = false;
-      if (this.dialogElement("save").selected) {
-        // This is always OK.
-        ok = true;
-      } 
-      else if (this.dialogElement("open").selected) {
-        switch (this.dialogElement("openHandler").selectedIndex) {
-        case 0:
-          // No app need be specified in this case.
-          ok = true;
-          break;
-        case 1:
-          // only enable the OK button if we have a default app to use or if 
-          // the user chose an app....
-          ok = this.chosenApp || /\S/.test(this.dialogElement("otherHandler").getAttribute("path")); 
-        break;
-        }
+#if 0
+      // Just because we have a content-type of application/octet-stream
+      // here doesn't actually mean that the content is of that type. Many
+      // servers default to sending text/plain for file types they don't know
+      // about. To account for this, the uriloader does some checking to see
+      // if a file sent as text/plain contains binary characters, and if so (*)
+      // it morphs the content-type into application/octet-stream so that
+      // the file can be properly handled. Since this is not generic binary
+      // data, rather, a data format that the system probably knows about,
+      // we don't want to use the content-type provided by this dialog's
+      // opener, as that's the generic application/octet-stream that the
+      // uriloader has passed, rather we want to ask the MIME Service.
+      // This is so we don't needlessly disable the "autohandle" checkbox.
+
+      // commented out to close the opening brace in the if statement.
+      // var mimeService = Components.classes["@mozilla.org/mime;1"].getService(Components.interfaces.nsIMIMEService);
+      // var type = mimeService.getTypeFromURI(this.mLauncher.source);
+      // this.realMIMEInfo = mimeService.getFromTypeAndExtension(type, "");
+
+      // if (type == "application/octet-stream") {
+#endif
+      if (shouldntRememberChoice) {
+        rememberChoice.checked = false;
+        rememberChoice.disabled = true;
       }
+      else {
+        rememberChoice.checked = !this.mLauncher.MIMEInfo.alwaysAskBeforeHandling;
+      }
+      this.toggleRememberChoice(rememberChoice);
+
+      // XXXben - menulist won't init properly, hack.
+      var openHandler = this.dialogElement("openHandler");
+      openHandler.parentNode.removeChild(openHandler);
+      var openHandlerBox = this.dialogElement("openHandlerBox");
+      openHandlerBox.appendChild(openHandler);
+    }
+
+    this.mDialog.setTimeout("dialog.postShowCallback()", 0);
+
+    this.mDialog.document.documentElement.getButton("accept").disabled = true;
+    this._showTimer = Components.classes["@mozilla.org/timer;1"]
+                                .createInstance(nsITimer);
+    this._showTimer.initWithCallback(this, 250, nsITimer.TYPE_ONE_SHOT);
+  },
 
-      // Enable Ok button if ok to press.
-      this.mDialog.document.documentElement.getButton("accept").disabled = !ok;
-    },
-    
-    // Returns true iff the user-specified helper app has been modified.
-    appChanged: function() {
-      return this.helperAppChoice() != this.mLauncher.MIMEInfo.preferredApplicationHandler;
-    },
+  notify: function (aTimer) {
+    if (aTimer == this._showTimer) {
+      if (!this.mDialog) {
+        this.reallyShow();
+      } else {
+        // The user may have already canceled the dialog.
+        try {
+          if (!this._blurred) {
+            this.mDialog.document.documentElement.getButton("accept").disabled = false;
+          }
+        } catch (ex) {}
+        this._delayExpired = true;
+      }
+      // The timer won't release us, so we have to release it.
+      this._showTimer = null;
+    }
+    else if (aTimer == this._saveToDiskTimer) {
+      // Since saveToDisk may open a file picker and therefore block this routine,
+      // we should only call it once the dialog is closed.
+      this.mLauncher.saveToDisk(null, false);
+      this._saveToDiskTimer = null;
+    }
+  },
+
+  postShowCallback: function () {
+    this.mDialog.sizeToContent();
 
-    updateMIMEInfo: function() {
-      var needUpdate = false;
-      // If current selection differs from what's in the mime info object,
-      // then we need to update.
-      if (this.saveToDisk) {
-        needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.saveToDisk;
-        if (needUpdate)
-          this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.saveToDisk;
-      } 
-      else if (this.useSystemDefault) {
-        needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.useSystemDefault;
-        if (needUpdate)
-          this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.useSystemDefault;
-      } 
-      else {
-        // For "open with", we need to check both preferred action and whether the user chose
-        // a new app.
-        needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.useHelperApp || this.appChanged();
-        if (needUpdate) {
-          this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.useHelperApp;
-          // App may have changed - Update application
-          var app = this.helperAppChoice();
-          this.mLauncher.MIMEInfo.preferredApplicationHandler = app;
+    // Set initial focus
+    this.dialogElement("mode").focus();
+  },
+
+  // initIntro:
+  initIntro: function(url, filename, displayname) {
+    this.dialogElement( "location" ).value = displayname;
+    this.dialogElement( "location" ).setAttribute("realname", filename);
+    this.dialogElement( "location" ).setAttribute("tooltiptext", displayname);
+
+    // if mSourcePath is a local file, then let's use the pretty path name instead of an ugly
+    // url...
+    var pathString = this.mSourcePath;
+    try
+    {
+      var fileURL = url.QueryInterface(Components.interfaces.nsIFileURL);
+      if (fileURL)
+      {
+        var fileObject = fileURL.file;
+        if (fileObject)
+        {
+          var parentObject = fileObject.parent;
+          if (parentObject)
+          {
+            pathString = parentObject.path;
+          }
         }
       }
-      // We will also need to update if the "always ask" flag has changed.
-      needUpdate = needUpdate || this.mLauncher.MIMEInfo.alwaysAskBeforeHandling != (!this.dialogElement("rememberChoice").checked);
+    } catch(ex) {}
+
+    if (pathString == this.mSourcePath)
+    {
+      // wasn't a fileURL
+      var tmpurl = url.clone(); // don't want to change the real url
+      try {
+        tmpurl.userPass = "";
+      } catch (ex) {}
+      pathString = tmpurl.prePath;
+    }
+
+    // Set the location text, which is separate from the intro text so it can be cropped
+    var location = this.dialogElement( "source" );
+    location.value = pathString;
+    location.setAttribute("tooltiptext", this.mSourcePath);
+
+    // Show the type of file.
+    var type = this.dialogElement("type");
+    var mimeInfo = this.mLauncher.MIMEInfo;
+
+    // 1. Try to use the pretty description of the type, if one is available.
+    var typeString = mimeInfo.description;
+
+    if (typeString == "") {
+      // 2. If there is none, use the extension to identify the file, e.g. "ZIP file"
+      var primaryExtension = "";
+      try {
+        primaryExtension = mimeInfo.primaryExtension;
+      }
+      catch (ex) {
+      }
+      if (primaryExtension != "")
+        typeString = this.dialogElement("strings").getFormattedString("fileType", [primaryExtension.toUpperCase()]);
+      // 3. If we can't even do that, just give up and show the MIME type.
+      else
+        typeString = mimeInfo.MIMEType;
+    }
+
+    type.value = typeString;
+  },
+
+  _blurred: false,
+  _delayExpired: false,
+  onBlur: function(aEvent) {
+    this._blurred = true;
+    this.mDialog.document.documentElement.getButton("accept").disabled = true;
+  },
+
+  onFocus: function(aEvent) {
+    this._blurred = false;
+    if (this._delayExpired) {
+      var script = "document.documentElement.getButton('accept').disabled = false";
+      this.mDialog.setTimeout(script, 250);
+    }
+  },
+
+  // Returns true if opening the default application makes sense.
+  openWithDefaultOK: function() {
+    // The checking is different on Windows...
+#ifdef XP_WIN
+    // Windows presents some special cases.
+    // We need to prevent use of "system default" when the file is
+    // executable (so the user doesn't launch nasty programs downloaded
+    // from the web), and, enable use of "system default" if it isn't
+    // executable (because we will prompt the user for the default app
+    // in that case).
+
+    //  Default is Ok if the file isn't executable (and vice-versa).
+    return !this.mLauncher.targetFileIsExecutable;
+#else
+    // On other platforms, default is Ok if there is a default app.
+    // Note that nsIMIMEInfo providers need to ensure that this holds true
+    // on each platform.
+    return this.mLauncher.MIMEInfo.hasDefaultHandler;
+#endif
+  },
 
-      // One last special case: If the input "always ask" flag was false, then we always
-      // update.  In that case we are displaying the helper app dialog for the first
-      // time for this mime type and we need to store the user's action in the mimeTypes.rdf
-      // data source (whether that action has changed or not; if it didn't change, then we need
-      // to store the "always ask" flag so the helper app dialog will or won't display
-      // next time, per the user's selection).
-      needUpdate = needUpdate || !this.mLauncher.MIMEInfo.alwaysAskBeforeHandling;
+  // Set "default" application description field.
+  initDefaultApp: function() {
+    // Use description, if we can get one.
+    var desc = this.mLauncher.MIMEInfo.defaultDescription;
+    if (desc) {
+      var defaultApp = this.dialogElement("strings").getFormattedString("defaultApp", [desc]);
+      this.dialogElement("defaultHandler").label = defaultApp;
+    }
+    else {
+      this.dialogElement("modeDeck").setAttribute("selectedIndex", "1");
+      // Hide the default handler item too, in case the user picks a
+      // custom handler at a later date which triggers the menulist to show.
+      this.dialogElement("defaultHandler").hidden = true;
+    }
+  },
+
+  // getPath:
+  getPath: function (aFile) {
+#ifdef XP_MACOSX
+    return aFile.leafName || aFile.path;
+#else
+    return aFile.path;
+#endif
+  },
+
+  // initAppAndSaveToDiskValues:
+  initAppAndSaveToDiskValues: function() {
+    var modeGroup = this.dialogElement("mode");
 
-      // Make sure mime info has updated setting for the "always ask" flag.
-      this.mLauncher.MIMEInfo.alwaysAskBeforeHandling = !this.dialogElement("rememberChoice").checked;
+    // We don't let users open .exe files or random binary data directly
+    // from the browser at the moment because of security concerns.
+    var openWithDefaultOK = this.openWithDefaultOK();
+    var mimeType = this.mLauncher.MIMEInfo.MIMEType;
+    if (this.mLauncher.targetFileIsExecutable || (
+      (mimeType == "application/octet-stream" ||
+       mimeType == "application/x-msdownload") &&
+        !openWithDefaultOK)) {
+      this.dialogElement("open").disabled = true;
+      var openHandler = this.dialogElement("openHandler");
+      openHandler.disabled = true;
+      openHandler.selectedItem = null;
+      modeGroup.selectedItem = this.dialogElement("save");
+      return;
+    }
+
+    // Fill in helper app info, if there is any.
+    try {
+      this.chosenApp =
+        this.mLauncher.MIMEInfo.preferredApplicationHandler
+                               .QueryInterface(Components.interfaces.nsILocalHandlerApp);
+    } catch (e) {
+      this.chosenApp = null;
+    }
+    // Initialize "default application" field.
+    this.initDefaultApp();
+
+    var otherHandler = this.dialogElement("otherHandler");
+
+    // Fill application name textbox.
+    if (this.chosenApp && this.chosenApp.executable &&
+        this.chosenApp.executable.path) {
+      otherHandler.setAttribute("path",
+                                this.getPath(this.chosenApp.executable));
+
+#if XP_MACOSX
+      this.chosenApp.executable.QueryInterface(Components.interfaces.nsILocalFileMac);
+      otherHandler.label = this.chosenApp.executable.bundleDisplayName;
+#else
+      otherHandler.label = this.chosenApp.executable.leafName;
+#endif
+      otherHandler.hidden = false;
+    }
+
+    var useDefault = this.dialogElement("useSystemDefault");
+    var openHandler = this.dialogElement("openHandler");
+    openHandler.selectedIndex = 0;
+
+    if (this.mLauncher.MIMEInfo.preferredAction == this.nsIMIMEInfo.useSystemDefault) {
+      // Open (using system default).
+      modeGroup.selectedItem = this.dialogElement("open");
+    } else if (this.mLauncher.MIMEInfo.preferredAction == this.nsIMIMEInfo.useHelperApp) {
+      // Open with given helper app.
+      modeGroup.selectedItem = this.dialogElement("open");
+      openHandler.selectedIndex = 1;
+    } else {
+      // Save to disk.
+      modeGroup.selectedItem = this.dialogElement("save");
+    }
 
-      return needUpdate;        
-    },
-    
-    // See if the user changed things, and if so, update the
-    // mimeTypes.rdf entry for this mime type.
-    updateHelperAppPref: function() {
-      var ha = new this.mDialog.HelperApps();
-      ha.updateTypeInfo(this.mLauncher.MIMEInfo);
-      ha.destroy();
-    },
-    
-    // onOK:
-    onOK: function() {
-      // Verify typed app path, if necessary.
-      if (this.useOtherHandler) {
-        var helperApp = this.helperAppChoice();
-        if (!helperApp || !helperApp.executable ||
-            !helperApp.executable.exists()) {
-          // Show alert and try again.        
-          var bundle = this.dialogElement("strings");                    
-          var msg = bundle.getFormattedString("badApp", [this.dialogElement("otherHandler").getAttribute("path")]);
-          var svc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
-          svc.alert(this.mDialog, bundle.getString("badApp.title"), msg);
+    // If we don't have a "default app" then disable that choice.
+    if (!openWithDefaultOK) {
+      var useDefault = this.dialogElement("defaultHandler");
+      var isSelected = useDefault.selected;
+
+      // Disable that choice.
+      useDefault.hidden = true;
+      // If that's the default, then switch to "save to disk."
+      if (isSelected) {
+        openHandler.selectedIndex = 1;
+        modeGroup.selectedItem = this.dialogElement("save");
+      }
+    }
+
+    otherHandler.nextSibling.hidden = otherHandler.nextSibling.nextSibling.hidden = false;
+    this.updateOKButton();
+  },
+
+  // Returns the user-selected application
+  helperAppChoice: function() {
+    return this.chosenApp;
+  },
+
+  get saveToDisk() {
+    return this.dialogElement("save").selected;
+  },
+
+  get useOtherHandler() {
+    return this.dialogElement("open").selected && this.dialogElement("openHandler").selectedIndex == 1;
+  },
+
+  get useSystemDefault() {
+    return this.dialogElement("open").selected && this.dialogElement("openHandler").selectedIndex == 0;
+  },
+
+  toggleRememberChoice: function (aCheckbox) {
+    this.dialogElement("settingsChange").hidden = !aCheckbox.checked;
+    this.mDialog.sizeToContent();
+  },
+
+  openHandlerCommand: function () {
+    var openHandler = this.dialogElement("openHandler");
+    if (openHandler.selectedItem.id == "choose")
+      this.chooseApp();
+    else
+      openHandler.setAttribute("lastSelectedItemID", openHandler.selectedItem.id);
+  },
+
+  updateOKButton: function() {
+    var ok = false;
+    if (this.dialogElement("save").selected) {
+      // This is always OK.
+      ok = true;
+    }
+    else if (this.dialogElement("open").selected) {
+      switch (this.dialogElement("openHandler").selectedIndex) {
+      case 0:
+        // No app need be specified in this case.
+        ok = true;
+        break;
+      case 1:
+        // only enable the OK button if we have a default app to use or if
+        // the user chose an app....
+        ok = this.chosenApp || /\S/.test(this.dialogElement("otherHandler").getAttribute("path")); 
+        break;
+      }
+    }
+
+    // Enable Ok button if ok to press.
+    this.mDialog.document.documentElement.getButton("accept").disabled = !ok;
+  },
+
+  // Returns true iff the user-specified helper app has been modified.
+  appChanged: function() {
+    return this.helperAppChoice() != this.mLauncher.MIMEInfo.preferredApplicationHandler;
+  },
 
-          // Disable the OK button.
-          this.mDialog.document.documentElement.getButton("accept").disabled = true;
-          this.dialogElement("mode").focus();          
-
-          // Clear chosen application.
-          this.chosenApp = null;
-
-          // Leave dialog up.
-          return false;
-        }
+  updateMIMEInfo: function() {
+    var needUpdate = false;
+    // If current selection differs from what's in the mime info object,
+    // then we need to update.
+    if (this.saveToDisk) {
+      needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.saveToDisk;
+      if (needUpdate)
+        this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.saveToDisk;
+    }
+    else if (this.useSystemDefault) {
+      needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.useSystemDefault;
+      if (needUpdate)
+        this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.useSystemDefault;
+    }
+    else {
+      // For "open with", we need to check both preferred action and whether the user chose
+      // a new app.
+      needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.useHelperApp || this.appChanged();
+      if (needUpdate) {
+        this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.useHelperApp;
+        // App may have changed - Update application
+        var app = this.helperAppChoice();
+        this.mLauncher.MIMEInfo.preferredApplicationHandler = app;
       }
-        
-      // Remove our web progress listener (a progress dialog will be
-      // taking over).
-      this.mLauncher.setWebProgressListener(null);
+    }
+    // We will also need to update if the "always ask" flag has changed.
+    needUpdate = needUpdate || this.mLauncher.MIMEInfo.alwaysAskBeforeHandling != (!this.dialogElement("rememberChoice").checked);
+
+    // One last special case: If the input "always ask" flag was false, then we always
+    // update.  In that case we are displaying the helper app dialog for the first
+    // time for this mime type and we need to store the user's action in the mimeTypes.rdf
+    // data source (whether that action has changed or not; if it didn't change, then we need
+    // to store the "always ask" flag so the helper app dialog will or won't display
+    // next time, per the user's selection).
+    needUpdate = needUpdate || !this.mLauncher.MIMEInfo.alwaysAskBeforeHandling;
+
+    // Make sure mime info has updated setting for the "always ask" flag.
+    this.mLauncher.MIMEInfo.alwaysAskBeforeHandling = !this.dialogElement("rememberChoice").checked;
+
+    return needUpdate;
+  },
+
+  // See if the user changed things, and if so, update the
+  // mimeTypes.rdf entry for this mime type.
+  updateHelperAppPref: function() {
+    var ha = new this.mDialog.HelperApps();
+    ha.updateTypeInfo(this.mLauncher.MIMEInfo);
+    ha.destroy();
+  },
 
-      // saveToDisk and launchWithApplication can return errors in 
-      // certain circumstances (e.g. The user clicks cancel in the
-      // "Save to Disk" dialog. In those cases, we don't want to
-      // update the helper application preferences in the RDF file.
-      try {
-        var needUpdate = this.updateMIMEInfo();
-        
-        if (this.dialogElement("save").selected) {
-          // If we're using a default download location, create a path
-          // for the file to be saved to to pass to |saveToDisk| - otherwise
-          // we must ask the user to pick a save name.
+  // onOK:
+  onOK: function() {
+    // Verify typed app path, if necessary.
+    if (this.useOtherHandler) {
+      var helperApp = this.helperAppChoice();
+      if (!helperApp || !helperApp.executable ||
+          !helperApp.executable.exists()) {
+        // Show alert and try again.
+        var bundle = this.dialogElement("strings");
+        var msg = bundle.getFormattedString("badApp", [this.dialogElement("otherHandler").getAttribute("path")]);
+        var svc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
+        svc.alert(this.mDialog, bundle.getString("badApp.title"), msg);
+
+        // Disable the OK button.
+        this.mDialog.document.documentElement.getButton("accept").disabled = true;
+        this.dialogElement("mode").focus();
+
+        // Clear chosen application.
+        this.chosenApp = null;
+
+        // Leave dialog up.
+        return false;
+      }
+    }
+
+    // Remove our web progress listener (a progress dialog will be
+    // taking over).
+    this.mLauncher.setWebProgressListener(null);
+
+    // saveToDisk and launchWithApplication can return errors in
+    // certain circumstances (e.g. The user clicks cancel in the
+    // "Save to Disk" dialog. In those cases, we don't want to
+    // update the helper application preferences in the RDF file.
+    try {
+      var needUpdate = this.updateMIMEInfo();
+
+      if (this.dialogElement("save").selected) {
+        // If we're using a default download location, create a path
+        // for the file to be saved to to pass to |saveToDisk| - otherwise
+        // we must ask the user to pick a save name.
 
 #if 0
-          var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
-          var targetFile = null;
-          try {
-            targetFile = prefs.getComplexValue("browser.download.defaultFolder", 
-                                               Components.interfaces.nsILocalFile);
-            var leafName = this.dialogElement("location").getAttribute("realname");
-            // Ensure that we don't overwrite any existing files here. 
-            targetFile = this.validateLeafName(targetFile, leafName, null);
-          }
-          catch(e) { }
+        var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
+        var targetFile = null;
+        try {
+          targetFile = prefs.getComplexValue("browser.download.defaultFolder",
+                                             Components.interfaces.nsILocalFile);
+          var leafName = this.dialogElement("location").getAttribute("realname");
+          // Ensure that we don't overwrite any existing files here.
+          targetFile = this.validateLeafName(targetFile, leafName, null);
+        }
+        catch(e) { }
 
-          this.mLauncher.saveToDisk(targetFile, false);
+        this.mLauncher.saveToDisk(targetFile, false);
 #endif
 
-          // see @notify
-          // we cannot use opener's setTimeout, see bug 420405
-          this._saveToDiskTimer = Components.classes["@mozilla.org/timer;1"]
-                                            .createInstance(nsITimer);
-          this._saveToDiskTimer.initWithCallback(this, 0,
-                                                 nsITimer.TYPE_ONE_SHOT);
-        }
-        else
-          this.mLauncher.launchWithApplication(null, false);
+        // see @notify
+        // we cannot use opener's setTimeout, see bug 420405
+        this._saveToDiskTimer = Components.classes["@mozilla.org/timer;1"]
+                                          .createInstance(nsITimer);
+        this._saveToDiskTimer.initWithCallback(this, 0,
+                                               nsITimer.TYPE_ONE_SHOT);
+      }
+      else
+        this.mLauncher.launchWithApplication(null, false);
+
+      // Update user pref for this mime type (if necessary). We do not
+      // store anything in the mime type preferences for the ambiguous
+      // type application/octet-stream. We do NOT do this for
+      // application/x-msdownload since we want users to be able to
+      // autodownload these to disk.
+      if (needUpdate && this.mLauncher.MIMEInfo.MIMEType != "application/octet-stream")
+        this.updateHelperAppPref();
+    } catch(e) { }
+
+    // Unhook dialog from this object.
+    this.mDialog.dialog = null;
+
+    // Close up dialog by returning true.
+    return true;
+  },
 
-        // Update user pref for this mime type (if necessary). We do not
-        // store anything in the mime type preferences for the ambiguous
-        // type application/octet-stream. We do NOT do this for 
-        // application/x-msdownload since we want users to be able to 
-        // autodownload these to disk. 
-        if (needUpdate && this.mLauncher.MIMEInfo.MIMEType != "application/octet-stream")
-          this.updateHelperAppPref();
-      } catch(e) { }
+  // onCancel:
+  onCancel: function() {
+    // Remove our web progress listener.
+    this.mLauncher.setWebProgressListener(null);
+
+    // Cancel app launcher.
+    try {
+      const NS_BINDING_ABORTED = 0x804b0002;
+      this.mLauncher.cancel(NS_BINDING_ABORTED);
+    } catch(exception) {
+    }
+
+    // Unhook dialog from this object.
+    this.mDialog.dialog = null;
 
-      // Unhook dialog from this object.
-      this.mDialog.dialog = null;
-
-      // Close up dialog by returning true.
-      return true;
-    },
+    // Close up dialog by returning true.
+    return true;
+  },
 
-    // onCancel:
-    onCancel: function() {
-      // Remove our web progress listener.
-      this.mLauncher.setWebProgressListener(null);
+  // dialogElement:  Convenience.
+  dialogElement: function(id) {
+    return this.mDialog.document.getElementById(id);
+  },
 
-      // Cancel app launcher.
+  // Retrieve the pretty description from the file
+  getFileDisplayName: function getFileDisplayName(file)
+  {
+#ifdef XP_WIN
+    if (file instanceof Components.interfaces.nsILocalFileWin) {
       try {
-        const NS_BINDING_ABORTED = 0x804b0002;
-        this.mLauncher.cancel(NS_BINDING_ABORTED);
-      } catch(exception) {
+        return file.getVersionInfoField("FileDescription");
+      } catch (ex) {
       }
-
-      // Unhook dialog from this object.
-      this.mDialog.dialog = null;
-
-      // Close up dialog by returning true.
-      return true;
-    },
-
-    // dialogElement:  Convenience. 
-    dialogElement: function(id) {
-      return this.mDialog.document.getElementById(id);
-    },
+    }
+#endif
+    return file.leafName;
+  },
 
-    // Retrieve the pretty description from the file
-    getFileDisplayName: function getFileDisplayName(file)
-    { 
+  // chooseApp:  Open file picker and prompt user for application.
+  chooseApp: function() {
 #ifdef XP_WIN
-        if (file instanceof Components.interfaces.nsILocalFileWin) {
-          try {
-            return file.getVersionInfoField("FileDescription");
-          } catch (ex) {
-          }
-        }
-#endif
-        return file.leafName;
-    },
-
-    // chooseApp:  Open file picker and prompt user for application.
-    chooseApp: function() {
-#ifdef XP_WIN
-    // Protect against the lack of an extension    
+    // Protect against the lack of an extension
     var fileExtension = "";
     try {
-        fileExtension = this.mLauncher.MIMEInfo.primaryExtension;
+      fileExtension = this.mLauncher.MIMEInfo.primaryExtension;
     } catch(ex) {
     }
 
     // Try to use the pretty description of the type, if one is available.
     var typeString = this.mLauncher.MIMEInfo.description;
 
     if (!typeString) {
-      // If there is none, use the extension to 
+      // If there is none, use the extension to
       // identify the file, e.g. "ZIP file"
       if (fileExtension) {
         typeString =
           this.dialogElement("strings").
           getFormattedString("fileType", [fileExtension.toUpperCase()]);
       } else {
         // If we can't even do that, just give up and show the MIME type.
         typeString = this.mLauncher.MIMEInfo.MIMEType;
       }
     }
 
     var params = {};
-    params.title = 
+    params.title =
       this.dialogElement("strings").getString("chooseAppFilePickerTitle");
     params.description = typeString;
     params.filename    = this.mLauncher.suggestedFileName;
     params.mimeInfo    = this.mLauncher.MIMEInfo;
     params.handlerApp  = null;
 
     this.mDialog.openDialog("chrome://global/content/appPicker.xul", null,
                             "chrome,modal,centerscreen,titlebar,dialog=yes",
                             params);
 
     if (params.handlerApp &&
         params.handlerApp.executable &&
         params.handlerApp.executable.isFile()) {
-        // Show the "handler" menulist since we have a (user-specified) 
-        // application now.
-        this.dialogElement("modeDeck").setAttribute("selectedIndex", "0");
+      // Show the "handler" menulist since we have a (user-specified)
+      // application now.
+      this.dialogElement("modeDeck").setAttribute("selectedIndex", "0");
 
-        // Remember the file they chose to run.
-        this.chosenApp = params.handlerApp;
+      // Remember the file they chose to run.
+      this.chosenApp = params.handlerApp;
 
-        // Update dialog
-        var otherHandler = this.dialogElement("otherHandler");
-        otherHandler.removeAttribute("hidden");
-        otherHandler.setAttribute("path",
-          this.getPath(this.chosenApp.executable));
-        otherHandler.label = 
-          this.getFileDisplayName(this.chosenApp.executable);
-        this.dialogElement("openHandler").selectedIndex = 1;
-        this.dialogElement("openHandler").setAttribute("lastSelectedItemID",
-          "otherHandler");
-        this.dialogElement("mode").selectedItem = this.dialogElement("open");
+      // Update dialog
+      var otherHandler = this.dialogElement("otherHandler");
+      otherHandler.removeAttribute("hidden");
+      otherHandler.setAttribute("path",
+                                this.getPath(this.chosenApp.executable));
+      otherHandler.label =
+        this.getFileDisplayName(this.chosenApp.executable);
+      this.dialogElement("openHandler").selectedIndex = 1;
+      this.dialogElement("openHandler").setAttribute("lastSelectedItemID",
+                                                     "otherHandler");
+      this.dialogElement("mode").selectedItem = this.dialogElement("open");
     } else {
-        var openHandler = this.dialogElement("openHandler");
-        var lastSelectedID = openHandler.getAttribute("lastSelectedItemID");
-        if (!lastSelectedID)
-            lastSelectedID = "defaultHandler";
-        openHandler.selectedItem = this.dialogElement(lastSelectedID);
+      var openHandler = this.dialogElement("openHandler");
+      var lastSelectedID = openHandler.getAttribute("lastSelectedItemID");
+      if (!lastSelectedID)
+        lastSelectedID = "defaultHandler";
+      openHandler.selectedItem = this.dialogElement(lastSelectedID);
     }
 
 #else
-      var nsIFilePicker = Components.interfaces.nsIFilePicker;
-      var fp = Components.classes["@mozilla.org/filepicker;1"]
-                         .createInstance(nsIFilePicker);
-      fp.init(this.mDialog,
-              this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
-              nsIFilePicker.modeOpen);
+    var nsIFilePicker = Components.interfaces.nsIFilePicker;
+    var fp = Components.classes["@mozilla.org/filepicker;1"]
+                       .createInstance(nsIFilePicker);
+    fp.init(this.mDialog,
+            this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
+            nsIFilePicker.modeOpen);
+
+    fp.appendFilters(nsIFilePicker.filterApps);
+
+    if (fp.show() == nsIFilePicker.returnOK && fp.file) {
+      // Show the "handler" menulist since we have a (user-specified)
+      // application now.
+      this.dialogElement("modeDeck").setAttribute("selectedIndex", "0");
 
-      fp.appendFilters(nsIFilePicker.filterApps);
+      // Remember the file they chose to run.
+      var localHandlerApp =
+        Components.classes["@mozilla.org/uriloader/local-handler-app;1"].
+                   createInstance(Components.interfaces.nsILocalHandlerApp);
+      localHandlerApp.executable = fp.file;
+      this.chosenApp = localHandlerApp;
+
+      // Update dialog.
+      var otherHandler = this.dialogElement("otherHandler");
+      otherHandler.removeAttribute("hidden");
+      otherHandler.setAttribute("path", this.getPath(this.chosenApp.executable));
+#ifdef XP_MACOSX
+      this.chosenApp.executable
+                    .QueryInterface(Components.interfaces.nsILocalFileMac);
+      otherHandler.label = this.chosenApp.executable.bundleDisplayName;
+#else
+      otherHandler.label = this.chosenApp.executable.leafName;
+#endif
+      this.dialogElement("openHandler").selectedIndex = 1;
+      this.dialogElement("openHandler").setAttribute("lastSelectedItemID", "otherHandler");
 
-      if (fp.show() == nsIFilePicker.returnOK && fp.file) {
-        // Show the "handler" menulist since we have a (user-specified) 
-        // application now.
-        this.dialogElement("modeDeck").setAttribute("selectedIndex", "0");
-        
-        // Remember the file they chose to run.
-        var localHandlerApp = 
-          Components.classes["@mozilla.org/uriloader/local-handler-app;1"].
-          createInstance(Components.interfaces.nsILocalHandlerApp);
-        localHandlerApp.executable = fp.file;
-        this.chosenApp = localHandlerApp;
-        
-        // Update dialog.
-        var otherHandler = this.dialogElement("otherHandler");
-        otherHandler.removeAttribute("hidden");
-        otherHandler.setAttribute("path", this.getPath(this.chosenApp.executable));
-#ifdef XP_MACOSX
-        this.chosenApp.executable
-            .QueryInterface(Components.interfaces.nsILocalFileMac);
-        otherHandler.label = this.chosenApp.executable.bundleDisplayName;
-#else
-        otherHandler.label = this.chosenApp.executable.leafName;
+      this.dialogElement("mode").selectedItem = this.dialogElement("open");
+    }
+    else {
+      var openHandler = this.dialogElement("openHandler");
+      var lastSelectedID = openHandler.getAttribute("lastSelectedItemID");
+      if (!lastSelectedID)
+        lastSelectedID = "defaultHandler";
+      openHandler.selectedItem = this.dialogElement(lastSelectedID);
+    }
 #endif
-        this.dialogElement("openHandler").selectedIndex = 1;
-        this.dialogElement("openHandler").setAttribute("lastSelectedItemID", "otherHandler");
-        
-        this.dialogElement("mode").selectedItem = this.dialogElement("open");
+  },
+
+  // Turn this on to get debugging messages.
+  debug: false,
+
+  // Dump text (if debug is on).
+  dump: function( text ) {
+    if ( this.debug ) {
+      dump( text );
+    }
+  },
+
+  // dumpObj:
+  dumpObj: function( spec ) {
+    var val = "<undefined>";
+    try {
+      val = eval( "this."+spec ).toString();
+    } catch( exception ) {
+    }
+    this.dump( spec + "=" + val + "\n" );
+  },
+
+  // dumpObjectProperties
+  dumpObjectProperties: function( desc, obj ) {
+    for( prop in obj ) {
+      this.dump( desc + "." + prop + "=" );
+      var val = "<undefined>";
+      try {
+        val = obj[ prop ];
+      } catch ( exception ) {
       }
-      else {
-        var openHandler = this.dialogElement("openHandler");
-        var lastSelectedID = openHandler.getAttribute("lastSelectedItemID");
-        if (!lastSelectedID)
-          lastSelectedID = "defaultHandler";
-        openHandler.selectedItem = this.dialogElement(lastSelectedID);
-      }
-#endif
-    },
-
-    // Turn this on to get debugging messages.
-    debug: false,
-
-    // Dump text (if debug is on).
-    dump: function( text ) {
-        if ( this.debug ) {
-            dump( text ); 
-        }
-    },
-
-    // dumpObj:
-    dumpObj: function( spec ) {
-         var val = "<undefined>";
-         try {
-             val = eval( "this."+spec ).toString();
-         } catch( exception ) {
-         }
-         this.dump( spec + "=" + val + "\n" );
-    },
-
-    // dumpObjectProperties
-    dumpObjectProperties: function( desc, obj ) {
-         for( prop in obj ) {
-             this.dump( desc + "." + prop + "=" );
-             var val = "<undefined>";
-             try {
-                 val = obj[ prop ];
-             } catch ( exception ) {
-             }
-             this.dump( val + "\n" );
-         }
+      this.dump( val + "\n" );
     }
+  }
 }
 
 // This Component's module implementation.  All the code below is used to get this
 // component registered and accessible via XPCOM.
 var module = {
-    // registerSelf: Register this component.
-    registerSelf: function (compMgr, fileSpec, location, type) {
-        compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
+  // registerSelf: Register this component.
+  registerSelf: function (compMgr, fileSpec, location, type) {
+    compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
 
-        compMgr.registerFactoryLocation( this.cid,
-                                         "Unknown Content Type Dialog",
-                                         this.contractId,
-                                         fileSpec,
-                                         location,
-                                         type );
-    },
+    compMgr.registerFactoryLocation( this.cid,
+                                     "Unknown Content Type Dialog",
+                                     this.contractId,
+                                     fileSpec,
+                                     location,
+                                     type );
+  },
 
-    // getClassObject: Return this component's factory object.
-    getClassObject: function (compMgr, cid, iid) {
-        if (!cid.equals(this.cid)) {
-            throw Components.results.NS_ERROR_NO_INTERFACE;
-        }
+  // getClassObject: Return this component's factory object.
+  getClassObject: function (compMgr, cid, iid) {
+    if (!cid.equals(this.cid)) {
+      throw Components.results.NS_ERROR_NO_INTERFACE;
+    }
 
-        if (!iid.equals(Components.interfaces.nsIFactory)) {
-            throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-        }
+    if (!iid.equals(Components.interfaces.nsIFactory)) {
+      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+    }
 
-        return this.factory;
-    },
+    return this.factory;
+  },
 
-    /* CID for this class */
-    cid: Components.ID("{F68578EB-6EC2-4169-AE19-8C6243F0ABE1}"),
+  /* CID for this class */
+  cid: Components.ID("{F68578EB-6EC2-4169-AE19-8C6243F0ABE1}"),
 
-    /* Contract ID for this class */
-    contractId: "@mozilla.org/helperapplauncherdialog;1",
+  /* Contract ID for this class */
+  contractId: "@mozilla.org/helperapplauncherdialog;1",
 
-    /* factory object */
-    factory: {
-        // createInstance: Return a new nsProgressDialog object.
-        createInstance: function (outer, iid) {
-            if (outer != null)
-                throw Components.results.NS_ERROR_NO_AGGREGATION;
+  /* factory object */
+  factory: {
+    // createInstance: Return a new nsProgressDialog object.
+    createInstance: function (outer, iid) {
+      if (outer != null)
+        throw Components.results.NS_ERROR_NO_AGGREGATION;
 
-            return (new nsUnknownContentTypeDialog()).QueryInterface(iid);
-        }
-    },
+      return (new nsUnknownContentTypeDialog()).QueryInterface(iid);
+    }
+  },
 
-    // canUnload: n/a (returns true)
-    canUnload: function(compMgr) {
-        return true;
-    }
+  // canUnload: n/a (returns true)
+  canUnload: function(compMgr) {
+    return true;
+  }
 };
 
 // NSGetModule: Return the nsIModule object.
 function NSGetModule(compMgr, fileSpec) {
-    return module;
+  return module;
 }