home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2005 October / Gamestar_77_2005-10_dvd.iso / Programy / nsb-install-8-0.exe / chrome / toolkit.jar / content / mozapps / update / update.js < prev    next >
Text File  |  2005-07-29  |  39KB  |  1,017 lines

  1. //
  2. // window.arguments[1...] is an array of nsIUpdateItem implementing objects 
  3. // that are to be updated. 
  4. //  * if the array is empty, all items are updated (like a background update
  5. //    check)
  6. //  * if the array contains one or two UpdateItems, with null id fields, 
  7. //    all items of that /type/ are updated.
  8. //
  9. // This UI can be opened from the following places, and in the following modes:
  10. //
  11. // - from the Version Compatibility Checker at startup
  12. //    as the application starts a check is done to see if the application being
  13. //    started is the same version that was started last time. If it isn't, a
  14. //    list of UpdateItems that are incompatible with the verison being 
  15. //    started is generated and this UI opened with that list. This UI then
  16. //    offers to check for updates to those UpdateItems that are compatible
  17. //    with the version of the application being started. 
  18. //    
  19. //    In this mode, the wizard is opened to panel 'mismatch'. 
  20. //
  21. // - from the Extension Manager or Options Dialog or any UI where the user
  22. //   directly requests to check for updates.
  23. //    in this case the user selects UpdateItem(s) to update and this list
  24. //    is passed to this UI. If a single item is sent with the id field set to
  25. //    null but the type set correctly, this UI will check for updates to all 
  26. //    items of that type.
  27. //
  28. //    In this mode, the wizard is opened to panel 'checking'.
  29. //
  30. // - from the Updates Available Status Bar notification.
  31. //    in this case the background update checking has determined there are new
  32. //    updates that can be installed and has prepared a list for the user to see.
  33. //    They can update by clicking on a status bar icon which passes the list
  34. //    to this UI which lets them choose to install updates. 
  35. //
  36. //    In this mode, the wizard is opened to panel 'updatesFound' if the data
  37. //    set is immediately available, or 'checking' if the user closed the browser
  38. //    since the last background check was performed and the check needs to be
  39. //    performed again. 
  40. //
  41.  
  42. const nsIUpdateItem       = Components.interfaces.nsIUpdateItem;
  43. const nsIUpdateService    = Components.interfaces.nsIUpdateService;
  44. const nsIExtensionManager = Components.interfaces.nsIExtensionManager;
  45.  
  46. const PREF_APP_ID                               = "app.id";
  47. const PREF_UPDATE_APP_UPDATESAVAILABLE          = "app.update.updatesAvailable";
  48. const PREF_UPDATE_APP_PERFORMED                 = "app.update.performed";
  49.  
  50. const PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED  = "extensions.update.autoUpdateEnabled";
  51. const PREF_UPDATE_EXTENSIONS_COUNT              = "extensions.update.count";
  52. const PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD = "extensions.update.severity.threshold";
  53.  
  54. const PREF_UPDATE_SEVERITY                      = "update.severity";
  55.  
  56. var gSourceEvent = null;
  57. var gUpdateTypes = null;
  58.  
  59. var gUpdateWizard = {
  60.   // The items to check for updates for (e.g. an extension, some subset of extensions, 
  61.   // all extensions, a list of compatible extensions, etc...)
  62.   items: [],
  63.   // The items that we found updates available for
  64.   itemsToUpdate: [],
  65.   // The items that we successfully installed updates for
  66.   updatedCount: 0,
  67.   appUpdatesAvailable: false,
  68.  
  69.   shouldSuggestAutoChecking: false,
  70.   shouldAutoCheck: false,
  71.   
  72.   updatingApp: false,
  73.   remainingExtensionUpdateCount: 0,
  74.   
  75.   succeeded: true,
  76.   
  77.   offeredResetHomepage: false,
  78.  
  79.   appComps: {
  80.     upgraded: { 
  81.       core      : [],
  82.       optional  : [],
  83.       languages : [],
  84.     },
  85.     optional: {
  86.       optional  : [],
  87.       languages : [],
  88.     }
  89.   },
  90.   selectedLocaleAvailable: false,
  91.  
  92.   init: function ()
  93.   {
  94.     gUpdateTypes = window.arguments[0];
  95.     gSourceEvent = window.arguments[1];
  96.     for (var i = 2; i < window.arguments.length; ++i)
  97.       this.items.push(window.arguments[i].QueryInterface(nsIUpdateItem));
  98.  
  99.     var pref = Components.classes["@mozilla.org/preferences-service;1"]
  100.                          .getService(Components.interfaces.nsIPrefBranch);
  101.     this.shouldSuggestAutoChecking = (gSourceEvent == nsIUpdateService.SOURCE_EVENT_MISMATCH) && 
  102.                                       !pref.getBoolPref(PREF_UPDATE_EXTENSIONS_AUTOUPDATEENABLED);
  103.  
  104.     if (gSourceEvent != nsIUpdateService.SOURCE_EVENT_MISMATCH)
  105.       document.documentElement.advance();
  106.     else 
  107.       gMismatchPage.init();
  108.   },
  109.   
  110.   uninit: function ()
  111.   {
  112.     // Ensure all observers are unhooked, just in case something goes wrong or the
  113.     // user aborts. 
  114.     gUpdatePage.uninit();  
  115.   },
  116.   
  117.   onWizardFinish: function ()
  118.   {
  119.     var pref = Components.classes["@mozilla.org/preferences-service;1"]
  120.                          .getService(Components.interfaces.nsIPrefBranch);
  121.     if (this.shouldSuggestAutoChecking)
  122.       pref.setBoolPref("update.extensions.enabled", this.shouldAutoCheck); 
  123.     
  124.     if (this.succeeded) {
  125.       if (this.updatingApp) {
  126.         // Clear the "app update available" pref as an interim amnesty assuming
  127.         // the user actually does install the new version. If they don't, a subsequent
  128.         // update check will poke them again.
  129.         this.clearAppUpdatePrefs();
  130.       }
  131.       else {
  132.         // Downloading and Installed Extension
  133.         this.clearExtensionUpdatePrefs();
  134.       }
  135.     }
  136.  
  137.     if (this.offeredResetHomepage) {
  138.       pref.setBoolPref("browser.update.resetHomepage", 
  139.                        document.getElementById("resetHomepage").checked); 
  140.     }
  141.     
  142.     // Send an event to refresh any FE notification components. 
  143.     var os = Components.classes["@mozilla.org/observer-service;1"]
  144.                        .getService(Components.interfaces.nsIObserverService);
  145.     var userEvt = Components.interfaces.nsIUpdateService.SOURCE_EVENT_USER;
  146.     os.notifyObservers(null, "Update:Ended", userEvt.toString());
  147.   },
  148.   
  149.   clearAppUpdatePrefs: function ()
  150.   {
  151.     var pref = Components.classes["@mozilla.org/preferences-service;1"]
  152.                          .getService(Components.interfaces.nsIPrefBranch);
  153.                          
  154.     // Set the "applied app updates this session" pref so that the update service
  155.     // does not display the update notifier for application updates anymore this
  156.     // session, to give the user a one-cycle amnesty to install the newer version.
  157.     var updates = Components.classes["@mozilla.org/updates/update-service;1"]
  158.                             .getService(Components.interfaces.nsIUpdateService);
  159.     updates.appUpdatesAvailable = false;
  160.     
  161.     pref.setBoolPref(PREF_UPDATE_APP_PERFORMED, true);    
  162.  
  163.     // Unset prefs used by the update service to signify application updates
  164.     if (pref.prefHasUserValue(PREF_UPDATE_APP_UPDATESAVAILABLE))
  165.       pref.clearUserPref(PREF_UPDATE_APP_UPDATESAVAILABLE);
  166.  
  167.     // Lower the severity to reflect the fact that there are now only Extension/
  168.     // Theme updates available
  169.     var newCount = pref.getIntPref(PREF_UPDATE_EXTENSIONS_COUNT);
  170.     var threshold = pref.getIntPref(PREF_UPDATE_EXTENSIONS_SEVERITY_THRESHOLD);
  171.     if (newCount >= threshold)
  172.       pref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_MEDIUM);
  173.     else
  174.       pref.setIntPref(PREF_UPDATE_SEVERITY, nsIUpdateService.SEVERITY_LOW);
  175.   },
  176.   
  177.   clearExtensionUpdatePrefs: function ()
  178.   {
  179.     var pref = Components.classes["@mozilla.org/preferences-service;1"]
  180.                          .getService(Components.interfaces.nsIPrefBranch);
  181.                          
  182.     // Set the "applied extension updates this session" pref so that the 
  183.     // update service does not display the update notifier for extension
  184.     // updates anymore this session (the updates will be applied at the next
  185.     // start).
  186.     var updates = Components.classes["@mozilla.org/updates/update-service;1"]
  187.                             .getService(Components.interfaces.nsIUpdateService);
  188.     updates.extensionUpdatesAvailable = this.remainingExtensionUpdateCount;
  189.     
  190.     if (pref.prefHasUserValue(PREF_UPDATE_EXTENSIONS_COUNT)) 
  191.       pref.clearUserPref(PREF_UPDATE_EXTENSIONS_COUNT);
  192.   },
  193.   
  194.   _setUpButton: function (aButtonID, aButtonKey, aDisabled)
  195.   {
  196.     var strings = document.getElementById("updateStrings");
  197.     var button = document.documentElement.getButton(aButtonID);
  198.     if (aButtonKey) {
  199.       button.label = strings.getString(aButtonKey);
  200.       try {
  201.         button.accesskey = strings.getString(aButtonKey + "Accesskey");
  202.       }
  203.       catch (e) {
  204.       }
  205.     }
  206.     button.disabled = aDisabled;
  207.   },
  208.   
  209.   setButtonLabels: function (aBackButton, aBackButtonIsDisabled, 
  210.                              aNextButton, aNextButtonIsDisabled,
  211.                              aCancelButton, aCancelButtonIsDisabled)
  212.   {
  213.     
  214.     this._setUpButton("back", aBackButton, aBackButtonIsDisabled);
  215.     this._setUpButton("next", aNextButton, aNextButtonIsDisabled);
  216.     this._setUpButton("cancel", aCancelButton, aCancelButtonIsDisabled);
  217.   },
  218.   
  219.   /////////////////////////////////////////////////////////////////////////////
  220.   // Update Errors
  221.   errorItems: [],
  222.   errorOnApp: false,
  223.  
  224.   showErrors: function (aState, aErrors)
  225.   {
  226.     openDialog("chrome://mozapps/content/update/errors.xul", "", 
  227.                "modal", { state: aState, errors: aErrors });
  228.   },
  229.   
  230.   showUpdateCheckErrors: function ()
  231.   {
  232.     var errors = [];
  233.     for (var i = 0; i < this.errorItems.length; ++i)
  234.       errors.push({ name: this.errorItems[i].name, error: true });
  235.  
  236.     if (this.errorOnApp) {
  237.       var brandShortName = document.getElementById("brandStrings").getString("brandShortName");
  238.       errors.push({ name: brandShortName, error: true });    
  239.     }
  240.     
  241.     this.showErrors("checking", errors);
  242.   },
  243.  
  244.   checkForErrors: function (aElementIDToShow)
  245.   {
  246.     if (this.errorOnGeneric || this.errorItems.length > 0 || this.errorOnApp)
  247.       document.getElementById(aElementIDToShow).hidden = false;
  248.   },
  249.   
  250.   onWizardClose: function (aEvent)
  251.   {
  252.     if (gInstallingPage._installing) {
  253.       var os = Components.classes["@mozilla.org/observer-service;1"]
  254.                         .getService(Components.interfaces.nsIObserverService);
  255.       os.notifyObservers(null, "xpinstall-progress", "cancel");
  256.       return false;
  257.     }    
  258.     return true;
  259.   }
  260. };
  261.  
  262. var gMismatchPage = {
  263.   init: function ()
  264.   {
  265.     var incompatible = document.getElementById("mismatch.incompatible");
  266.     for (var i = 0; i < gUpdateWizard.items.length; ++i) {
  267.       var item = gUpdateWizard.items[i];
  268.       var listitem = document.createElement("listitem");
  269.       listitem.setAttribute("label", item.name + " " + item.version);
  270.       incompatible.appendChild(listitem);
  271.     }
  272.   },
  273.   
  274.   onPageShow: function ()
  275.   {
  276.     gUpdateWizard.setButtonLabels(null, true, 
  277.                                   "mismatchCheckNow", false, 
  278.                                   "mismatchDontCheck", false);
  279.     document.documentElement.getButton("next").focus();
  280.   }
  281. };
  282.  
  283. var gUpdatePage = {
  284.   _completeCount: 0,
  285.   _messages: ["Update:Extension:Started", 
  286.               "Update:Extension:Ended", 
  287.               "Update:Extension:Item-Started", 
  288.               "Update:Extension:Item-Ended",
  289.               "Update:Extension:Item-Error",
  290.               "Update:App:Ended",
  291.               "Update:Ended"],
  292.   
  293.   onPageShow: function ()
  294.   {
  295.     gUpdateWizard.setButtonLabels(null, true, 
  296.                                   "nextButtonText", true, 
  297.                                   "cancelButtonText", false);
  298.     document.documentElement.getButton("next").focus();
  299.  
  300.     var os = Components.classes["@mozilla.org/observer-service;1"]
  301.                        .getService(Components.interfaces.nsIObserverService);
  302.     for (var i = 0; i < this._messages.length; ++i)
  303.       os.addObserver(this, this._messages[i], false);
  304.  
  305.     gUpdateWizard.errorItems = [];
  306.  
  307.     var updates = Components.classes["@mozilla.org/updates/update-service;1"]
  308.                             .getService(Components.interfaces.nsIUpdateService);
  309.     updates.checkForUpdatesInternal(gUpdateWizard.items, gUpdateWizard.items.length, 
  310.                                     gUpdateTypes, gSourceEvent);
  311.   },
  312.  
  313.   _destroyed: false,  
  314.   uninit: function ()
  315.   {
  316.     if (this._destroyed)
  317.       return;
  318.   
  319.     var os = Components.classes["@mozilla.org/observer-service;1"]
  320.                        .getService(Components.interfaces.nsIObserverService);
  321.     for (var i = 0; i < this._messages.length; ++i)
  322.       os.removeObserver(this, this._messages[i]);
  323.  
  324.     this._destroyed = true;
  325.   },
  326.  
  327.   _totalCount: 0,
  328.   get totalCount()
  329.   {
  330.     if (!this._totalCount) {
  331.       this._totalCount = gUpdateWizard.items.length;
  332.       if (this._totalCount == 0) {
  333.         var em = Components.classes["@mozilla.org/extensions/manager;1"]
  334.                             .getService(Components.interfaces.nsIExtensionManager);
  335.         var extensionCount = em.getItemList(null, nsIUpdateItem.TYPE_EXTENSION, {}).length;
  336.         var themeCount = em.getItemList(null, nsIUpdateItem.TYPE_THEME, {}).length;
  337.  
  338.         this._totalCount = extensionCount + themeCount + 1;
  339.       }
  340.     }
  341.     return this._totalCount;
  342.   },  
  343.   
  344.   observe: function (aSubject, aTopic, aData)
  345.   {
  346.     var canFinish = false;
  347.     switch (aTopic) {
  348.     case "Update:Extension:Started":
  349.       break;
  350.     case "Update:Extension:Item-Started":
  351.       break;
  352.     case "Update:Extension:Item-Ended":
  353.       if (aSubject) {
  354.         var item = aSubject.QueryInterface(Components.interfaces.nsIUpdateItem);
  355.         gUpdateWizard.itemsToUpdate.push(item);
  356.       
  357.         var updateStrings = document.getElementById("updateStrings");
  358.         var status = document.getElementById("checking.status");
  359.         var statusString = updateStrings.getFormattedString("checkingPrefix", [item.name]);
  360.         status.setAttribute("value", statusString);
  361.       }
  362.       ++this._completeCount;
  363.  
  364.       // Update the Progress Bar            
  365.       var progress = document.getElementById("checking.progress");
  366.       progress.value = Math.ceil((this._completeCount / this.totalCount) * 100);
  367.       
  368.       break;
  369.     case "Update:Extension:Item-Error":
  370.       if (aSubject) {
  371.         var item = aSubject.QueryInterface(Components.interfaces.nsIUpdateItem);
  372.         gUpdateWizard.errorItems.push(item);
  373.       }
  374.       else {
  375.         for (var i = 0; i < gUpdateWizard.items.length; ++i) {
  376.           if (!gUpdateWizard.items[i].updateRDF)
  377.             gUpdateWizard.errorItems.push(gUpdateWizard.items[i]);
  378.         }
  379.       }
  380.       ++this._completeCount;
  381.       var progress = document.getElementById("checking.progress");
  382.       progress.value = Math.ceil((this._completeCount / this.totalCount) * 100);
  383.  
  384.       break;
  385.     case "Update:Extension:Ended":
  386.       // If we were passed a set of extensions/themes/other to update, this
  387.       // means we're not checking for app updates, so don't wait for the app
  388.       // update to complete before advancing (because there is none).
  389.       // canFinish = gUpdateWizard.items.length > 0;
  390.       // XXXben
  391.       break;
  392.     case "Update:Ended":
  393.       // If we're doing a general update check, (that is, no specific extensions/themes
  394.       // were passed in for us to check for updates to), this notification means both
  395.       // extension and app updates have completed.
  396.       canFinish = true;
  397.       break;
  398.     case "Update:App:Error":
  399.       gUpdateWizard.errorOnApp = true;
  400.       ++this._completeCount;
  401.       var progress = document.getElementById("checking.progress");
  402.       progress.value = Math.ceil((this._completeCount / this.totalCount) * 100);
  403.       break;
  404.     case "Update:App:Ended":
  405.       // The "Updates Found" page of the update wizard needs to know if it there are app 
  406.       // updates so it can list them first. 
  407.       ++this._completeCount;
  408.       var progress = document.getElementById("checking.progress");
  409.       progress.value = Math.ceil((this._completeCount / this.totalCount) * 100);
  410.       break;
  411.     }
  412.  
  413.     if (canFinish) {
  414.       gUpdatePage.uninit();
  415.       var updates = Components.classes["@mozilla.org/updates/update-service;1"]
  416.                               .getService(Components.interfaces.nsIUpdateService);
  417.       if ((gUpdateTypes & nsIUpdateItem.TYPE_ADDON && gUpdateWizard.itemsToUpdate.length > 0) || 
  418.           (gUpdateTypes & nsIUpdateItem.TYPE_APP && updates.appUpdatesAvailable))
  419.         document.getElementById("checking").setAttribute("next", "found");
  420.       document.documentElement.advance();
  421.     }
  422.   }
  423. };
  424.  
  425. var gFoundPage = {
  426.   _appUpdateExists: false,
  427.   _appSelected: false, 
  428.   _appItem: null,
  429.   _nonAppItems: [],
  430.   
  431.   _newestInfo: null,
  432.   _currentInfo: null,
  433.   
  434.   buildAddons: function ()
  435.   {
  436.     var hasExtensions = false;
  437.     var foundAddonsList = document.getElementById("found.addons.list");
  438.     var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  439.                         .createInstance(Components.interfaces.nsIURI);
  440.     var itemCount = gUpdateWizard.itemsToUpdate.length;
  441.     for (var i = 0; i < itemCount; ++i) {
  442.       var item = gUpdateWizard.itemsToUpdate[i];
  443.       var checkbox = document.createElement("checkbox");
  444.       foundAddonsList.appendChild(checkbox);
  445.       checkbox.setAttribute("type", "update");
  446.       checkbox.label        = item.name + " " + item.version;
  447.       checkbox.URL          = item.xpiURL;
  448.       checkbox.infoURL      = "";
  449.       checkbox.internalName = "";
  450.       uri.spec              = item.xpiURL;
  451.       checkbox.source       = uri.host;
  452.       checkbox.checked      = true;
  453.       hasExtensions         = true;
  454.     }
  455.  
  456.     if (hasExtensions) {
  457.       var addonsHeader = document.getElementById("addons");
  458.       var strings = document.getElementById("updateStrings");
  459.       addonsHeader.label = strings.getFormattedString("updateTypeExtensions", [itemCount]);
  460.       addonsHeader.collapsed = false;
  461.     }
  462.   },
  463.  
  464.   buildPatches: function (aPatches)
  465.   {
  466.     var needsPatching = false;
  467.     var critical = document.getElementById("found.criticalUpdates.list");
  468.     var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  469.                         .createInstance(Components.interfaces.nsIURI);
  470.     var count = 0;
  471.     for (var i = 0; i < aPatches.length; ++i) {
  472.       var ver = InstallTrigger.getVersion(aPatches[i].internalName);
  473.       if (InstallTrigger.getVersion(aPatches[i].internalName)) {
  474.         // The user has already installed this patch since info
  475.         // about it exists in the Version Registry. Skip. 
  476.         continue;
  477.       }
  478.       
  479.       var checkbox = document.createElement("checkbox");
  480.       critical.appendChild(checkbox);
  481.       checkbox.setAttribute("type", "update");
  482.       checkbox.label        = aPatches[i].name;
  483.       checkbox.URL          = aPatches[i].URL;
  484.       checkbox.infoURL      = aPatches[i].infoURL;
  485.       checkbox.internalName = aPatches[i].internalName;
  486.       uri.spec              = checkbox.URL;
  487.       checkbox.source       = uri.host;
  488.       checkbox.checked      = true;
  489.       needsPatching         = true;
  490.       ++count;
  491.     }
  492.     
  493.     if (needsPatching) {
  494.       var patchesHeader = document.getElementById("patches");
  495.       var strings = document.getElementById("updateStrings");
  496.       patchesHeader.label = strings.getFormattedString("updateTypePatches", [count]);
  497.       patchesHeader.collapsed = false;
  498.     }
  499.   },
  500.   
  501.   buildApp: function (aFiles)
  502.   {
  503.     // A New version of the app is available. 
  504.     var app = document.getElementById("app");
  505.     var strings = document.getElementById("updateStrings");
  506.     var brandStrings = document.getElementById("brandStrings");
  507.     var brandShortName = brandStrings.getString("brandShortName");
  508.     app.label = strings.getFormattedString("appNameAndVersionFormat", 
  509.                                             [brandShortName, 
  510.                                              this._newestInfo.updateDisplayVersion]);
  511.     app.accesskey = brandShortName.charAt(0);
  512.     app.collapsed = false;
  513.  
  514.     var foundAppLabel = document.getElementById("found.app.label");
  515.     var text = strings.getFormattedString("foundAppLabel",
  516.                                           [brandShortName, 
  517.                                            this._newestInfo.updateDisplayVersion])
  518.     foundAppLabel.appendChild(document.createTextNode(text));
  519.  
  520.     var features = this._newestInfo.getCollection("features", { });
  521.     if (features) {
  522.       var foundAppFeatures = document.getElementById("found.app.features");
  523.       foundAppFeatures.hidden = false;
  524.       text = strings.getFormattedString("foundAppFeatures", 
  525.                                         [brandShortName, 
  526.                                          this._newestInfo.updateDisplayVersion]);
  527.       foundAppFeatures.appendChild(document.createTextNode(text));
  528.  
  529.       var foundAppFeaturesList = document.getElementById("found.app.featuresList");
  530.       for (var i = 0; i < features.length; ++i) {
  531.         var feature = document.createElement("label");
  532.         foundAppFeaturesList.appendChild(feature);
  533.         feature.setAttribute("value", features[i].name);
  534.       }
  535.     }
  536.     
  537.     var foundAppInfoLink = document.getElementById("found.app.infoLink");
  538.     foundAppInfoLink.href = this._newestInfo.updateInfoURL;
  539.   },
  540.   
  541.   buildOptional: function (aComponents)
  542.   {
  543.     var needsOptional = false;
  544.     var critical = document.getElementById("found.components.list");
  545.     var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  546.                         .createInstance(Components.interfaces.nsIURI);
  547.     var count = 0;
  548.     for (var i = 0; i < aComponents.length; ++i) {
  549.       if (InstallTrigger.getVersion(aComponents[i].internalName)) {
  550.         // The user has already installed this patch since info
  551.         // about it exists in the Version Registry. Skip. 
  552.         continue;
  553.       }
  554.       
  555.       var checkbox = document.createElement("checkbox");
  556.       critical.appendChild(checkbox);
  557.       checkbox.setAttribute("type", "update");
  558.       checkbox.label        = aComponents[i].name;
  559.       checkbox.URL          = aComponents[i].URL;
  560.       checkbox.infoURL      = aComponents[i].infoURL;
  561.       checkbox.internalName = aComponents[i].internalName;
  562.       uri.spec              = checkbox.URL;
  563.       checkbox.source       = uri.host;
  564.       needsOptional         = true;
  565.       ++count;
  566.     }
  567.     
  568.     if (needsOptional) {
  569.       var optionalHeader = document.getElementById("components");
  570.       var strings = document.getElementById("updateStrings");
  571.       optionalHeader.label = strings.getFormattedString("updateTypeComponents", [count]);
  572.       optionalHeader.collapsed = false;
  573.     }
  574.   },
  575.  
  576.   buildLanguages: function (aLanguages)
  577.   {
  578.     var hasLanguages = false;
  579.     var languageList = document.getElementById("found.languages.list");
  580.     var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  581.                         .createInstance(Components.interfaces.nsIURI);
  582.     var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
  583.                        .getService(Components.interfaces.nsIXULChromeRegistry);
  584.     var selectedLocale = cr.getSelectedLocale("global");
  585.     var count = 0;
  586.     for (var i = 0; i < aLanguages.length; ++i) {
  587.       if (aLanguages[i].internalName == selectedLocale)
  588.         continue;
  589.       var checkbox = document.createElement("checkbox");
  590.       languageList.appendChild(checkbox);
  591.       checkbox.setAttribute("type", "update");
  592.       checkbox.label        = aLanguages[i].name;
  593.       checkbox.URL          = aLanguages[i].URL;
  594.       checkbox.infoURL      = aLanguages[i].infoURL;
  595.       checkbox.internalName = aLanguages[i].internalName;
  596.       uri.spec              = checkbox.URL;
  597.       checkbox.source       = uri.host;
  598.       hasLanguages          = true;
  599.       ++count;
  600.     }
  601.     
  602.     if (hasLanguages) {
  603.       var languagesHeader = document.getElementById("found.languages.header");
  604.       var strings = document.getElementById("updateStrings");
  605.       languagesHeader.label = strings.getFormattedString("updateTypeLangPacks", [count]);
  606.       languagesHeader.collapsed = false;
  607.     }
  608.   },
  609.  
  610.   _initialized: false,
  611.   onPageShow: function ()
  612.   {
  613.     gUpdateWizard.setButtonLabels(null, true, 
  614.                                   "installButtonText", false, 
  615.                                   null, false);
  616.     document.documentElement.getButton("next").focus();
  617.     
  618.     var updates = document.getElementById("found.updates");
  619.     if (!this._initialized) {
  620.       this._initialized = true;
  621.       
  622.       updates.computeSizes();
  623.  
  624.       // Don't show the app update option or critical updates if the user has 
  625.       // already installed an app update but has not yet restarted. 
  626.       var pref = Components.classes["@mozilla.org/preferences-service;1"]
  627.                           .getService(Components.interfaces.nsIPrefBranch);
  628.       var updatePerformed = pref.getBoolPref(PREF_UPDATE_APP_PERFORMED);
  629.       if (gUpdateTypes & nsIUpdateItem.TYPE_APP) {
  630.         var updatesvc = Components.classes["@mozilla.org/updates/update-service;1"]
  631.                                   .getService(Components.interfaces.nsIUpdateService);
  632.         this._currentInfo = updatesvc.currentVersion;
  633.         if (this._currentInfo) {
  634.           var patches = this._currentInfo.getCollection("patches", { });
  635.           if (patches.length > 0 && !updatePerformed)
  636.             this.buildPatches(patches);
  637.  
  638.           // Turning this off until we can better determine what is and is not installed. 
  639.           // var components = this._currentInfo.getCollection("optional", { });
  640.           // if (components.length > 0)
  641.           //   this.buildOptional(components);
  642.  
  643.           var languages = this._currentInfo.getCollection("languages", { });
  644.           if (languages.length > 0)
  645.             this.buildLanguages(languages);
  646.         }
  647.         
  648.         this._newestInfo = updatesvc.newestVersion;
  649.         if (this._newestInfo) {
  650.           var languages = this._newestInfo.getCollection("languages", { });
  651.           var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
  652.                             .getService(Components.interfaces.nsIXULChromeRegistry);
  653.           var selectedLocale = cr.getSelectedLocale("global");
  654.           var haveLanguage = false;
  655.           for (var i = 0; i < languages.length; ++i) {
  656.             if (languages[i].internalName == selectedLocale)
  657.               haveLanguage = true;
  658.           }
  659.  
  660.           var files = this._newestInfo.getCollection("files", { });
  661.           if (files.length > 0 && haveLanguage && !updatePerformed) 
  662.             this.buildApp(files);
  663.             
  664.           // When the user upgrades the application, any optional components that
  665.           // they have installed are automatically installed. If there are remaining
  666.           // optional components that are not currently installed, then these
  667.           // are offered as an option.
  668.           var components = this._newestInfo.getCollection("optional", { });
  669.           for (var i = 0; i < components.length; ++i) {
  670.             if (InstallTrigger.getVersion(components[i].internalName))
  671.               gUpdateWizard.appComps.upgraded.optional.push(components[i]);
  672.             else
  673.               gUpdateWizard.appComps.optional.optional.push(components[i]);
  674.           }
  675.           
  676.           var cr = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
  677.                             .getService(Components.interfaces.nsIXULChromeRegistry);
  678.           var selectedLocale = cr.getSelectedLocale("global");
  679.           gUpdateWizard.selectedLocaleAvailable = false;
  680.           var languages = this._newestInfo.getCollection("languages", { });
  681.           for (i = 0; i < languages.length; ++i) {
  682.             if (languages[i].internalName == selectedLocale) {
  683.               gUpdateWizard.selectedLocaleAvailable = true;
  684.               gUpdateWizard.appComps.upgraded.languages.push(languages[i]);
  685.             }
  686.           }
  687.           
  688.           if (!gUpdateWizard.selectedLocaleAvailable)
  689.             gUpdateWizard.appComps.optional.languages = gUpdateWizard.appComps.optional.languages.concat(languages);
  690.             
  691.           gUpdateWizard.appComps.upgraded.core = gUpdateWizard.appComps.upgraded.core.concat(files);
  692.         }
  693.       }
  694.  
  695.       if (gUpdateTypes & nsIUpdateItem.TYPE_ADDON)
  696.         this.buildAddons();
  697.     }
  698.         
  699.     var kids = updates._getRadioChildren();
  700.     for (var i = 0; i < kids.length; ++i) {
  701.       if (kids[i].collapsed == false) {
  702.         updates.selectedIndex = i;
  703.         break;
  704.       }
  705.     }
  706.   },
  707.     
  708.   onSelect: function (aEvent)
  709.   {
  710.     var updates = document.getElementById("found.updates");
  711.     var oneChecked = true;
  712.     if (updates.selectedItem.id != "app") {
  713.       oneChecked = false;
  714.       var items = updates.selectedItem.getElementsByTagName("checkbox");
  715.       for (var i = 0; i < items.length; ++i) {  
  716.         if (items[i].checked) {
  717.           oneChecked = true;
  718.           break;
  719.         }
  720.       }
  721.     }
  722.  
  723.     var strings = document.getElementById("updateStrings");
  724.     var text;
  725.     if (aEvent.target.selectedItem.id == "app") {
  726.       if (gUpdateWizard.appComps.optional.optional.length > 0) {
  727.         gUpdateWizard.setButtonLabels(null, true, 
  728.                                       "nextButtonText", true, 
  729.                                       null, false);
  730.           
  731.         text = strings.getString("foundInstructionsAppComps");
  732.         document.getElementById("found").setAttribute("next", "optional"); 
  733.       }
  734.       gUpdateWizard.updatingApp = true;
  735.     }
  736.     else {
  737.       gUpdateWizard.setButtonLabels(null, true, 
  738.                                     "installButtonText", true, 
  739.                                     null, false);
  740.       text = strings.getString("foundInstructions");
  741.       document.getElementById("found").setAttribute("next", "installing"); 
  742.       
  743.       gUpdateWizard.updatingApp = false;
  744.     }
  745.         
  746.     document.documentElement.getButton("next").disabled = !oneChecked;
  747.  
  748.     var foundInstructions = document.getElementById("foundInstructions");
  749.     while (foundInstructions.hasChildNodes())
  750.       foundInstructions.removeChild(foundInstructions.firstChild);
  751.     foundInstructions.appendChild(document.createTextNode(text));
  752.   }
  753. };
  754.  
  755. var gOptionalPage = {
  756.   onPageShow: function ()
  757.   {
  758.     gUpdateWizard.setButtonLabels(null, false, 
  759.                                   "installButtonText", false, 
  760.                                   null, false);
  761.  
  762.     var optionalItemsList = document.getElementById("optionalItemsList");
  763.     while (optionalItemsList.hasChildNodes())
  764.       optionalItemsList.removeChild(optionalItemsList.firstChild);
  765.  
  766.     for (var i = 0; i < gUpdateWizard.appComps.optional.optional.length; ++i) {
  767.       var checkbox = document.createElement("checkbox");
  768.       checkbox.setAttribute("label", gUpdateWizard.appComps.optional.optional[i].name);
  769.       checkbox.setAttribute("index", i);
  770.       optionalItemsList.appendChild(checkbox);
  771.     }
  772.     
  773.     document.documentElement.getButton("next").focus(); 
  774.   },
  775.   
  776.   onCommand: function (aEvent)
  777.   {
  778.     if (aEvent.target.localName == "checkbox") {
  779.       gUpdateWizard.appComps.upgraded.optional = [];
  780.       var optionalItemsList = document.getElementById("optionalItemsList");
  781.       var checkboxes = optionalItemsList.getElementsByTagName("checkbox");
  782.       for (var i = 0; i < checkboxes.length; ++i) {
  783.         if (checkboxes[i].checked) {
  784.           var index = parseInt(checkboxes[i].getAttribute("index"));
  785.           var item = gUpdateWizard.appComps.optional.optional[index];
  786.           gUpdateWizard.appComps.upgraded.optional.push(item);
  787.         }
  788.       }
  789.     }
  790.   },
  791.   
  792.   onListMouseOver: function (aEvent)
  793.   {
  794.     if (aEvent.target.localName == "checkbox") {
  795.       var index = parseInt(aEvent.target.getAttribute("index"));
  796.       var desc = gUpdateWizard.appComps.optional.optional[index].description;
  797.       var optionalDescription = document.getElementById("optionalDescription");
  798.       while (optionalDescription.hasChildNodes()) 
  799.         optionalDescription.removeChild(optionalDescription.firstChild);
  800.       optionalDescription.appendChild(document.createTextNode(desc));
  801.     }
  802.   },
  803.   
  804.   onListMouseOut: function (aEvent)
  805.   {
  806.     if (aEvent.target.localName == "vbox") {
  807.       var optionalDescription = document.getElementById("optionalDescription");
  808.       while (optionalDescription.hasChildNodes()) 
  809.         optionalDescription.removeChild(optionalDescription.firstChild);
  810.     }
  811.   }
  812. };
  813.  
  814. var gInstallingPage = {
  815.   _installing       : false,
  816.   _restartRequired  : false,
  817.   _objs             : [],
  818.   
  819.   onPageShow: function ()
  820.   {
  821.     gUpdateWizard.setButtonLabels(null, true, 
  822.                                   "nextButtonText", true, 
  823.                                   null, true);
  824.  
  825.     // Get XPInstallManager and kick off download/install 
  826.     // process, registering us as an observer. 
  827.     var items = [];
  828.     this._objs = [];
  829.     
  830.     this._restartRequired = false;
  831.     
  832.     gUpdateWizard.remainingExtensionUpdateCount = gUpdateWizard.itemsToUpdate.length;
  833.  
  834.     var updates = document.getElementById("found.updates");
  835.     if (updates.selectedItem.id != "app") {
  836.       var checkboxes = updates.selectedItem.getElementsByTagName("checkbox");
  837.       for (var i = 0; i < checkboxes.length; ++i) {
  838.         if (checkboxes[i].type == "update" && checkboxes[i].checked) {
  839.           items.push(checkboxes[i].URL);
  840.           this._objs.push({ name: checkboxes[i].label });
  841.         }
  842.       }
  843.     }
  844.     else {
  845.       // To install an app update we need to collect together the following
  846.       // sets of files:
  847.       // - core files
  848.       // - optional components (we need to show another page) 
  849.       // - selected language, if the available language set does not match
  850.       //   the one currently selected for the "global" package
  851.       // Order is *probably* important here.      
  852.       for (var i = 0; i < gUpdateWizard.appComps.upgraded.core.length; ++i) {
  853.         items.push(gUpdateWizard.appComps.upgraded.core[i].URL);
  854.         this._objs.push({ name: gUpdateWizard.appComps.upgraded.core[i].name });
  855.       }
  856.       for (var i = 0; i < gUpdateWizard.appComps.upgraded.languages.length; ++i) {
  857.         items.push(gUpdateWizard.appComps.upgraded.languages[i].URL);
  858.         this._objs.push({ name: gUpdateWizard.appComps.upgraded.languages[i].name });
  859.       }
  860.       for (var i = 0; i < gUpdateWizard.appComps.upgraded.optional.length; ++i) {
  861.         items.push(gUpdateWizard.appComps.upgraded.optional[i].URL);
  862.         this._objs.push({ name: gUpdateWizard.appComps.upgraded.optional[i].name });
  863.       }
  864.     }
  865.     
  866.     var xpimgr = Components.classes["@mozilla.org/xpinstall/install-manager;1"]
  867.                            .createInstance(Components.interfaces.nsIXPInstallManager);
  868.     xpimgr.initManagerFromChrome(items, items.length, this);
  869.   },
  870.   
  871.   /////////////////////////////////////////////////////////////////////////////
  872.   // nsIXPIProgressDialog
  873.   onStateChange: function (aIndex, aState, aValue)
  874.   {
  875.     var strings = document.getElementById("updateStrings");
  876.  
  877.     const nsIXPIProgressDialog = Components.interfaces.nsIXPIProgressDialog;
  878.     switch (aState) {
  879.     case nsIXPIProgressDialog.DOWNLOAD_START:
  880.       var label = strings.getFormattedString("downloadingPrefix", [this._objs[aIndex].name]);
  881.       var actionItem = document.getElementById("actionItem");
  882.       actionItem.value = label;
  883.       break;
  884.     case nsIXPIProgressDialog.DOWNLOAD_DONE:
  885.     case nsIXPIProgressDialog.INSTALL_START:
  886.       var label = strings.getFormattedString("installingPrefix", [this._objs[aIndex].name]);
  887.       var actionItem = document.getElementById("actionItem");
  888.       actionItem.value = label;
  889.       this._installing = true;
  890.       break;
  891.     case nsIXPIProgressDialog.INSTALL_DONE:
  892.       switch (aValue) {
  893.       case 999: 
  894.         this._restartRequired = true;
  895.         break;
  896.       case 0: 
  897.         --gUpdateWizard.remainingExtensionUpdateCount;
  898.         break;
  899.       default:
  900.         // XXXben ignore chrome registration errors hack!
  901.         if (!(aValue == -239 && gUpdateWizard.updatingApp)) {
  902.           this._objs[aIndex].error = aValue;
  903.           this._errors = true;
  904.         }
  905.         break;
  906.       }
  907.       break;
  908.     case nsIXPIProgressDialog.DIALOG_CLOSE:
  909.       this._installing = false;
  910.       var nextPage = this._errors ? "errors" : (this._restartRequired ? "restart" : "finished");
  911.       document.getElementById("installing").setAttribute("next", nextPage);
  912.       document.documentElement.advance();
  913.       break;
  914.     }
  915.   },
  916.   
  917.   _objs: [],
  918.   _errors: false,
  919.   
  920.   onProgress: function (aIndex, aValue, aMaxValue)
  921.   {
  922.     var downloadProgress = document.getElementById("downloadProgress");
  923.     downloadProgress.value = Math.ceil((aValue/aMaxValue) * 100);
  924.   }
  925. };
  926.  
  927. var gErrorsPage = {
  928.   onPageShow: function ()
  929.   {
  930.     document.documentElement.getButton("finish").focus();
  931.     gUpdateWizard.succeeded = false;
  932.   },
  933.   
  934.   onShowErrors: function ()
  935.   {
  936.     gUpdateWizard.showErrors("install", gInstallingPage._objs);
  937.   }  
  938. };
  939.  
  940. var gFinishedPage = {
  941.   onPageShow: function ()
  942.   {
  943.     gUpdateWizard.setButtonLabels(null, true, null, true, null, true);
  944.     document.documentElement.getButton("finish").focus();
  945.     
  946.     var iR = document.getElementById("incompatibleRemaining");
  947.     var iR2 = document.getElementById("incompatibleRemaining2");
  948.     var fEC = document.getElementById("finishedEnableChecking");
  949.  
  950.     if (gUpdateWizard.shouldSuggestAutoChecking) {
  951.       iR.hidden = true;
  952.       iR2.hidden = false;
  953.       fEC.hidden = false;
  954.       fEC.click();
  955.     }
  956.     else {
  957.       iR.hidden = false;
  958.       iR2.hidden = true;
  959.       fEC.hidden = true;
  960.     }
  961.     
  962.     if (gSourceEvent == nsIUpdateService.SOURCE_EVENT_MISMATCH) {
  963.       document.getElementById("finishedMismatch").hidden = false;
  964.       document.getElementById("incompatibleAlert").hidden = false;
  965.     }
  966.   }
  967. };
  968.  
  969. var gRestartPage = {
  970.   onPageShow: function ()
  971.   {
  972.     gUpdateWizard.setButtonLabels(null, true, null, true, null, true);
  973.     
  974.     // XXXben - we should really have a way to restart the app now from here!
  975.     
  976.     gUpdateWizard.offeredResetHomepage = true;
  977.  
  978.     document.documentElement.getButton("finish").focus();
  979.  
  980.     // Create a re-reg chrome marker to tell the Chrome Registry to rebuild the
  981.     // Chrome Reg Datasource and overlayinfo directory on the next start since 
  982.     // we've upgraded in-place (and thus chrome.rdf's mtime is newer than the
  983.     // installed-chrome.txt file that was installed by the update process since
  984.     // chrome.rdf was flushed when the browser started, AFTER installed-chrome.txt
  985.     // was created.
  986.     var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]
  987.                                 .getService(Components.interfaces.nsIProperties);
  988.     var file = fileLocator.get("AChrom", Components.interfaces.nsIFile);
  989.     file.append(".reregchrome");
  990.     if (!file.exists())
  991.       file.create(Components.interfaces.nsIFile.FILE_TYPE, 0644);
  992.   }
  993. };
  994.  
  995. var gNoUpdatesPage = {
  996.   onPageShow: function (aEvent)
  997.   {
  998.     gUpdateWizard.setButtonLabels(null, true, null, true, null, true);
  999.     document.documentElement.getButton("finish").focus();
  1000.     if (gSourceEvent == nsIUpdateService.SOURCE_EVENT_MISMATCH) {
  1001.       document.getElementById("introUser").hidden = true;
  1002.       document.getElementById("introMismatch").hidden = false;
  1003.       document.getElementById("mismatchNoUpdates").hidden = false;
  1004.         
  1005.       if (gUpdateWizard.shouldSuggestAutoChecking) {
  1006.         document.getElementById("mismatchIncompatibleRemaining").hidden = true;
  1007.         document.getElementById("mismatchIncompatibleRemaining2").hidden = false;
  1008.         document.getElementById("mismatchFinishedEnableChecking").hidden = false;
  1009.       }
  1010.     }
  1011.  
  1012.     gUpdateWizard.succeeded = false;
  1013.     gUpdateWizard.checkForErrors("updateCheckErrorNotFound");
  1014.   }
  1015. };
  1016.  
  1017.