CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / browser / components / preferences / advanced.js
blob2dfcd5c47d0a109da6ab956ec6e61930d49320cc
1 # -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 # ***** BEGIN LICENSE BLOCK *****
3 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 # The contents of this file are subject to the Mozilla Public License Version
6 # 1.1 (the "License"); you may not use this file except in compliance with
7 # the License. You may obtain a copy of the License at
8 # http://www.mozilla.org/MPL/
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.
15 # The Original Code is the Firefox Preferences System.
17 # The Initial Developer of the Original Code is
18 # Ben Goodger.
19 # Portions created by the Initial Developer are Copyright (C) 2005
20 # the Initial Developer. All Rights Reserved.
22 # Contributor(s):
23 #   Ben Goodger <ben@mozilla.org>
24 #   Jeff Walden <jwalden+code@mit.edu>
26 # Alternatively, the contents of this file may be used under the terms of
27 # either the GNU General Public License Version 2 or later (the "GPL"), or
28 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 # in which case the provisions of the GPL or the LGPL are applicable instead
30 # of those above. If you wish to allow use of your version of this file only
31 # under the terms of either the GPL or the LGPL, and not to allow others to
32 # use your version of this file under the terms of the MPL, indicate your
33 # decision by deleting the provisions above and replace them with the notice
34 # and other provisions required by the GPL or the LGPL. If you do not delete
35 # the provisions above, a recipient may use your version of this file under
36 # the terms of any one of the MPL, the GPL or the LGPL.
38 # ***** END LICENSE BLOCK *****
40 // Load DownloadUtils module for convertByteUnits
41 Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
42 Components.utils.import("resource://gre/modules/Services.jsm");
44 var gAdvancedPane = {
45   _inited: false,
47   /**
48    * Brings the appropriate tab to the front and initializes various bits of UI.
49    */
50   init: function ()
51   {
52     this._inited = true;
53     var advancedPrefs = document.getElementById("advancedPrefs");
55     var extraArgs = window.arguments[1];
56     if (extraArgs && extraArgs["advancedTab"]){
57       advancedPrefs.selectedTab = document.getElementById(extraArgs["advancedTab"]);
58     } else {
59       var preference = document.getElementById("browser.preferences.advanced.selectedTabIndex");
60       if (preference.value !== null)
61         advancedPrefs.selectedIndex = preference.value;
62     }
64 #ifdef MOZ_UPDATER
65     this.updateAppUpdateItems();
66     this.updateAutoItems();
67     this.updateModeItems();
68 #endif
69     this.updateOfflineApps();
70 #ifdef MOZ_CRASHREPORTER
71     this.initSubmitCrashes();
72 #endif
73     this.updateActualCacheSize();
74   },
76   /**
77    * Stores the identity of the current tab in preferences so that the selected
78    * tab can be persisted between openings of the preferences window.
79    */
80   tabSelectionChanged: function ()
81   {
82     if (!this._inited)
83       return;
84     var advancedPrefs = document.getElementById("advancedPrefs");
85     var preference = document.getElementById("browser.preferences.advanced.selectedTabIndex");
86     preference.valueFromPreferences = advancedPrefs.selectedIndex;
87   },
88   
89   // GENERAL TAB
91   /*
92    * Preferences:
93    *
94    * accessibility.browsewithcaret
95    * - true enables keyboard navigation and selection within web pages using a
96    *   visible caret, false uses normal keyboard navigation with no caret
97    * accessibility.typeaheadfind
98    * - when set to true, typing outside text areas and input boxes will
99    *   automatically start searching for what's typed within the current
100    *   document; when set to false, no search action happens
101    * general.autoScroll
102    * - when set to true, clicking the scroll wheel on the mouse activates a
103    *   mouse mode where moving the mouse down scrolls the document downward with
104    *   speed correlated with the distance of the cursor from the original
105    *   position at which the click occurred (and likewise with movement upward);
106    *   if false, this behavior is disabled
107    * general.smoothScroll
108    * - set to true to enable finer page scrolling than line-by-line on page-up,
109    *   page-down, and other such page movements
110    * layout.spellcheckDefault
111    * - an integer:
112    *     0  disables spellchecking
113    *     1  enables spellchecking, but only for multiline text fields
114    *     2  enables spellchecking for all text fields
115    */
117   /**
118    * Stores the original value of the spellchecking preference to enable proper
119    * restoration if unchanged (since we're mapping a tristate onto a checkbox).
120    */
121   _storedSpellCheck: 0,
123   /**
124    * Returns true if any spellchecking is enabled and false otherwise, caching
125    * the current value to enable proper pref restoration if the checkbox is
126    * never changed.
127    */
128   readCheckSpelling: function ()
129   {
130     var pref = document.getElementById("layout.spellcheckDefault");
131     this._storedSpellCheck = pref.value;
133     return (pref.value != 0);
134   },
136   /**
137    * Returns the value of the spellchecking preference represented by UI,
138    * preserving the preference's "hidden" value if the preference is
139    * unchanged and represents a value not strictly allowed in UI.
140    */
141   writeCheckSpelling: function ()
142   {
143     var checkbox = document.getElementById("checkSpelling");
144     return checkbox.checked ? (this._storedSpellCheck == 2 ? 2 : 1) : 0;
145   },
147   /**
148    *
149    */
150   initSubmitCrashes: function ()
151   {
152     var checkbox = document.getElementById("submitCrashesBox");
153     try {
154       var cr = Components.classes["@mozilla.org/toolkit/crash-reporter;1"].
155                getService(Components.interfaces.nsICrashReporter);
156       checkbox.checked = cr.submitReports;
157     } catch (e) {
158       checkbox.style.display = "none";
159     }
160   },
162   /**
163    *
164    */
165   updateSubmitCrashes: function ()
166   {
167     var checkbox = document.getElementById("submitCrashesBox");
168     try {
169       var cr = Components.classes["@mozilla.org/toolkit/crash-reporter;1"].
170                getService(Components.interfaces.nsICrashReporter);
171       cr.submitReports = checkbox.checked;
172     } catch (e) { }
173   },
175   /**
176    * When the user toggles the layers.acceleration.disabled pref,
177    * sync its new value to the gfx.direct2d.disabled pref too.
178    */
179   updateHardwareAcceleration: function()
180   {
181 #ifdef XP_WIN
182     var pref = document.getElementById("layers.acceleration.disabled");
183     Services.prefs.setBoolPref("gfx.direct2d.disabled", !pref.value);
184 #endif
185   },
187   // NETWORK TAB
189   /*
190    * Preferences:
191    *
192    * browser.cache.disk.capacity
193    * - the size of the browser cache in KB
194    * - Only used if browser.cache.disk.smart_size.enabled is disabled
195    */
197   /**
198    * Displays a dialog in which proxy settings may be changed.
199    */
200   showConnections: function ()
201   {
202     document.documentElement.openSubDialog("chrome://browser/content/preferences/connection.xul",
203                                            "", null);
204   },
206   // Retrieves the amount of space currently used by disk cache
207   updateActualCacheSize: function ()
208   {
209     var visitor = {
210       visitDevice: function (deviceID, deviceInfo)
211       {
212         if (deviceID == "disk") {
213           var actualSizeLabel = document.getElementById("actualCacheSize");
214           var sizeStrings = DownloadUtils.convertByteUnits(deviceInfo.totalSize);
215           var prefStrBundle = document.getElementById("bundlePreferences");
216           var sizeStr = prefStrBundle.getFormattedString("actualCacheSize",
217                                                           sizeStrings);
218           actualSizeLabel.value = sizeStr;
219         }
220         // Do not enumerate entries
221         return false;
222       },
224       visitEntry: function (deviceID, entryInfo)
225       {
226         // Do not enumerate entries.
227         return false;
228       }
229     };
230     var cacheService =
231       Components.classes["@mozilla.org/network/cache-service;1"]
232                 .getService(Components.interfaces.nsICacheService);
233     cacheService.visitEntries(visitor);
234   },
236   updateCacheSizeUI: function (smartSizeEnabled)
237   {
238     document.getElementById("useCacheBefore").disabled = smartSizeEnabled;
239     document.getElementById("cacheSize").disabled = smartSizeEnabled;
240     document.getElementById("useCacheAfter").disabled = smartSizeEnabled;
241   },
243   readSmartSizeEnabled: function ()
244   {
245     // The smart_size.enabled preference element is inverted="true", so its
246     // value is the opposite of the actual pref value
247     var disabled = document.getElementById("browser.cache.disk.smart_size.enabled").value;
248     this.updateCacheSizeUI(!disabled);
249   },
250   
251   /**
252    * Converts the cache size from units of KB to units of MB and returns that
253    * value.
254    */
255   readCacheSize: function ()
256   {
257     var preference = document.getElementById("browser.cache.disk.capacity");
258     return preference.value / 1024;
259   },
261   /**
262    * Converts the cache size as specified in UI (in MB) to KB and returns that
263    * value.
264    */
265   writeCacheSize: function ()
266   {
267     var cacheSize = document.getElementById("cacheSize");
268     var intValue = parseInt(cacheSize.value, 10);
269     return isNaN(intValue) ? 0 : intValue * 1024;
270   },
272   /**
273    * Clears the cache.
274    */
275   clearCache: function ()
276   {
277     var cacheService = Components.classes["@mozilla.org/network/cache-service;1"]
278                                        .getService(Components.interfaces.nsICacheService);
279     try {
280       cacheService.evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
281     } catch(ex) {}
282     this.updateActualCacheSize();
283   },
285   readOfflineNotify: function()
286   {
287     var pref = document.getElementById("browser.offline-apps.notify");
288     var button = document.getElementById("offlineNotifyExceptions");
289     button.disabled = !pref.value;
290     return pref.value;
291   },
293   showOfflineExceptions: function()
294   {
295     var bundlePreferences = document.getElementById("bundlePreferences");
296     var params = { blockVisible     : false,
297                    sessionVisible   : false,
298                    allowVisible     : false,
299                    prefilledHost    : "",
300                    permissionType   : "offline-app",
301                    manageCapability : Components.interfaces.nsIPermissionManager.DENY_ACTION,
302                    windowTitle      : bundlePreferences.getString("offlinepermissionstitle"),
303                    introText        : bundlePreferences.getString("offlinepermissionstext") };
304     document.documentElement.openWindow("Browser:Permissions",
305                                         "chrome://browser/content/preferences/permissions.xul",
306                                         "", params);
307   },
309   // XXX: duplicated in browser.js
310   _getOfflineAppUsage: function (host, groups)
311   {
312     var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
313                        getService(Components.interfaces.nsIApplicationCacheService);
314     if (!groups)
315       groups = cacheService.getGroups();
317     var ios = Components.classes["@mozilla.org/network/io-service;1"].
318               getService(Components.interfaces.nsIIOService);
320     var usage = 0;
321     for (var i = 0; i < groups.length; i++) {
322       var uri = ios.newURI(groups[i], null, null);
323       if (uri.asciiHost == host) {
324         var cache = cacheService.getActiveCache(groups[i]);
325         usage += cache.usage;
326       }
327     }
329     var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
330                          getService(Components.interfaces.nsIDOMStorageManager);
331     usage += storageManager.getUsage(host);
333     return usage;
334   },
336   /**
337    * Updates the list of offline applications
338    */
339   updateOfflineApps: function ()
340   {
341     var pm = Components.classes["@mozilla.org/permissionmanager;1"]
342                        .getService(Components.interfaces.nsIPermissionManager);
344     var list = document.getElementById("offlineAppsList");
345     while (list.firstChild) {
346       list.removeChild(list.firstChild);
347     }
349     var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
350                        getService(Components.interfaces.nsIApplicationCacheService);
351     var groups = cacheService.getGroups();
353     var bundle = document.getElementById("bundlePreferences");
355     var enumerator = pm.enumerator;
356     while (enumerator.hasMoreElements()) {
357       var perm = enumerator.getNext().QueryInterface(Components.interfaces.nsIPermission);
358       if (perm.type == "offline-app" &&
359           perm.capability != Components.interfaces.nsIPermissionManager.DEFAULT_ACTION &&
360           perm.capability != Components.interfaces.nsIPermissionManager.DENY_ACTION) {
361         var row = document.createElement("listitem");
362         row.id = "";
363         row.className = "offlineapp";
364         row.setAttribute("host", perm.host);
365         var converted = DownloadUtils.
366                         convertByteUnits(this._getOfflineAppUsage(perm.host, groups));
367         row.setAttribute("usage",
368                          bundle.getFormattedString("offlineAppUsage",
369                                                    converted));
370         list.appendChild(row);
371       }
372     }
373   },
375   offlineAppSelected: function()
376   {
377     var removeButton = document.getElementById("offlineAppsListRemove");
378     var list = document.getElementById("offlineAppsList");
379     if (list.selectedItem) {
380       removeButton.setAttribute("disabled", "false");
381     } else {
382       removeButton.setAttribute("disabled", "true");
383     }
384   },
386   removeOfflineApp: function()
387   {
388     var list = document.getElementById("offlineAppsList");
389     var item = list.selectedItem;
390     var host = item.getAttribute("host");
392     var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
393                             .getService(Components.interfaces.nsIPromptService);
394     var flags = prompts.BUTTON_TITLE_IS_STRING * prompts.BUTTON_POS_0 +
395                 prompts.BUTTON_TITLE_CANCEL * prompts.BUTTON_POS_1;
397     var bundle = document.getElementById("bundlePreferences");
398     var title = bundle.getString("offlineAppRemoveTitle");
399     var prompt = bundle.getFormattedString("offlineAppRemovePrompt", [host]);
400     var confirm = bundle.getString("offlineAppRemoveConfirm");
401     var result = prompts.confirmEx(window, title, prompt, flags, confirm,
402                                    null, null, null, {});
403     if (result != 0)
404       return;
406     // clear offline cache entries
407     var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
408                        getService(Components.interfaces.nsIApplicationCacheService);
409     var ios = Components.classes["@mozilla.org/network/io-service;1"].
410               getService(Components.interfaces.nsIIOService);
411     var groups = cacheService.getGroups();
412     for (var i = 0; i < groups.length; i++) {
413         var uri = ios.newURI(groups[i], null, null);
414         if (uri.asciiHost == host) {
415             var cache = cacheService.getActiveCache(groups[i]);
416             cache.discard();
417         }
418     }
420     // send out an offline-app-removed signal.  The nsDOMStorage
421     // service will clear DOM storage for this host.
422     var obs = Components.classes["@mozilla.org/observer-service;1"]
423                         .getService(Components.interfaces.nsIObserverService);
424     obs.notifyObservers(null, "offline-app-removed", host);
426     // remove the permission
427     var pm = Components.classes["@mozilla.org/permissionmanager;1"]
428                        .getService(Components.interfaces.nsIPermissionManager);
429     pm.remove(host, "offline-app",
430               Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
431     pm.remove(host, "offline-app",
432               Components.interfaces.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
434     list.removeChild(item);
435     gAdvancedPane.offlineAppSelected();
436   },
438   // UPDATE TAB
440   /*
441    * Preferences:
442    *
443    * app.update.enabled
444    * - true if updates to the application are enabled, false otherwise
445    * extensions.update.enabled
446    * - true if updates to extensions and themes are enabled, false otherwise
447    * browser.search.update
448    * - true if updates to search engines are enabled, false otherwise
449    * app.update.auto
450    * - true if updates should be automatically downloaded and installed,
451    *   possibly with a warning if incompatible extensions are installed (see
452    *   app.update.mode); false if the user should be asked what he wants to do
453    *   when an update is available
454    * app.update.mode
455    * - an integer:
456    *     0    do not warn if an update will disable extensions or themes
457    *     1    warn if an update will disable extensions or themes
458    *     2    warn if an update will disable extensions or themes *or* if the
459    *          update is a major update
460    */
462   /**
463    * Enables and disables various UI preferences as necessary to reflect locked,
464    * disabled, and checked/unchecked states.
465    *
466    * UI state matrix for update preference conditions
467    * 
468    * UI Components:                                     Preferences
469    * 1 = Firefox checkbox                               i   = app.update.enabled
470    * 2 = When updates for Firefox are found label       ii  = app.update.auto
471    * 3 = Automatic Radiogroup (Ask vs. Automatically)   iii = app.update.mode
472    * 4 = Warn before disabling extensions checkbox
473    * 
474    * States:
475    * Element     p   val     locked    Disabled 
476    * 1           i   t/f     f         false
477    *             i   t/f     t         true
478    *             ii  t/f     t/f       false
479    *             iii 0/1/2   t/f       false
480    * 2,3         i   t       t/f       false
481    *             i   f       t/f       true
482    *             ii  t/f     f         false
483    *             ii  t/f     t         true
484    *             iii 0/1/2   t/f       false
485    * 4           i   t       t/f       false
486    *             i   f       t/f       true
487    *             ii  t       t/f       false
488    *             ii  f       t/f       true
489    *             iii 0/1/2   f         false
490    *             iii 0/1/2   t         true   
491    * 
492    */
493 #ifdef MOZ_UPDATER
494   updateAppUpdateItems: function () 
495   {
496     var aus = 
497         Components.classes["@mozilla.org/updates/update-service;1"].
498         getService(Components.interfaces.nsIApplicationUpdateService);
500     var enabledPref = document.getElementById("app.update.enabled");
501     var enableAppUpdate = document.getElementById("enableAppUpdate");
503     enableAppUpdate.disabled = !aus.canCheckForUpdates || enabledPref.locked;
504   },
506   /**
507    * Enables/disables UI for "when updates are found" based on the values,
508    * and "locked" states of associated preferences.
509    */
510   updateAutoItems: function () 
511   {
512     var enabledPref = document.getElementById("app.update.enabled");
513     var autoPref = document.getElementById("app.update.auto");
514     
515     var updateModeLabel = document.getElementById("updateModeLabel");
516     var updateMode = document.getElementById("updateMode");
517     
518     var disable = enabledPref.locked || !enabledPref.value ||
519                   autoPref.locked;
520     updateModeLabel.disabled = updateMode.disabled = disable;
521   },
523   /**
524    * Enables/disables the "warn if incompatible extensions/themes exist" UI
525    * based on the values and "locked" states of various preferences.
526    */
527   updateModeItems: function () 
528   {
529     var enabledPref = document.getElementById("app.update.enabled");
530     var autoPref = document.getElementById("app.update.auto");
531     var modePref = document.getElementById("app.update.mode");
532     
533     var warnIncompatible = document.getElementById("warnIncompatible");
534     
535     var disable = enabledPref.locked || !enabledPref.value || autoPref.locked ||
536                   !autoPref.value || modePref.locked;
537     warnIncompatible.disabled = disable;
538   },
540   /**
541    * Stores the value of the app.update.mode preference, which is a tristate
542    * integer preference.  We store the value here so that we can properly
543    * restore the preference value if the UI reflecting the preference value
544    * is in a state which can represent either of two integer values (as
545    * opposed to only one possible value in the other UI state).
546    */
547   _modePreference: -1,
549   /**
550    * Reads the app.update.mode preference and converts its value into a
551    * true/false value for use in determining whether the "Warn me if this will
552    * disable extensions or themes" checkbox is checked.  We also save the value
553    * of the preference so that the preference value can be properly restored if
554    * the user's preferences cannot adequately be expressed by a single checkbox.
555    *
556    * app.update.modee         Checkbox State    Meaning
557    * 0                        Unchecked         Do not warn
558    * 1                        Checked           Warn if there are incompatibilities
559    * 2                        Checked           Warn if there are incompatibilities,
560    *                                            or the update is major.
561    */
562   readAddonWarn: function ()
563   {
564     var preference = document.getElementById("app.update.mode");
565     var doNotWarn = preference.value != 0;
566     gAdvancedPane._modePreference = doNotWarn ? preference.value : 1;
567     return doNotWarn;
568   },
570   /**
571    * Converts the state of the "Warn me if this will disable extensions or
572    * themes" checkbox into the integer preference which represents it,
573    * returning that value.
574    */
575   writeAddonWarn: function ()
576   {
577     var warnIncompatible = document.getElementById("warnIncompatible");
578     return !warnIncompatible.checked ? 0 : gAdvancedPane._modePreference;
579   },
581   /**
582    * Displays the history of installed updates.
583    */
584   showUpdates: function ()
585   {
586     var prompter = Components.classes["@mozilla.org/updates/update-prompt;1"]
587                              .createInstance(Components.interfaces.nsIUpdatePrompt);
588     prompter.showUpdateHistory(window);
589   },
590 #endif
592   /**
593    * The Extensions checkbox and button are disabled only if the enable Addon
594    * update preference is locked. 
595    */
596   updateAddonUpdateUI: function ()
597   {
598     var enabledPref = document.getElementById("extensions.update.enabled");
599     var enableAddonUpdate = document.getElementById("enableAddonUpdate");
601     enableAddonUpdate.disabled = enabledPref.locked;
602   },  
603   
604   // ENCRYPTION TAB
606   /*
607    * Preferences:
608    *
609    * security.enable_ssl3
610    * - true if SSL 3 encryption is enabled, false otherwise
611    * security.enable_tls
612    * - true if TLS encryption is enabled, false otherwise
613    * security.default_personal_cert
614    * - a string:
615    *     "Select Automatically"   select a certificate automatically when a site
616    *                              requests one
617    *     "Ask Every Time"         present a dialog to the user so he can select
618    *                              the certificate to use on a site which
619    *                              requests one
620    */
622   /**
623    * Displays the user's certificates and associated options.
624    */
625   showCertificates: function ()
626   {
627     document.documentElement.openWindow("mozilla:certmanager",
628                                         "chrome://pippki/content/certManager.xul",
629                                         "", null);
630   },
632   /**
633    * Displays a dialog which describes the user's CRLs.
634    */
635   showCRLs: function ()
636   {
637     document.documentElement.openWindow("mozilla:crlmanager", 
638                                         "chrome://pippki/content/crlManager.xul",
639                                         "", null);
640   },
642   /**
643    * Displays a dialog in which OCSP preferences can be configured.
644    */
645   showOCSP: function ()
646   {
647     document.documentElement.openSubDialog("chrome://mozapps/content/preferences/ocsp.xul",
648                                            "", null);
649   },
651   /**
652    * Displays a dialog from which the user can manage his security devices.
653    */
654   showSecurityDevices: function ()
655   {
656     document.documentElement.openWindow("mozilla:devicemanager",
657                                         "chrome://pippki/content/device_manager.xul",
658                                         "", null);
659   }
660 #ifdef HAVE_SHELL_SERVICE
661   ,
663   // SYSTEM DEFAULTS
665   /*
666    * Preferences:
667    *
668    * browser.shell.checkDefault
669    * - true if a default-browser check (and prompt to make it so if necessary)
670    *   occurs at startup, false otherwise
671    */
673   /**
674    * Checks whether the browser is currently registered with the operating
675    * system as the default browser.  If the browser is not currently the
676    * default browser, the user is given the option of making it the default;
677    * otherwise, the user is informed that this browser already is the browser.
678    */
679   checkNow: function ()
680   {
681     var shellSvc = Components.classes["@mozilla.org/browser/shell-service;1"]
682                              .getService(Components.interfaces.nsIShellService);
683     var brandBundle = document.getElementById("bundleBrand");
684     var shellBundle = document.getElementById("bundleShell");
685     var brandShortName = brandBundle.getString("brandShortName");
686     var promptTitle = shellBundle.getString("setDefaultBrowserTitle");
687     var promptMessage;
688     const IPS = Components.interfaces.nsIPromptService;
689     var psvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
690                          .getService(IPS);
691     if (!shellSvc.isDefaultBrowser(false)) {
692       promptMessage = shellBundle.getFormattedString("setDefaultBrowserMessage", 
693                                                      [brandShortName]);
694       var rv = psvc.confirmEx(window, promptTitle, promptMessage, 
695                               IPS.STD_YES_NO_BUTTONS,
696                               null, null, null, null, { });
697       if (rv == 0)
698         shellSvc.setDefaultBrowser(true, false);
699     }
700     else {
701       promptMessage = shellBundle.getFormattedString("alreadyDefaultBrowser",
702                                                      [brandShortName]);
703       psvc.alert(window, promptTitle, promptMessage);
704     }
705   }
706 #endif