home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / phoenx05.zip / phoenix / components / nsHelperAppDlg.js < prev    next >
Text File  |  2002-12-10  |  28KB  |  718 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Netscape Public License
  6.  * Version 1.1 (the "License"); you may not use this file except in
  7.  * compliance with the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/NPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is the Mozilla browser.
  16.  *
  17.  * The Initial Developer of the Original Code is 
  18.  * Netscape Communications Corporation.
  19.  * Portions created by the Initial Developer are Copyright (C) 2001
  20.  * the Initial Developer. All Rights Reserved.
  21.  *
  22.  * Contributor(s):
  23.  *  Bill Law    <law@netscape.com>
  24.  *  Scott MacGregor <mscott@netscape.com>
  25.  *
  26.  *
  27.  * Alternatively, the contents of this file may be used under the terms of
  28.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  29.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  30.  * in which case the provisions of the GPL or the LGPL are applicable instead
  31.  * of those above. If you wish to allow use of your version of this file only
  32.  * under the terms of either the GPL or the LGPL, and not to allow others to
  33.  * use your version of this file under the terms of the NPL, indicate your
  34.  * decision by deleting the provisions above and replace them with the notice
  35.  * and other provisions required by the GPL or the LGPL. If you do not delete
  36.  * the provisions above, a recipient may use your version of this file under
  37.  * the terms of any one of the NPL, the GPL or the LGPL.
  38.  *
  39.  * ***** END LICENSE BLOCK ***** */
  40.  
  41. /* This file implements the nsIHelperAppLauncherDialog interface.
  42.  *
  43.  * The implementation consists of a JavaScript "class" named nsHelperAppDialog,
  44.  * comprised of:
  45.  *   - a JS constructor function
  46.  *   - a prototype providing all the interface methods and implementation stuff
  47.  *
  48.  * In addition, this file implements an nsIModule object that registers the
  49.  * nsHelperAppDialog component.
  50.  */
  51.  
  52.  
  53. /* ctor
  54.  */
  55. function nsHelperAppDialog() {
  56.     // Initialize data properties.
  57.     this.mLauncher = null;
  58.     this.mContext  = null;
  59.     this.mSourcePath = null;
  60.     this.choseApp  = false;
  61.     this.chosenApp = null;
  62.     this.givenDefaultApp = false;
  63.     this.strings   = new Array;
  64.     this.elements  = new Array;
  65.     this.updateSelf = true;
  66.     this.mTitle    = "";
  67. }
  68.  
  69. nsHelperAppDialog.prototype = {
  70.     // Turn this on to get debugging messages.
  71.     debug: false,
  72.  
  73.     nsIMIMEInfo  : Components.interfaces.nsIMIMEInfo,
  74.  
  75.     // Dump text (if debug is on).
  76.     dump: function( text ) {
  77.         if ( this.debug ) {
  78.             dump( text ); 
  79.         }
  80.     },
  81.  
  82.     // This "class" supports nsIHelperAppLauncherDialog, and nsISupports.
  83.     QueryInterface: function (iid) {
  84.         if (!iid.equals(Components.interfaces.nsIHelperAppLauncherDialog) &&
  85.             !iid.equals(Components.interfaces.nsISupports)) {
  86.             throw Components.results.NS_ERROR_NO_INTERFACE;
  87.         }
  88.         return this;
  89.     },
  90.  
  91.     // ---------- nsIHelperAppLauncherDialog methods ----------
  92.  
  93.     // show: Open XUL dialog using window watcher.  Since the dialog is not
  94.     //       modal, it needs to be a top level window and the way to open
  95.     //       one of those is via that route).
  96.     show: function(aLauncher, aContext)  {
  97.          this.mLauncher = aLauncher;
  98.          this.mContext  = aContext;
  99.          // Display the dialog using the Window Watcher interface.
  100.          var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  101.                     .getService( Components.interfaces.nsIWindowWatcher );
  102.          this.mDialog = ww.openWindow( null, // no parent
  103.                                        "chrome://global/content/nsHelperAppDlg.xul",
  104.                                        null,
  105.                                        "chrome,titlebar,dialog=yes",
  106.                                        null );
  107.          // Hook this object to the dialog.
  108.          this.mDialog.dialog = this;
  109.          // Watch for error notifications.
  110.          this.progressListener.helperAppDlg = this;
  111.          this.mLauncher.setWebProgressListener( this.progressListener );
  112.     },
  113.  
  114.     // promptForSaveToFile:  Display file picker dialog and return selected file.
  115.     promptForSaveToFile: function(aContext, aDefaultFile, aSuggestedFileExtension) {
  116.         var result = "";
  117.  
  118.         // Use file picker to show dialog.
  119.         var nsIFilePicker = Components.interfaces.nsIFilePicker;
  120.         var picker = Components.classes[ "@mozilla.org/filepicker;1" ]
  121.                        .createInstance( nsIFilePicker );
  122.         var bundle = Components.classes[ "@mozilla.org/intl/stringbundle;1" ]
  123.                        .getService( Components.interfaces.nsIStringBundleService )
  124.                            .createBundle( "chrome://global/locale/nsHelperAppDlg.properties");
  125.  
  126.         var windowTitle = bundle.GetStringFromName( "saveDialogTitle" );
  127.         
  128.         var parent = aContext
  129.                         .QueryInterface( Components.interfaces.nsIInterfaceRequestor )
  130.                         .getInterface( Components.interfaces.nsIDOMWindowInternal );
  131.         picker.init( parent, windowTitle, nsIFilePicker.modeSave );
  132.         picker.defaultString = aDefaultFile;
  133.         if (aSuggestedFileExtension) {
  134.             // aSuggestedFileExtension includes the period, so strip it
  135.             picker.defaultExtension = aSuggestedFileExtension.substring(1);
  136.         } else {
  137.             try {
  138.                 picker.defaultExtension = this.mLauncher.MIMEInfo.primaryExtension;
  139.             } catch (ex) {
  140.             }
  141.         }
  142.  
  143.         var wildCardExtension = "*";
  144.         if ( aSuggestedFileExtension ) {
  145.             wildCardExtension += aSuggestedFileExtension;
  146.             picker.appendFilter( wildCardExtension, wildCardExtension );
  147.         }
  148.  
  149.         picker.appendFilters( nsIFilePicker.filterAll );
  150.  
  151.         // Pull in the user's preferences and get the default download directory.
  152.         var prefs = Components.classes[ "@mozilla.org/preferences-service;1" ]
  153.                               .getService( Components.interfaces.nsIPrefBranch );
  154.         try {
  155.             var startDir = prefs.getComplexValue("browser.download.dir",
  156.                                                  Components.interfaces.nsILocalFile);
  157.             if ( startDir.exists() ) {
  158.                 picker.displayDirectory = startDir;
  159.             }
  160.         } catch( exception ) {
  161.         }
  162.  
  163.         var dlgResult = picker.show();
  164.  
  165.         if ( dlgResult == nsIFilePicker.returnCancel ) {
  166.             // Null result means user cancelled.
  167.             return null;
  168.         }
  169.  
  170.  
  171.         // be sure to save the directory the user chose as the new browser.download.dir
  172.         result = picker.file;
  173.  
  174.         if ( result ) {
  175.             var newDir = result.parent;
  176.             prefs.setComplexValue("browser.download.dir",
  177.                                   Components.interfaces.nsILocalFile, newDir);
  178.         }
  179.         return result;
  180.     },
  181.     
  182.     // showProgressDialog:  For now, use old dialog.  At some point, the caller should be
  183.     //                      converted to use the new generic progress dialog (when it's
  184.     //                      finished).
  185.     showProgressDialog: function(aLauncher, aContext) {
  186.          // Display the dialog using the Window Watcher interface.
  187.          var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  188.                     .getService( Components.interfaces.nsIWindowWatcher );
  189.          ww.openWindow( null, // no parent
  190.                         "chrome://global/content/nsProgressDlg.xul",
  191.                         null,
  192.                         "chrome,titlebar,minimizable,dialog=yes",
  193.                         aLauncher );
  194.     },
  195.     
  196.     // ---------- implementation methods ----------
  197.  
  198.     // Web progress listener so we can detect errors while mLauncher is
  199.     // streaming the data to a temporary file.
  200.     progressListener: {
  201.         // Implementation properties.
  202.         helperAppDlg: null,
  203.  
  204.         // nsIWebProgressListener methods.
  205.         // Look for error notifications and display alert to user.
  206.         onStatusChange: function( aWebProgress, aRequest, aStatus, aMessage ) {
  207.             if ( aStatus != Components.results.NS_OK ) {
  208.                 // Get prompt service.
  209.                 var prompter = Components.classes[ "@mozilla.org/embedcomp/prompt-service;1" ]
  210.                                    .getService( Components.interfaces.nsIPromptService );
  211.                 // Display error alert (using text supplied by back-end).
  212.                 prompter.alert( this.dialog, this.helperAppDlg.mTitle, aMessage );
  213.  
  214.                 // Close the dialog.
  215.                 this.helperAppDlg.onCancel();
  216.                 if ( this.helperAppDlg.mDialog ) {
  217.                     this.helperAppDlg.mDialog.close();
  218.                 }
  219.             }
  220.         },
  221.  
  222.         // Ignore onProgressChange, onStateChange, onLocationChange, and onSecurityChange notifications.
  223.         onProgressChange: function( aWebProgress,
  224.                                     aRequest,
  225.                                     aCurSelfProgress,
  226.                                     aMaxSelfProgress,
  227.                                     aCurTotalProgress,
  228.                                     aMaxTotalProgress ) {
  229.         },
  230.  
  231.         onStateChange: function( aWebProgress, aRequest, aStateFlags, aStatus ) {
  232.         },
  233.  
  234.         onLocationChange: function( aWebProgress, aRequest, aLocation ) {
  235.         },
  236.  
  237.         onSecurityChange: function( aWebProgress, aRequest, state ) {
  238.         }
  239.     },
  240.  
  241.     // initDialog:  Fill various dialog fields with initial content.
  242.     initDialog : function() {
  243.          // Check if file is executable (in which case, we will go straight to
  244.          // "save to disk").
  245.          var ignore1 = new Object;
  246.          var ignore2 = new Object;
  247.          var tmpFile = this.mLauncher.getDownloadInfo( ignore1, ignore2 );
  248.          if ( tmpFile.isExecutable() ) {
  249.              this.mLauncher.saveToDisk( null, false );
  250.              // Make sure onunload handler doesn't cancel.
  251.              this.mDialog.dialog = null;
  252.              // Close the dialog.
  253.              this.mDialog.close();
  254.              return;
  255.          }
  256.  
  257.          // Put product brand short name in prompt.
  258.          var prompt = this.dialogElement( "prompt" );
  259.          var modified = this.replaceInsert( prompt.firstChild.nodeValue, 1, this.getString( "brandShortName" ) );
  260.          prompt.firstChild.nodeValue = modified;
  261.  
  262.          // Put file name in window title.
  263.          var win   = this.dialogElement( "nsHelperAppDlg" );
  264.          var suggestedFileName = this.mLauncher.suggestedFileName;
  265.  
  266.          // Some URIs do not implement nsIURL, so we can't just QI.
  267.          var url   = this.mLauncher.source;
  268.          var fname = "";
  269.          this.mSourcePath = url.prePath;
  270.          try {
  271.              url = url.QueryInterface( Components.interfaces.nsIURL );
  272.              // A url, use file name from it.
  273.              fname = url.fileName;
  274.              this.mSourcePath += url.directory;
  275.          } catch (ex) {
  276.              // A generic uri, use path.
  277.              fname = url.path;
  278.              this.mSourcePath += url.path;
  279.          }
  280.  
  281.          if (suggestedFileName)
  282.            fname = suggestedFileName;
  283.            
  284.  
  285.          this.mTitle = this.replaceInsert( win.getAttribute( "title" ), 1, fname);
  286.          win.setAttribute( "title", this.mTitle );
  287.  
  288.          // Put content type and location into intro.
  289.          this.initIntro(url);
  290.  
  291.          var iconString = "moz-icon://" + fname + "?size=32&contentType=" + this.mLauncher.MIMEInfo.MIMEType;
  292.  
  293.          this.dialogElement("contentTypeImage").setAttribute("src", iconString);
  294.  
  295.          this.initAppAndSaveToDiskValues();
  296.  
  297.          // always make sure the window starts off with this checked....
  298.          this.dialogElement( "alwaysAskMe" ).checked = true;
  299.  
  300.          // Add special debug hook.
  301.          if ( this.debug ) {
  302.              prompt.setAttribute( "onclick", "dialog.doDebug()" );
  303.          }
  304.  
  305.          // Set up dialog button callbacks.
  306.          var object = this; // "this.onOK()" doesn't work!
  307.          this.mDialog.doSetOKCancel( function () { return object.onOK(); },
  308.                                      function () { return object.onCancel(); } );
  309.  
  310.          // Position it.
  311.          if ( this.mDialog.opener ) {
  312.              this.mDialog.moveToAlertPosition();
  313.          } else {
  314.              this.mDialog.sizeToContent();
  315.              this.mDialog.centerWindowOnScreen();
  316.          }
  317.  
  318.          // Set initial focus
  319.          this.dialogElement( "mode" ).focus();
  320.     },
  321.  
  322.     // initIntro:
  323.     initIntro: function(url) {
  324.         var intro = this.dialogElement( "intro" );
  325.         var desc = this.mLauncher.MIMEInfo.Description;
  326.         var modified;
  327.         if ( desc != "" ) 
  328.         {
  329.           // Use intro with descriptive text.
  330.           modified = this.replaceInsert( this.getString( "intro.withDesc" ), 1, this.mLauncher.MIMEInfo.Description );
  331.         } 
  332.         else 
  333.         {
  334.           // Use intro without descriptive text.
  335.           modified = this.getString( "intro.noDesc" );
  336.         }
  337.  
  338.         modified = this.replaceInsert( modified, 2, this.mLauncher.MIMEInfo.MIMEType );
  339.  
  340.         // if mSourcePath is a local file, then let's use the pretty path name instead of an ugly
  341.         // url...
  342.         var pathString = this.mSourcePath;
  343.         try 
  344.         {
  345.           var fileURL = url.QueryInterface(Components.interfaces.nsIFileURL);
  346.           if (fileURL)
  347.           {
  348.             var fileObject = fileURL.file;
  349.             if (fileObject)
  350.             {
  351.               var parentObject = fileObject.parent;
  352.               if (parentObject)
  353.               {
  354.                 pathString = parentObject.path;
  355.               }
  356.             }
  357.           }
  358.         } catch(ex) {}
  359.  
  360.  
  361.         intro.firstChild.nodeValue = "";
  362.         intro.firstChild.nodeValue = modified;
  363.  
  364.         // Set the location text, which is separate from the intro text so it can be cropped
  365.         var location = this.dialogElement( "location" );
  366.         location.value = pathString;
  367.     },
  368.  
  369.     // initAppAndSaveToDiskValues:
  370.     initAppAndSaveToDiskValues: function() {
  371.  
  372.         // Pre-select the choice the user made last time.
  373.         this.chosenApp = this.mLauncher.MIMEInfo.preferredApplicationHandler;
  374.         var applicationDescription = this.mLauncher.MIMEInfo.applicationDescription;
  375.  
  376.         if (applicationDescription != "")
  377.         {
  378.           this.updateApplicationName(applicationDescription); 
  379.           this.givenDefaultApp = true;
  380.         }
  381.         else if (this.chosenApp && this.chosenApp.path)
  382.         {
  383.           // If a user-chosen application, show its path.
  384.           this.updateApplicationName(this.chosenApp.path);
  385.           this.choseApp = true;
  386.         }
  387.         else
  388.          this.updateApplicationName(this.getString("noApplicationSpecified"));
  389.  
  390.         if ( (applicationDescription || this.choseApp) && this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.saveToDisk ) 
  391.         {
  392.           var openUsing = this.dialogElement( "openUsing" );
  393.           openUsing.radioGroup.selectedItem = openUsing;
  394.         }
  395.         else 
  396.         {
  397.           // Save to disk.
  398.           var saveToDisk = this.dialogElement( "saveToDisk" );
  399.           saveToDisk.radioGroup.selectedItem = saveToDisk;
  400.           // Disable choose app button.
  401.           this.dialogElement( "chooseApp" ).setAttribute( "disabled", "true" );
  402.         }
  403.     },
  404.  
  405.     updateApplicationName: function(newValue)
  406.     {
  407.       var applicationText = this.getString( "openUsingString" );
  408.       applicationText = this.replaceInsert( applicationText, 1, newValue );
  409.       var expl = this.dialogElement( "openUsing" );
  410.       expl.label = applicationText;
  411.     },
  412.  
  413.     // Enable pick app button if the user chooses that option.
  414.     toggleChoice : function () {
  415.         // See what option is selected.
  416.         if ( this.dialogElement( "openUsing" ).selected ) {
  417.             // We can enable the pick app button.
  418.             this.dialogElement( "chooseApp" ).removeAttribute( "disabled" );
  419.         } else {
  420.             // We can disable the pick app button.
  421.             this.dialogElement( "chooseApp" ).setAttribute( "disabled", "true" );
  422.         }
  423.  
  424.        this.updateOKButton();
  425.     },
  426.  
  427.     processAlwaysAskState : function () 
  428.     {
  429.       // if the user deselected the always ask checkbox, then store that on the mime object for future use...
  430.       if (!this.dialogElement( "alwaysAskMe" ).checked)
  431.       {
  432.         // we first need to rest the user action if the user selected save to disk instead of open...
  433.         // reset the preferred action in this case...we need to do this b4 setting the always ask before handling state
  434.  
  435.         if (!this.dialogElement( "openUsing" ).selected)
  436.         this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.saveToDisk;
  437.          
  438.  
  439.         this.mLauncher.MIMEInfo.alwaysAskBeforeHandling = false;
  440.       }
  441.     },
  442.     updateOKButton: function() {
  443.         var ok = false;
  444.         if ( this.dialogElement( "saveToDisk" ).selected ) 
  445.         {
  446.             // This is always OK.
  447.             ok = true;
  448.         } 
  449.         else 
  450.         {
  451.           // only enable the OK button if we have a default app to use or if 
  452.           // the user chose an app....
  453.           if ((this.choseApp && this.chosenApp.path) || this.givenDefaultApp)
  454.             ok = true;
  455.         }
  456.         
  457.         // Enable Ok button if ok to press.
  458.         this.dialogElement( "ok" ).disabled = !ok;
  459.     },
  460.  
  461.     // onOK:
  462.     onOK: function() {
  463.  
  464.       this.processAlwaysAskState(); 
  465.  
  466.       // Remove our web progress listener (a progress dialog will be
  467.       // taking over).
  468.       this.mLauncher.setWebProgressListener( null );
  469.  
  470.       if ( this.dialogElement( "openUsing" ).selected ) 
  471.       {
  472.          // If no app "chosen" then convert input string to file.
  473.          if (this.chosenApp)
  474.            this.mLauncher.launchWithApplication( this.chosenApp, false );
  475.           else 
  476.            this.mLauncher.launchWithApplication( null, false );
  477.       }
  478.       else
  479.         this.mLauncher.saveToDisk( null, false );
  480.         
  481.       // Unhook dialog from this object.
  482.       this.mDialog.dialog = null;
  483.  
  484.       // Close up dialog by returning true.
  485.       return true;
  486.      //this.mDialog.close();
  487.     },
  488.  
  489.     // onCancel:
  490.     onCancel: function() {
  491.         // Remove our web progress listener.
  492.         this.mLauncher.setWebProgressListener( null );
  493.  
  494.         // Cancel app launcher.
  495.         try {
  496.             this.mLauncher.Cancel();
  497.         } catch( exception ) {
  498.         }
  499.         
  500.         // Unhook dialog from this object.
  501.         this.mDialog.dialog = null;
  502.  
  503.         // Close up dialog by returning true.
  504.         return true;
  505.     },
  506.  
  507.     // dialogElement:  Try cache; obtain from document if not there.
  508.     dialogElement: function( id ) {
  509.          // Check if we've already fetched it.
  510.          if ( !( id in this.elements ) ) {
  511.              // No, then get it from dialog.
  512.              this.elements[ id ] = this.mDialog.document.getElementById( id );
  513.          }
  514.          return this.elements[ id ];
  515.     },
  516.  
  517.     // chooseApp:  Open file picker and prompt user for application.
  518.     chooseApp: function() {
  519.         var nsIFilePicker = Components.interfaces.nsIFilePicker;
  520.         var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance( nsIFilePicker );
  521.         fp.init( this.mDialog,
  522.                  this.getString( "chooseAppFilePickerTitle" ),
  523.                  nsIFilePicker.modeOpen );
  524.  
  525.         // XXX - We want to say nsIFilePicker.filterExecutable or something
  526.         fp.appendFilters( nsIFilePicker.filterAll );
  527.         
  528.         if ( fp.show() == nsIFilePicker.returnOK && fp.file ) {
  529.             // Remember the file they chose to run.
  530.             this.choseApp = true;
  531.             this.chosenApp    = fp.file;
  532.             // Update dialog.
  533.  
  534.             this.updateApplicationName(this.chosenApp.path);
  535.         }
  536.     },
  537.  
  538.     // setDefault:  Open "edit MIMEInfo" dialog (borrowed from prefs).
  539.     setDefault: function() {
  540.         // Get RDF service.
  541.         var rdf = Components.classes[ "@mozilla.org/rdf/rdf-service;1" ]
  542.                     .getService( Components.interfaces.nsIRDFService );
  543.         // Now ask if it knows about this mime type.
  544.         var exists = false;
  545.         var fileLocator = Components.classes[ "@mozilla.org/file/directory_service;1" ]
  546.                             .getService( Components.interfaces.nsIProperties );
  547.         var file        = fileLocator.get( "UMimTyp", Components.interfaces.nsIFile );
  548.         
  549.         // Get the data source; load it synchronously if it must be
  550.         // initialized.
  551.         var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
  552.         var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  553.         var fileurl = fileHandler.getURLSpecFromFile(file);
  554.         
  555.         var ds = rdf.GetDataSourceBlocking( fileurl );
  556.  
  557.         // Now check if this mimetype is really in there;
  558.         // This is done by seeing if there's a "value" arc from the mimetype resource
  559.         // to the mimetype literal string.
  560.         var mimeRes       = rdf.GetResource( "urn:mimetype:" + this.mLauncher.MIMEInfo.MIMEType );
  561.         var valueProperty = rdf.GetResource( "http://home.netscape.com/NC-rdf#value" );
  562.         var mimeLiteral   = rdf.GetLiteral( this.mLauncher.MIMEInfo.MIMEType );
  563.         exists =  ds.HasAssertion( mimeRes, valueProperty, mimeLiteral, true );
  564.  
  565.         var dlgUrl;
  566.         if ( exists ) {
  567.             // Open "edit mime type" dialog.
  568.             dlgUrl = "chrome://communicator/content/pref/pref-applications-edit.xul";
  569.         } else {
  570.             // Open "add mime type" dialog.
  571.             dlgUrl = "chrome://communicator/content/pref/pref-applications-new.xul";
  572.         }
  573.  
  574.         // Open whichever dialog is appropriate, passing this dialog object as argument.
  575.         this.updateSelf = false; // dialog will reset to true onOK
  576.         this.mDialog.openDialog( dlgUrl,
  577.                                  "_blank",
  578.                                  "chrome,modal=yes,resizable=no",
  579.                                  this );
  580.  
  581.         if (this.updateSelf) {
  582.             // Refresh dialog with updated info about the default action.
  583.             this.initIntro();
  584.             this.initAppAndSaveToDiskValues();
  585.         }
  586.     },
  587.  
  588.     // updateMIMEInfo:  This is called from the pref-applications-edit dialog when the user
  589.     //                  presses OK.  Take the updated MIMEInfo and have the helper app service
  590.     //                  "write" it back out to the RDF datasource.
  591.     updateMIMEInfo: function() {
  592.         this.dumpObjectProperties( "\tMIMEInfo", this.mLauncher.MIMEInfo );
  593.     },
  594.  
  595.     // dumpInfo:
  596.     doDebug: function() {
  597.         const nsIProgressDialog = Components.interfaces.nsIProgressDialog;
  598.         // Open new progress dialog.
  599.         var progress = Components.classes[ "@mozilla.org/progressdialog;1" ]
  600.                          .createInstance( nsIProgressDialog );
  601.         // Show it.
  602.         progress.open( this.mDialog );
  603.     },
  604.  
  605.     // dumpObj:
  606.     dumpObj: function( spec ) {
  607.          var val = "<undefined>";
  608.          try {
  609.              val = eval( "this."+spec ).toString();
  610.          } catch( exception ) {
  611.          }
  612.          this.dump( spec + "=" + val + "\n" );
  613.     },
  614.  
  615.     // dumpObjectProperties
  616.     dumpObjectProperties: function( desc, obj ) {
  617.          for( prop in obj ) {
  618.              this.dump( desc + "." + prop + "=" );
  619.              var val = "<undefined>";
  620.              try {
  621.                  val = obj[ prop ];
  622.              } catch ( exception ) {
  623.              }
  624.              this.dump( val + "\n" );
  625.          }
  626.     },
  627.  
  628.     // getString: Fetch data string from dialog content (and cache it).
  629.     getString: function( id ) {
  630.         // Check if we've fetched this string already.
  631.         if ( !( id in this.strings ) ) {
  632.             // Try to get it.
  633.             var elem = this.mDialog.document.getElementById( id );
  634.             if ( elem
  635.                  &&
  636.                  elem.firstChild
  637.                  &&
  638.                  elem.firstChild.nodeValue ) {
  639.                 this.strings[ id ] = elem.firstChild.nodeValue;
  640.             } else {
  641.                 // If unable to fetch string, use an empty string.
  642.                 this.strings[ id ] = "";
  643.             }
  644.         }
  645.         return this.strings[ id ];
  646.     },
  647.  
  648.     // replaceInsert: Replace given insert with replacement text and return the result.
  649.     replaceInsert: function( text, insertNo, replacementText ) {
  650.         var result = text;
  651.         var regExp = new RegExp("#"+insertNo);
  652.         result = result.replace( regExp, replacementText );
  653.         return result;
  654.     }
  655. }
  656.  
  657. // This Component's module implementation.  All the code below is used to get this
  658. // component registered and accessible via XPCOM.
  659. var module = {
  660.     firstTime: true,
  661.  
  662.     // registerSelf: Register this component.
  663.     registerSelf: function (compMgr, fileSpec, location, type) {
  664.         if (this.firstTime) {
  665.             this.firstTime = false;
  666.             throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
  667.         }
  668.         compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  669.  
  670.         compMgr.registerFactoryLocation( this.cid,
  671.                                          "Mozilla Helper App Launcher Dialog",
  672.                                          this.contractId,
  673.                                          fileSpec,
  674.                                          location,
  675.                                          type );
  676.     },
  677.  
  678.     // getClassObject: Return this component's factory object.
  679.     getClassObject: function (compMgr, cid, iid) {
  680.         if (!cid.equals(this.cid)) {
  681.             throw Components.results.NS_ERROR_NO_INTERFACE;
  682.         }
  683.  
  684.         if (!iid.equals(Components.interfaces.nsIFactory)) {
  685.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  686.         }
  687.  
  688.         return this.factory;
  689.     },
  690.  
  691.     /* CID for this class */
  692.     cid: Components.ID("{F68578EB-6EC2-4169-AE19-8C6243F0ABE1}"),
  693.  
  694.     /* Contract ID for this class */
  695.     contractId: "@mozilla.org/helperapplauncherdialog;1",
  696.  
  697.     /* factory object */
  698.     factory: {
  699.         // createInstance: Return a new nsProgressDialog object.
  700.         createInstance: function (outer, iid) {
  701.             if (outer != null)
  702.                 throw Components.results.NS_ERROR_NO_AGGREGATION;
  703.  
  704.             return (new nsHelperAppDialog()).QueryInterface(iid);
  705.         }
  706.     },
  707.  
  708.     // canUnload: n/a (returns true)
  709.     canUnload: function(compMgr) {
  710.         return true;
  711.     }
  712. };
  713.  
  714. // NSGetModule: Return the nsIModule object.
  715. function NSGetModule(compMgr, fileSpec) {
  716.     return module;
  717. }
  718.