Save all modification
[mozilla-1.9/m8.git] / browser / components / nsBrowserGlue.js
blobc8f8f2636e58739e5b96e30bce8a957e9aa0d516
1 # ***** BEGIN LICENSE BLOCK *****
2 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 # The contents of this file are subject to the Mozilla Public License Version
5 # 1.1 (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
7 # http://www.mozilla.org/MPL/
9 # Software distributed under the License is distributed on an "AS IS" basis,
10 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 # for the specific language governing rights and limitations under the
12 # License.
14 # The Original Code is the Browser Search Service.
16 # The Initial Developer of the Original Code is
17 # Giorgio Maone
18 # Portions created by the Initial Developer are Copyright (C) 2005
19 # the Initial Developer. All Rights Reserved.
21 # Contributor(s):
22 #   Giorgio Maone <g.maone@informaction.com>
24 # Alternatively, the contents of this file may be used under the terms of
25 # either the GNU General Public License Version 2 or later (the "GPL"), or
26 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 # in which case the provisions of the GPL or the LGPL are applicable instead
28 # of those above. If you wish to allow use of your version of this file only
29 # under the terms of either the GPL or the LGPL, and not to allow others to
30 # use your version of this file under the terms of the MPL, indicate your
31 # decision by deleting the provisions above and replace them with the notice
32 # and other provisions required by the GPL or the LGPL. If you do not delete
33 # the provisions above, a recipient may use your version of this file under
34 # the terms of any one of the MPL, the GPL or the LGPL.
36 # ***** END LICENSE BLOCK *****
38 const Ci = Components.interfaces;
39 const Cc = Components.classes;
40 const Cr = Components.results;
41 const Cu = Components.utils;
43 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
44 Cu.import("resource:///modules/distribution.js");
46 // Factory object
47 const BrowserGlueServiceFactory = {
48   _instance: null,
49   createInstance: function (outer, iid) 
50   {
51     if (outer != null)
52       throw Components.results.NS_ERROR_NO_AGGREGATION;
53     return this._instance == null ?
54       this._instance = new BrowserGlue() : this._instance;
55   }
58 // Constructor
60 function BrowserGlue() {
61   this._init();
62   this._profileStarted = false;
65 BrowserGlue.prototype = {
66   _saveSession: false,
68   // nsIObserver implementation 
69   observe: function(subject, topic, data) 
70   {
71     switch(topic) {
72       case "xpcom-shutdown":
73         this._dispose();
74         break;
75       case "profile-before-change":
76         this._onProfileChange();
77         break;
78       case "profile-change-teardown": 
79         this._onProfileShutdown();
80         break;
81       case "prefservice:after-app-defaults":
82         this._onAppDefaults();
83         break;
84       case "final-ui-startup":
85         this._onProfileStartup();
86         break;
87       case "browser:purge-session-history":
88         // reset the console service's error buffer
89         const cs = Cc["@mozilla.org/consoleservice;1"].
90                    getService(Ci.nsIConsoleService);
91         cs.logStringMessage(null); // clear the console (in case it's open)
92         cs.reset();
93         break;
94       case "quit-application-requested":
95         this._onQuitRequest(subject, data);
96         break;
97       case "quit-application-granted":
98         if (this._saveSession) {
99           var prefBranch = Cc["@mozilla.org/preferences-service;1"].
100                            getService(Ci.nsIPrefBranch);
101           prefBranch.setBoolPref("browser.sessionstore.resume_session_once", true);
102         }
103         break;
104     }
105   }
107   // initialization (called on application startup) 
108   _init: function() 
109   {
110     // observer registration
111     const osvr = Cc['@mozilla.org/observer-service;1'].
112                  getService(Ci.nsIObserverService);
113     osvr.addObserver(this, "profile-before-change", false);
114     osvr.addObserver(this, "profile-change-teardown", false);
115     osvr.addObserver(this, "xpcom-shutdown", false);
116     osvr.addObserver(this, "prefservice:after-app-defaults", false);
117     osvr.addObserver(this, "final-ui-startup", false);
118     osvr.addObserver(this, "browser:purge-session-history", false);
119     osvr.addObserver(this, "quit-application-requested", false);
120     osvr.addObserver(this, "quit-application-granted", false);
121   },
123   // cleanup (called on application shutdown)
124   _dispose: function() 
125   {
126     // observer removal 
127     const osvr = Cc['@mozilla.org/observer-service;1'].
128                  getService(Ci.nsIObserverService);
129     osvr.removeObserver(this, "profile-before-change");
130     osvr.removeObserver(this, "profile-change-teardown");
131     osvr.removeObserver(this, "xpcom-shutdown");
132     osvr.removeObserver(this, "prefservice:after-app-defaults");
133     osvr.removeObserver(this, "final-ui-startup");
134     osvr.removeObserver(this, "browser:purge-session-history");
135     osvr.removeObserver(this, "quit-application-requested");
136     osvr.removeObserver(this, "quit-application-granted");
137   },
139   _onAppDefaults: function()
140   {
141     // apply distribution customizations (prefs)
142     // other customizations are applied in _onProfileStartup()
143     var distro = new DistributionCustomizer();
144     distro.applyPrefDefaults();
145   },
147   // profile startup handler (contains profile initialization routines)
148   _onProfileStartup: function() 
149   {
150     // check to see if the EULA must be shown on startup
151     try {
152       var mustDisplayEULA = true;
153       var prefBranch = Cc["@mozilla.org/preferences-service;1"].
154                        getService(Ci.nsIPrefBranch);
155       var EULAVersion = prefBranch.getIntPref("browser.EULA.version");
156       mustDisplayEULA = !prefBranch.getBoolPref("browser.EULA." + EULAVersion + ".accepted");
157     } catch(ex) {
158     }
160     if (mustDisplayEULA) {
161       var ww2 = Cc["@mozilla.org/embedcomp/window-watcher;1"].
162                 getService(Ci.nsIWindowWatcher);
163       ww2.openWindow(null, "chrome://browser/content/EULA.xul", 
164                      "_blank", "chrome,centerscreen,modal,resizable=yes", null);
165     }
167     this.Sanitizer.onStartup();
168     // check if we're in safe mode
169     var app = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).
170               QueryInterface(Ci.nsIXULRuntime);
171     if (app.inSafeMode) {
172       var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
173                getService(Ci.nsIWindowWatcher);
174       ww.openWindow(null, "chrome://browser/content/safeMode.xul", 
175                     "_blank", "chrome,centerscreen,modal,resizable=no", null);
176     }
178     // initialize Places
179     this._initPlaces();
181     // apply distribution customizations
182     // prefs are applied in _onAppDefaults()
183     var distro = new DistributionCustomizer();
184     distro.applyCustomizations();
186     // indicate that the profile was initialized
187     this._profileStarted = true;
188   },
190   _onProfileChange: function()
191   {
192     // this block is for code that depends on _onProfileStartup() having 
193     // been called.
194     if (this._profileStarted) {
195       // final places cleanup
196       this._shutdownPlaces();
197     }
198   },
200   // profile shutdown handler (contains profile cleanup routines)
201   _onProfileShutdown: function() 
202   {
203     // here we enter last survival area, in order to avoid multiple
204     // "quit-application" notifications caused by late window closings
205     const appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
206                        getService(Ci.nsIAppStartup);
207     try {
208       appStartup.enterLastWindowClosingSurvivalArea();
210       this.Sanitizer.onShutdown();
212     } catch(ex) {
213     } finally {
214       appStartup.exitLastWindowClosingSurvivalArea();
215     }
216   },
218   _onQuitRequest: function(aCancelQuit, aQuitType)
219   {
220     var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
221              getService(Ci.nsIWindowMediator);
222     var windowcount = 0;
223     var pagecount = 0;
224     var browserEnum = wm.getEnumerator("navigator:browser");
225     while (browserEnum.hasMoreElements()) {
226       windowcount++;
228       var browser = browserEnum.getNext();
229       var tabbrowser = browser.document.getElementById("content");
230       if (tabbrowser)
231         pagecount += tabbrowser.browsers.length;
232     }
234     this._saveSession = false;
235     if (pagecount < 2)
236       return;
238     if (aQuitType != "restart")
239       aQuitType = "quit";
241     var prefBranch = Cc["@mozilla.org/preferences-service;1"].
242                      getService(Ci.nsIPrefBranch);
243     var showPrompt = true;
244     try {
245       if (prefBranch.getIntPref("browser.startup.page") == 3 ||
246           prefBranch.getBoolPref("browser.sessionstore.resume_session_once"))
247         showPrompt = false;
248       else
249         showPrompt = prefBranch.getBoolPref("browser.warnOnQuit");
250     } catch (ex) {}
252     var buttonChoice = 0;
253     if (showPrompt) {
254       var bundleService = Cc["@mozilla.org/intl/stringbundle;1"].
255                           getService(Ci.nsIStringBundleService);
256       var quitBundle = bundleService.createBundle("chrome://browser/locale/quitDialog.properties");
257       var brandBundle = bundleService.createBundle("chrome://branding/locale/brand.properties");
259       var appName = brandBundle.GetStringFromName("brandShortName");
260       var quitDialogTitle = quitBundle.formatStringFromName(aQuitType + "DialogTitle",
261                                                               [appName], 1);
262       var quitTitle = quitBundle.GetStringFromName(aQuitType + "Title");
263       var cancelTitle = quitBundle.GetStringFromName("cancelTitle");
264       var saveTitle = quitBundle.GetStringFromName("saveTitle");
265       var neverAskText = quitBundle.GetStringFromName("neverAsk");
267       var message;
268       if (aQuitType == "restart")
269         message = quitBundle.formatStringFromName("messageRestart",
270                                                   [appName], 1);
271       else if (windowcount == 1)
272         message = quitBundle.formatStringFromName("messageNoWindows",
273                                                   [appName], 1);
274       else
275         message = quitBundle.formatStringFromName("message",
276                                                   [appName], 1);
278       var promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"].
279                           getService(Ci.nsIPromptService);
281       var flags = promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0 +
282                   promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_1 +
283                   promptService.BUTTON_POS_0_DEFAULT;
284       var neverAsk = {value:false};
285       if (aQuitType != "restart")
286         flags += promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_2;
287       buttonChoice = promptService.confirmEx(null, quitDialogTitle, message,
288                                    flags, quitTitle, cancelTitle, saveTitle,
289                                    neverAskText, neverAsk);
291       switch (buttonChoice) {
292       case 0:
293         if (neverAsk.value)
294           prefBranch.setBoolPref("browser.warnOnQuit", false);
295         break;
296       case 1:
297         aCancelQuit.QueryInterface(Ci.nsISupportsPRBool);
298         aCancelQuit.data = true;
299         break;
300       case 2:
301         // could also set browser.warnOnQuit to false here,
302         // but not setting it is a little safer.
303         if (neverAsk.value)
304           prefBranch.setIntPref("browser.startup.page", 3);
305         break;
306       }
308       this._saveSession = buttonChoice == 2;
309     }
310   },
312   // returns the (cached) Sanitizer constructor
313   get Sanitizer() 
314   {
315     if(typeof(Sanitizer) != "function") { // we should dynamically load the script
316       Cc["@mozilla.org/moz/jssubscript-loader;1"].
317       getService(Ci.mozIJSSubScriptLoader).
318       loadSubScript("chrome://browser/content/sanitize.js", null);
319     }
320     return Sanitizer;
321   },
323   /**
324    * Initialize Places
325    * - imports the bookmarks html file if bookmarks datastore is empty
326    */
327   _initPlaces: function bg__initPlaces() {
328     // we need to instantiate the history service before we check the 
329     // the browser.places.importBookmarksHTML pref, as 
330     // nsNavHistory::ForceMigrateBookmarksDB() will set that pref
331     // if we need to force a migration (due to a schema change)
332     var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
333                   getService(Ci.nsINavHistoryService);
335     var importBookmarks = false;
336     try {
337       var prefBranch = Cc["@mozilla.org/preferences-service;1"].
338                        getService(Ci.nsIPrefBranch);
339       importBookmarks = prefBranch.getBoolPref("browser.places.importBookmarksHTML");
340     } catch(ex) {}
342     if (!importBookmarks)
343       return;
345     var dirService = Cc["@mozilla.org/file/directory_service;1"].
346                      getService(Ci.nsIProperties);
348     var bookmarksFile = dirService.get("BMarks", Ci.nsILocalFile);
350     if (bookmarksFile.exists()) {
351       // import the file
352       try {
353         var importer = 
354           Cc["@mozilla.org/browser/places/import-export-service;1"].
355           getService(Ci.nsIPlacesImportExportService);
356         importer.importHTMLFromFile(bookmarksFile, true);
357       } catch(ex) {
358       } finally {
359         prefBranch.setBoolPref("browser.places.importBookmarksHTML", false);
360       }
362       // backup pre-places bookmarks.html
363       // XXXtodo remove this before betas, after import/export is solid
364       var profDir = dirService.get("ProfD", Ci.nsILocalFile);
365       var bookmarksBackup = profDir.clone();
366       bookmarksBackup.append("bookmarks.preplaces.html");
367       if (!bookmarksBackup.exists()) {
368         // save old bookmarks.html file as bookmarks.preplaces.html
369         try {
370           bookmarksFile.copyTo(profDir, "bookmarks.preplaces.html");
371         } catch(ex) {
372           dump("nsBrowserGlue::_initPlaces(): copy of bookmarks.html to bookmarks.preplaces.html failed: " + ex + "\n");
373         }
374       }
375     }
376   },
378   /**
379    * Places shut-down tasks
380    * - back up and archive bookmarks
381    */
382   _shutdownPlaces: function bg__shutdownPlaces() {
383     // backup bookmarks to bookmarks.html
384     var importer =
385       Cc["@mozilla.org/browser/places/import-export-service;1"].
386       getService(Ci.nsIPlacesImportExportService);
387     importer.backupBookmarksFile();
388   },
389   
390   // ------------------------------
391   // public nsIBrowserGlue members
392   // ------------------------------
393   
394   sanitize: function(aParentWindow) 
395   {
396     this.Sanitizer.sanitize(aParentWindow);
397   },
399   // for XPCOM
400   classDescription: "Firefox Browser Glue Service",
401   classID:          Components.ID("{eab9012e-5f74-4cbc-b2b5-a590235513cc}"),
402   contractID:       "@mozilla.org/browser/browserglue;1",
404   QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupports,
405                                           Ci.nsISupportsWeakReference,
406                                           Ci.nsIBrowserGlue]),
408   // redefine the default factory for XPCOMUtils
409   _xpcom_factory: BrowserGlueServiceFactory,
411   // get this contractID registered for certain categories via XPCOMUtils
412   _xpcom_categories: [
413     // make BrowserGlue a startup observer
414     { category: "app-startup", service: true }
415   ]
418 //module initialization
419 function NSGetModule(aCompMgr, aFileSpec) {
420   return XPCOMUtils.generateModule([BrowserGlue]);
423